From 0a8b86b57f0d2cd3937f7f8e394902da3885f0ef Mon Sep 17 00:00:00 2001 From: Michael Dolan Date: Wed, 29 Apr 2020 01:18:24 -0400 Subject: [PATCH 01/33] Upgrade to CMake 3.12, Add support for ext CMake configs Signed-off-by: Michael Dolan --- .github/workflows/analysis_workflow.yml | 4 + CMakeLists.txt | 18 +- docs/CMakeLists.txt | 17 +- docs/installation.rst | 29 ++- ext/CMakeLists.txt | 33 +-- share/ci/scripts/linux/install_expat.sh | 4 +- share/ci/scripts/linux/install_lcms2.sh | 5 +- share/ci/scripts/linux/install_oiio.sh | 7 +- share/ci/scripts/linux/install_openexr.sh | 4 +- share/ci/scripts/linux/install_pybind11.sh | 5 +- share/ci/scripts/linux/install_pystring.sh | 5 +- share/ci/scripts/linux/install_yaml-cpp.sh | 3 +- share/cmake/modules/FindExpat.cmake | 211 ---------------- share/cmake/modules/FindExtPackages.cmake | 52 ++++ share/cmake/modules/FindHalf.cmake | 226 ++++++++++++++++++ share/cmake/modules/FindIlmBase.cmake | 216 ----------------- share/cmake/modules/FindOpenImageIO.cmake | 36 --- share/cmake/modules/FindSphinx.cmake | 31 ++- share/cmake/modules/FindYamlCpp.cmake | 221 ----------------- share/cmake/modules/Findexpat.cmake | 218 +++++++++++++++++ .../{FindLCMS2.cmake => Findlcms2.cmake} | 124 +++++----- share/cmake/modules/Findpybind11.cmake | 103 ++++---- ...{FindPystring.cmake => Findpystring.cmake} | 104 ++++---- share/cmake/modules/Findyaml-cpp.cmake | 219 +++++++++++++++++ .../{BuildLCMS2.cmake => Buildlcms2.cmake} | 0 ...uildPystring.cmake => Buildpystring.cmake} | 4 +- share/cmake/scripts/PatchOpenEXR.cmake | 9 + src/CMakeLists.txt | 5 +- src/OpenColorIO/CMakeLists.txt | 4 +- src/apps/CMakeLists.txt | 4 +- src/apps/ocioconvert/CMakeLists.txt | 4 +- src/apps/ociodisplay/CMakeLists.txt | 2 +- src/apps/ociolutimage/CMakeLists.txt | 2 +- src/apps/ocioperf/CMakeLists.txt | 4 +- src/bindings/python/CMakeLists.txt | 5 - src/libutils/oiiohelpers/CMakeLists.txt | 4 +- tests/cpu/CMakeLists.txt | 6 +- 37 files changed, 957 insertions(+), 991 deletions(-) delete mode 100644 share/cmake/modules/FindExpat.cmake create mode 100644 share/cmake/modules/FindExtPackages.cmake create mode 100644 share/cmake/modules/FindHalf.cmake delete mode 100644 share/cmake/modules/FindIlmBase.cmake delete mode 100755 share/cmake/modules/FindOpenImageIO.cmake delete mode 100644 share/cmake/modules/FindYamlCpp.cmake create mode 100644 share/cmake/modules/Findexpat.cmake rename share/cmake/modules/{FindLCMS2.cmake => Findlcms2.cmake} (51%) rename share/cmake/modules/{FindPystring.cmake => Findpystring.cmake} (57%) create mode 100644 share/cmake/modules/Findyaml-cpp.cmake rename share/cmake/projects/{BuildLCMS2.cmake => Buildlcms2.cmake} (100%) rename share/cmake/projects/{BuildPystring.cmake => Buildpystring.cmake} (81%) create mode 100644 share/cmake/scripts/PatchOpenEXR.cmake diff --git a/.github/workflows/analysis_workflow.yml b/.github/workflows/analysis_workflow.yml index 3b4853f2d8..9c4cf9dc7a 100644 --- a/.github/workflows/analysis_workflow.yml +++ b/.github/workflows/analysis_workflow.yml @@ -21,6 +21,8 @@ jobs: <${{ matrix.compiler-desc }} cxx=${{ matrix.cxx-standard }}, docs=${{ matrix.build-docs }}>' + # Don't run on OCIO forks + if: github.repository == 'AcademySoftwareFoundation/OpenColorIO' # GH-hosted VM. The build runs in CentOS 7 'container' defined below. runs-on: ubuntu-latest container: @@ -145,6 +147,8 @@ jobs: linux_sonarcloud: name: 'Linux CentOS 7 VFX CY2020 SonarCloud ' + # Don't run on OCIO forks + if: github.repository == 'AcademySoftwareFoundation/OpenColorIO' # GH-hosted VM. The build runs in CentOS 7 'container' defined below. runs-on: ubuntu-latest container: diff --git a/CMakeLists.txt b/CMakeLists.txt index 2e11471fb9..6ad50de66a 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,7 +1,7 @@ # SPDX-License-Identifier: BSD-3-Clause # Copyright Contributors to the OpenColorIO Project. -cmake_minimum_required(VERSION 3.11) +cmake_minimum_required(VERSION 3.12) project(OpenColorIO VERSION 2.0.0 @@ -88,19 +88,19 @@ if(OCIO_BUILD_GPU_TESTS OR OCIO_BUILD_APPS) set(OCIO_GL_ENABLED ON) find_package(OpenGL QUIET) if(NOT OpenGL_FOUND) - message(WARNING "OpenGL not found.") + message(WARNING "Could NOT find OpenGL.") set(OCIO_GL_ENABLED OFF) endif() if(NOT APPLE) find_package(GLEW QUIET) if(NOT GLEW_FOUND) - message(WARNING "GLEW not found.") + message(WARNING "Coule NOT find GLEW.") set(OCIO_GL_ENABLED OFF) endif() endif() find_package(GLUT QUIET) if(NOT GLUT_FOUND) - message(WARNING "GLUT not found.") + message(WARNING "Could NOT find GLUT.") set(OCIO_GL_ENABLED OFF) endif() endif() @@ -210,12 +210,20 @@ if(OCIO_BUILD_STATIC) endif() endif() +############################################################################### +# Find or install external dependencies +# Some required targets may be created by third-party CMake configs, which +# don't generally produce global targets. To guarantee all imported targets are +# global, this module is included at the project root level. + +include(share/cmake/modules/FindExtPackages.cmake) + ############################################################################### # Progress to other sources +add_subdirectory(ext) add_subdirectory(tests) add_subdirectory(include) -add_subdirectory(ext) add_subdirectory(src) if(OCIO_BUILD_DOCS) add_subdirectory(docs) diff --git a/docs/CMakeLists.txt b/docs/CMakeLists.txt index 1228407f5c..02a21489d4 100644 --- a/docs/CMakeLists.txt +++ b/docs/CMakeLists.txt @@ -8,19 +8,6 @@ if(NOT OCIO_BUILD_PYTHON) message(FATAL_ERROR "Doc generation requires that the python bindings be built") endif() -############################################################################### -### External Python dependencies ### - -include(FindPythonPackage) - -# Sphinx -# https://pypi.python.org/pypi/Sphinx -set(SPHINX_MIN_VERSION 1.8.5) -find_package(Sphinx ${SPHINX_MIN_VERSION} REQUIRED) -if(NOT SPHINX_FOUND) - message(FATAL_ERROR "Doc generation requires Sphinx") -endif() - ############################################################################### ### Setup PYTHONPATH ### @@ -135,7 +122,7 @@ add_custom_target(rst_extraction add_custom_target(docs ALL COMMAND - ${PYT_PRE_CMD} "${SPHINX_EXECUTABLE}" -b html . "${CMAKE_CURRENT_BINARY_DIR}/build-html" + ${PYT_PRE_CMD} "${Sphinx_EXECUTABLE}" -b html . "${CMAKE_CURRENT_BINARY_DIR}/build-html" DEPENDS OpenColorIO PyOpenColorIO @@ -162,7 +149,7 @@ if(PDFLATEX_COMPILER) add_custom_target(latex COMMAND - ${PYT_PRE_CMD} "${SPHINX_EXECUTABLE}" -b latex . "${CMAKE_CURRENT_BINARY_DIR}/build-latex" + ${PYT_PRE_CMD} "${Sphinx_EXECUTABLE}" -b latex . "${CMAKE_CURRENT_BINARY_DIR}/build-latex" DEPENDS OpenColorIO PyOpenColorIO diff --git a/docs/installation.rst b/docs/installation.rst index f96d715159..dff5be6042 100644 --- a/docs/installation.rst +++ b/docs/installation.rst @@ -55,7 +55,7 @@ Dependencies The basic requirements for building OCIO are: -- cmake >= 3.10 +- cmake >= 3.12 - \*Expat >= 2.2.5 (XML parser for CDL/CLF/CTF) - \*yaml-cpp >= 0.6.3 (YAML parser for Configs) - \*IlmBase (Half only) >= 2.3.0 (for half domain LUTs) @@ -64,10 +64,11 @@ The basic requirements for building OCIO are: Some optional components also depend on: - \*Little CMS >= 2.2 (for ociobakelut ICC profile baking) -- Python 2.x (for the Python bindings and docs) +- \*pybind11 >= 2.4.3 (for the Python bindings) +- Python >= 2.7 (for the Python bindings and docs) - \*Sphinx >= 1.8.5 +- OpenImageIO >= 2.1.9 (for apps including ocioconvert) - Nuke 6.x or newer (for the Nuke nodes) -- OpenImageIO (for apps including ocioconvert) Automated Installation ^^^^^^^^^^^^^^^^^^^^^^ @@ -97,16 +98,18 @@ When using existing system libraries, the following CMake variables can be defined to hint at non-standard install locations and preference of shared or static linking: -- ``-DEXPAT_DIRS=`` (include and/or library root dir) -- ``-DEXPAT_STATIC_LIBRARY=ON`` (prefer static lib) -- ``-DYAMLCPP_DIRS=`` (include and/or library root dir) -- ``-DYAMLCPP_STATIC_LIBRARY=ON`` (prefer static lib) -- ``-DILMBASE_DIRS=`` (include and/or library root dir) -- ``-DILMBASE_STATIC_LIBRARY=ON`` (prefer static lib) -- ``-DPYSTRING_DIRS=`` (include and/or library root dir) -- ``-DPYSTRING_STATIC_LIBRARY=ON`` (prefer static lib) -- ``-DLCMS2_DIRS=`` (include and/or library root dir) -- ``-DLCMS2_STATIC_LIBRARY=ON`` (prefer static lib) +- ``-DExpat_ROOT=`` (include and/or library root dir) +- ``-DExpat_STATIC_LIBRARY=ON`` (prefer static lib) +- ``-Dyaml-cpp_ROOT=`` (include and/or library root dir) +- ``-Dyaml-cpp_STATIC_LIBRARY=ON`` (prefer static lib) +- ``-DHalf_ROOT=`` (include and/or library root dir) +- ``-DHalf_STATIC_LIBRARY=ON`` (prefer static lib) +- ``-Dpystring_ROOT=`` (include and/or library root dir) +- ``-Dpystring_STATIC_LIBRARY=ON`` (prefer static lib) +- ``-Dlcms2_ROOT=`` (include and/or library root dir) +- ``-Dlcms2_STATIC_LIBRARY=ON`` (prefer static lib) +- ``-pybind11_ROOT=`` (include and/or library root dir) +- ``-DPYTHON_EXECUTABLE=`` (Python executable) - ``-DNUKE_INSTALL_PATH=`` (or use ``NDK_PATH`` environment variable) To hint at Python package locations, add paths to the ``PYTHONPATH`` diff --git a/ext/CMakeLists.txt b/ext/CMakeLists.txt index 10bcf488d3..8a270d60ed 100644 --- a/ext/CMakeLists.txt +++ b/ext/CMakeLists.txt @@ -1,39 +1,8 @@ # SPDX-License-Identifier: BSD-3-Clause # Copyright Contributors to the OpenColorIO Project. - -############################################################################### -### External third-party C/C++ dependencies. ### - -# Expat -# https://github.com/libexpat/libexpat -set(EXPAT_MIN_VERSION 2.2.5) -find_package(Expat ${EXPAT_MIN_VERSION} REQUIRED) - -# yaml-cpp -# https://github.com/jbeder/yaml-cpp -set(YAMLCPP_MIN_VERSION 0.6.3) -find_package(YamlCpp ${YAMLCPP_MIN_VERSION} REQUIRED) - -# IlmBase (Half part only) -# https://github.com/openexr/openexr -set(ILMBASE_MIN_VERSION 2.3.0) -find_package(IlmBase ${ILMBASE_MIN_VERSION} REQUIRED) - -# Pystring -# https://github.com/imageworks/pystring -set(PYSTRING_MIN_VERSION 1.1.3) -find_package(Pystring ${PYSTRING_MIN_VERSION} REQUIRED) - -if(OCIO_BUILD_APPS) - # LCMS2 - # https://github.com/mm2/Little-CMS - set(LCMS2_MIN_VERSION 2.2) - find_package(LCMS2 ${LCMS2_MIN_VERSION} REQUIRED) -endif() - ############################################################################### -### External (modified) third-party C/C++ dependencies. ### +### External (modified) third-party C/C++ dependencies ### # Sample ICC (modified) add_subdirectory(sampleicc) diff --git a/share/ci/scripts/linux/install_expat.sh b/share/ci/scripts/linux/install_expat.sh index 3d76a5f0ef..66c4df9f2a 100755 --- a/share/ci/scripts/linux/install_expat.sh +++ b/share/ci/scripts/linux/install_expat.sh @@ -24,12 +24,12 @@ fi mkdir build cd build -cmake -DCMAKE_INSTALL_PREFIX=/usr/local \ - -DCMAKE_BUILD_TYPE=Release \ +cmake -DCMAKE_BUILD_TYPE=Release \ -DEXPAT_BUILD_TOOLS=OFF \ -DEXPAT_BUILD_EXAMPLES=OFF \ -DEXPAT_BUILD_TESTS=OFF \ -DEXPAT_SHARED_LIBS=ON \ + -DEXPAT_BUILD_DOCS=OFF \ -DCMAKE_C_FLAGS="-fPIC" \ -DCMAKE_CXX_FLAGS="-fPIC" \ ../expat/. diff --git a/share/ci/scripts/linux/install_lcms2.sh b/share/ci/scripts/linux/install_lcms2.sh index 71d9568953..6baa691d6d 100755 --- a/share/ci/scripts/linux/install_lcms2.sh +++ b/share/ci/scripts/linux/install_lcms2.sh @@ -16,12 +16,11 @@ else git checkout tags/lcms${LCMS2_VERSION} -b lcms${LCMS2_VERSION} fi -cp ../share/cmake/projects/BuildLCMS2.cmake CMakeLists.txt +cp ../share/cmake/projects/Buildlcms2.cmake CMakeLists.txt mkdir build cd build -cmake -DCMAKE_INSTALL_PREFIX=/usr/local \ - -DBUILD_SHARED_LIBS:BOOL=ON \ +cmake -DBUILD_SHARED_LIBS=ON \ -DCMAKE_C_FLAGS="-fPIC" \ ../. make -j4 diff --git a/share/ci/scripts/linux/install_oiio.sh b/share/ci/scripts/linux/install_oiio.sh index 2f53b59f7f..637cdd19de 100755 --- a/share/ci/scripts/linux/install_oiio.sh +++ b/share/ci/scripts/linux/install_oiio.sh @@ -6,10 +6,6 @@ set -ex OIIO_VERSION="$1" -# TODO: Remove this when the aswf-docker containers are upgraded to the newer -# version of OpenJpeg. OIIO has deprecated v1 support. -sudo yum -y install openjpeg2-devel - git clone https://github.com/OpenImageIO/oiio.git cd oiio @@ -22,8 +18,7 @@ fi mkdir build cd build -cmake -DCMAKE_INSTALL_PREFIX=/usr/local \ - -DOIIO_BUILD_TOOLS=OFF \ +cmake -DOIIO_BUILD_TOOLS=OFF \ -DOIIO_BUILD_TESTS=OFF \ -DVERBOSE=ON \ -DSTOP_ON_WARNING=OFF \ diff --git a/share/ci/scripts/linux/install_openexr.sh b/share/ci/scripts/linux/install_openexr.sh index 675a1068ef..9684f5bcd7 100755 --- a/share/ci/scripts/linux/install_openexr.sh +++ b/share/ci/scripts/linux/install_openexr.sh @@ -18,10 +18,10 @@ fi mkdir build cd build -cmake -DCMAKE_INSTALL_PREFIX=/usr/local \ - -DBUILD_TESTING=OFF \ +cmake -DBUILD_TESTING=OFF \ -DOPENEXR_BUILD_UTILS=OFF \ -DOPENEXR_VIEWERS_ENABLE=OFF \ + -DINSTALL_OPENEXR_EXAMPLES=OFF \ -DPYILMBASE_ENABLE=OFF \ -DCMAKE_C_FLAGS="-fPIC" \ -DCMAKE_CXX_FLAGS="-fPIC" \ diff --git a/share/ci/scripts/linux/install_pybind11.sh b/share/ci/scripts/linux/install_pybind11.sh index 9fa196bf11..c91cd8bd09 100755 --- a/share/ci/scripts/linux/install_pybind11.sh +++ b/share/ci/scripts/linux/install_pybind11.sh @@ -18,9 +18,8 @@ fi mkdir build cd build -cmake -DCMAKE_INSTALL_PREFIX=/usr/local \ - -DPYBIND11_INSTALL:BOOL=ON \ - -DPYBIND11_TEST:BOOL=OFF \ +cmake -DPYBIND11_INSTALL=ON \ + -DPYBIND11_TEST=OFF \ ../. make -j4 sudo make install diff --git a/share/ci/scripts/linux/install_pystring.sh b/share/ci/scripts/linux/install_pystring.sh index 8a2dcdc0c8..b5e1684e2a 100755 --- a/share/ci/scripts/linux/install_pystring.sh +++ b/share/ci/scripts/linux/install_pystring.sh @@ -16,12 +16,11 @@ else git checkout tags/v${PYSTRING_VERSION} -b v${PYSTRING_VERSION} fi -cp ../share/cmake/projects/BuildPystring.cmake CMakeLists.txt +cp ../share/cmake/projects/Buildpystring.cmake CMakeLists.txt mkdir build cd build -cmake -DCMAKE_INSTALL_PREFIX=/usr/local \ - -DBUILD_SHARED_LIBS:BOOL=ON \ +cmake -DBUILD_SHARED_LIBS=ON \ -DCMAKE_CXX_FLAGS="-fPIC" \ ../. make -j4 diff --git a/share/ci/scripts/linux/install_yaml-cpp.sh b/share/ci/scripts/linux/install_yaml-cpp.sh index 420db742e3..3c7780f7d7 100755 --- a/share/ci/scripts/linux/install_yaml-cpp.sh +++ b/share/ci/scripts/linux/install_yaml-cpp.sh @@ -25,8 +25,7 @@ fi mkdir build cd build -cmake -DCMAKE_INSTALL_PREFIX=/usr/local \ - -DBUILD_SHARED_LIBS=ON \ +cmake -DBUILD_SHARED_LIBS=ON \ -DYAML_CPP_BUILD_TESTS=OFF \ -DYAML_CPP_BUILD_TOOLS=OFF \ -DYAML_CPP_BUILD_CONTRIB=OFF \ diff --git a/share/cmake/modules/FindExpat.cmake b/share/cmake/modules/FindExpat.cmake deleted file mode 100644 index 07270469d8..0000000000 --- a/share/cmake/modules/FindExpat.cmake +++ /dev/null @@ -1,211 +0,0 @@ -# SPDX-License-Identifier: BSD-3-Clause -# Copyright Contributors to the OpenColorIO Project. -# -# Locate or install expat -# -# Variables defined by this module: -# EXPAT_FOUND - If FALSE, do not try to link to expat -# EXPAT_LIBRARY - Where to find expat -# EXPAT_INCLUDE_DIR - Where to find expat.h -# EXPAT_VERSION - The version of the library -# -# Targets defined by this module: -# expat::expat - IMPORTED target, if found -# -# By default, the dynamic libraries of expat will be found. To find the static -# ones instead, you must set the EXPAT_STATIC_LIBRARY variable to TRUE -# before calling find_package(Expat ...). -# -# If expat is not installed in a standard path, you can use the EXPAT_DIRS -# variable to tell CMake where to find it. If it is not found and -# OCIO_INSTALL_EXT_PACKAGES is set to MISSING or ALL, expat will be downloaded, -# built, and statically-linked into libOpenColorIO at build time. -# - -if(NOT TARGET expat::expat) - add_library(expat::expat UNKNOWN IMPORTED GLOBAL) - set(_EXPAT_TARGET_CREATE TRUE) -endif() - -############################################################################### -### Try to find package ### - -if(NOT OCIO_INSTALL_EXT_PACKAGES STREQUAL ALL) - # Try to use pkg-config to get the version - find_package(PkgConfig QUIET) - pkg_check_modules(PC_EXPAT QUIET expat) - - set(_EXPAT_SEARCH_DIRS - ${EXPAT_DIRS} - ~/Library/Frameworks - /Library/Frameworks - /usr/local - /usr - /sw # Fink - /opt/local # DarwinPorts - /opt/csw # Blastwave - /opt - ) - - # Find include directory - find_path(EXPAT_INCLUDE_DIR - NAMES - expat.h - HINTS - ${_EXPAT_SEARCH_DIRS} - ${PC_EXPAT_INCLUDE_DIRS} - PATH_SUFFIXES - include - expat/include - ) - - # Lib names to search for - set(_EXPAT_LIB_NAMES expat libexpat) - if(WIN32 AND BUILD_TYPE_DEBUG) - # Prefer Debug lib names (Windows only) - list(INSERT _EXPAT_LIB_NAMES 0 expatd) - endif() - - if(EXPAT_STATIC_LIBRARY) - # Prefer static lib names - set(_EXPAT_STATIC_LIB_NAMES - "${CMAKE_STATIC_LIBRARY_PREFIX}expat${CMAKE_STATIC_LIBRARY_SUFFIX}") - if(WIN32 AND BUILD_TYPE_DEBUG) - # Prefer static Debug lib names (Windows only) - list(INSERT _EXPAT_STATIC_LIB_NAMES 0 - "${CMAKE_STATIC_LIBRARY_PREFIX}expatd${CMAKE_STATIC_LIBRARY_SUFFIX}") - endif() - endif() - - # Find library - find_library(EXPAT_LIBRARY - NAMES - ${_EXPAT_STATIC_LIB_NAMES} - ${_EXPAT_LIB_NAMES} - HINTS - ${_EXPAT_SEARCH_DIRS} - ${PC_EXPAT_LIBRARY_DIRS} - PATH_SUFFIXES - lib64 lib - ) - - # Get version from header or config file - # if(PC_EXPAT_FOUND) - # set(EXPAT_VERSION "${PC_EXPAT_VERSION}") - if(EXPAT_INCLUDE_DIR AND EXISTS "${EXPAT_INCLUDE_DIR}/expat.h") - file(STRINGS "${EXPAT_INCLUDE_DIR}/expat.h" _EXPAT_VER_SEARCH - REGEX "^[ \t]*#define[ \t]+XML_(MAJOR|MINOR|MICRO)_VERSION[ \t]+[0-9]+.*$") - if(_EXPAT_VER_SEARCH) - foreach(_VER_PART MAJOR MINOR MICRO) - string(REGEX REPLACE ".*#define[ \t]+XML_${_VER_PART}_VERSION[ \t]+([0-9]+).*" - "\\1" EXPAT_VERSION_${_VER_PART} "${_EXPAT_VER_SEARCH}") - if(NOT EXPAT_VERSION_${_VER_PART}) - set(EXPAT_VERSION_${_VER_PART} 0) - endif() - endforeach() - set(EXPAT_VERSION - "${EXPAT_VERSION_MAJOR}.${EXPAT_VERSION_MINOR}.${EXPAT_VERSION_MICRO}") - endif() - elseif(PC_EXPAT_FOUND) - set(EXPAT_VERSION "${PC_EXPAT_VERSION}") - endif() - - # Override REQUIRED if package can be installed - if(OCIO_INSTALL_EXT_PACKAGES STREQUAL MISSING) - set(Expat_FIND_REQUIRED FALSE) - endif() - - include(FindPackageHandleStandardArgs) - find_package_handle_standard_args(Expat - REQUIRED_VARS - EXPAT_INCLUDE_DIR - EXPAT_LIBRARY - VERSION_VAR - EXPAT_VERSION - ) - set(EXPAT_FOUND ${Expat_FOUND}) -endif() - -############################################################################### -### Install package from source ### - -if(NOT EXPAT_FOUND) - include(ExternalProject) - - set(_EXT_DIST_ROOT "${CMAKE_BINARY_DIR}/ext/dist") - set(_EXT_BUILD_ROOT "${CMAKE_BINARY_DIR}/ext/build") - - # Set find_package standard args - set(EXPAT_FOUND TRUE) - set(EXPAT_VERSION ${Expat_FIND_VERSION}) - set(EXPAT_INCLUDE_DIR "${_EXT_DIST_ROOT}/include") - - # Set the expected library name - if(WIN32 AND BUILD_TYPE_DEBUG) - set(_EXPAT_LIB_SUFFIX "d") - endif() - set(EXPAT_LIBRARY - "${_EXT_DIST_ROOT}/lib/${CMAKE_STATIC_LIBRARY_PREFIX}expat${_EXPAT_LIB_SUFFIX}${CMAKE_STATIC_LIBRARY_SUFFIX}") - - if(_EXPAT_TARGET_CREATE) - if(UNIX) - set(EXPAT_C_FLAGS "${EXPAT_C_FLAGS} -fPIC") - set(EXPAT_CXX_FLAGS "${EXPAT_CXX_FLAGS} -fPIC") - endif() - - if(MSVC) - set(EXPAT_C_FLAGS "${EXPAT_C_FLAGS} /EHsc") - set(EXPAT_CXX_FLAGS "${EXPAT_CXX_FLAGS} /EHsc") - endif() - - string(STRIP "${EXPAT_C_FLAGS}" EXPAT_C_FLAGS) - string(STRIP "${EXPAT_CXX_FLAGS}" EXPAT_CXX_FLAGS) - - set(EXPAT_CMAKE_ARGS - ${EXPAT_CMAKE_ARGS} - -DCMAKE_INSTALL_PREFIX=${_EXT_DIST_ROOT} - -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE} - -DBUILD_examples:BOOL=OFF - -DBUILD_tests:BOOL=OFF - -DBUILD_shared:BOOL=OFF - -DBUILD_doc:BOOL=OFF - -DCMAKE_C_FLAGS=${EXPAT_C_FLAGS} - -DCMAKE_CXX_FLAGS=${EXPAT_CXX_FLAGS} - -DCMAKE_CXX_STANDARD=${CMAKE_CXX_STANDARD} - ) - if(CMAKE_TOOLCHAIN_FILE) - set(EXPAT_CMAKE_ARGS - ${EXPAT_CMAKE_ARGS} -DCMAKE_TOOLCHAIN_FILE=${CMAKE_TOOLCHAIN_FILE}) - endif() - - # Hack to let imported target be built from ExternalProject_Add - file(MAKE_DIRECTORY ${EXPAT_INCLUDE_DIR}) - - ExternalProject_Add(expat_install - GIT_REPOSITORY "https://github.com/libexpat/libexpat.git" - GIT_TAG "R_${Expat_FIND_VERSION_MAJOR}_${Expat_FIND_VERSION_MINOR}_${Expat_FIND_VERSION_PATCH}" - GIT_CONFIG advice.detachedHead=false - GIT_SHALLOW TRUE - PREFIX "${_EXT_BUILD_ROOT}/libexpat" - BUILD_BYPRODUCTS ${EXPAT_LIBRARY} - SOURCE_SUBDIR expat - CMAKE_ARGS ${EXPAT_CMAKE_ARGS} - EXCLUDE_FROM_ALL TRUE - ) - - add_dependencies(expat::expat expat_install) - message(STATUS "Installing Expat: ${EXPAT_LIBRARY} (version ${EXPAT_VERSION})") - endif() -endif() - -############################################################################### -### Configure target ### - -if(_EXPAT_TARGET_CREATE) - set_target_properties(expat::expat PROPERTIES - IMPORTED_LOCATION ${EXPAT_LIBRARY} - INTERFACE_INCLUDE_DIRECTORIES ${EXPAT_INCLUDE_DIR} - ) - - mark_as_advanced(EXPAT_INCLUDE_DIR EXPAT_LIBRARY EXPAT_VERSION) -endif() diff --git a/share/cmake/modules/FindExtPackages.cmake b/share/cmake/modules/FindExtPackages.cmake new file mode 100644 index 0000000000..743db41f56 --- /dev/null +++ b/share/cmake/modules/FindExtPackages.cmake @@ -0,0 +1,52 @@ +# SPDX-License-Identifier: BSD-3-Clause +# Copyright Contributors to the OpenColorIO Project. +# +# All find modules used in this module support typical find_package +# behavior or installation of packages from external projects, as configured +# by the OCIO_INSTALL_EXT_PACKAGES option. +# + +# expat +# https://github.com/libexpat/libexpat +find_package(expat 2.2.8 REQUIRED) + +# yaml-cpp +# https://github.com/jbeder/yaml-cpp +find_package(yaml-cpp 0.6.3 REQUIRED) + +# Half (OpenEXR/IlmBase) +# https://github.com/openexr/openexr +find_package(Half 2.4.0 REQUIRED) + +# pystring +# https://github.com/imageworks/pystring +find_package(pystring 1.1.3 REQUIRED) + +if(OCIO_BUILD_APPS) + # lcms2 + # https://github.com/mm2/Little-CMS + find_package(lcms2 2.2 REQUIRED) +endif() + +if(OCIO_BUILD_PYTHON) + # pybind11 + # https://github.com/pybind/pybind11 + find_package(pybind11 2.4.3 REQUIRED) +endif() + +if(OCIO_BUILD_DOCS) + find_package(PythonInterp 2.7 QUIET) + + if(PYTHONINTERP_FOUND) + if(PYTHON_VERSION_MAJOR GREATER_EQUAL 3) + set(Sphinx_MIN_VERSION 2.0.0) + else() + # Last release with Python 2.7 support + set(Sphinx_MIN_VERSION 1.8.5) + endif() + + # Sphinx + # https://pypi.python.org/pypi/Sphinx + find_package(Sphinx ${Sphinx_MIN_VERSION} REQUIRED) + endif() +endif() diff --git a/share/cmake/modules/FindHalf.cmake b/share/cmake/modules/FindHalf.cmake new file mode 100644 index 0000000000..38a74c8dd6 --- /dev/null +++ b/share/cmake/modules/FindHalf.cmake @@ -0,0 +1,226 @@ +# SPDX-License-Identifier: BSD-3-Clause +# Copyright Contributors to the OpenColorIO Project. +# +# Locate or install ilmbase +# +# Variables defined by this module: +# Half_FOUND - If FALSE, do not try to link to ilmbase +# Half_LIBRARY - Half library to link to +# Half_INCLUDE_DIR - Where to find half.h +# Half_VERSION - The version of the library +# +# Targets defined by this module: +# IlmBase::Half - IMPORTED target, if found +# +# By default, the dynamic libraries of ilmbase will be found. To find the +# static ones instead, you must set the Half_STATIC_LIBRARY variable to +# TRUE before calling find_package(IlmBase ...). +# +# If ilmbase is not installed in a standard path, you can use the +# Half_ROOT variable to tell CMake where to find it. If it is not found +# and OCIO_INSTALL_EXT_PACKAGES is set to MISSING or ALL, ilmbase will be +# downloaded, built, and statically-linked into libOpenColorIO at build time. +# + +# IlmBase components may have the version in their name +set(_Half_LIB_VER "${Half_FIND_VERSION_MAJOR}_${Half_FIND_VERSION_MINOR}") + +############################################################################### +### Try to find package ### + +if(NOT OCIO_INSTALL_EXT_PACKAGES STREQUAL ALL) + set(_Half_REQUIRED_VARS Half_LIBRARY) + + if(NOT DEFINED Half_ROOT) + # Search for IlmBaseConfig.cmake + find_package(IlmBase ${Half_FIND_VERSION} CONFIG QUIET) + endif() + + if(Half_FOUND) + get_target_property(Half_LIBRARY IlmBase::Half LOCATION) + else() + list(APPEND _Half_REQUIRED_VARS Half_INCLUDE_DIR) + + # Search for IlmBase.pc + find_package(PkgConfig QUIET) + pkg_check_modules(PC_IlmBase QUIET "IlmBase>=${Half_FIND_VERSION}") + + # Find include directory + find_path(Half_INCLUDE_DIR + NAMES + OpenEXR/half.h + HINTS + ${Half_ROOT} + ${PC_Half_INCLUDE_DIRS} + PATH_SUFFIXES + include + OpenEXR/include + ) + + # Lib names to search for + set(_Half_LIB_NAMES "Half-${_Half_LIB_VER}" Half) + if(BUILD_TYPE_DEBUG) + # Prefer Debug lib names + list(INSERT _Half_LIB_NAMES 0 "Half-${_Half_LIB_VER}_d") + endif() + + if(Half_STATIC_LIBRARY) + # Prefer static lib names + set(_Half_STATIC_LIB_NAMES + "${CMAKE_STATIC_LIBRARY_PREFIX}Half-${_Half_LIB_VER}${CMAKE_STATIC_LIBRARY_SUFFIX}" + "${CMAKE_STATIC_LIBRARY_PREFIX}Half${CMAKE_STATIC_LIBRARY_SUFFIX}" + ) + if(BUILD_TYPE_DEBUG) + # Prefer static Debug lib names + list(INSERT _Half_STATIC_LIB_NAMES 0 + "${CMAKE_STATIC_LIBRARY_PREFIX}Half-${_Half_LIB_VER}_d${CMAKE_STATIC_LIBRARY_SUFFIX}") + endif() + endif() + + # Find library + find_library(Half_LIBRARY + NAMES + ${_Half_STATIC_LIB_NAMES} + ${_Half_LIB_NAMES} + HINTS + ${Half_ROOT} + ${PC_Half_LIBRARY_DIRS} + PATH_SUFFIXES + lib64 lib + ) + + # Get version from config header file + if(Half_INCLUDE_DIR) + if(EXISTS "${Half_INCLUDE_DIR}/OpenEXR/IlmBaseConfig.h") + set(_Half_CONFIG "${Half_INCLUDE_DIR}/OpenEXR/IlmBaseConfig.h") + elseif(EXISTS "${Half_INCLUDE_DIR}/OpenEXR/OpenEXRConfig.h") + set(_Half_CONFIG "${Half_INCLUDE_DIR}/OpenEXR/OpenEXRConfig.h") + endif() + endif() + + if(_Half_CONFIG) + file(STRINGS "${_Half_CONFIG}" _Half_VER_SEARCH + REGEX "^[ \t]*#define[ \t]+(OPENEXR|ILMBASE)_VERSION_STRING[ \t]+\"[.0-9]+\".*$") + if(_Half_VER_SEARCH) + string(REGEX REPLACE ".*#define[ \t]+(OPENEXR|ILMBASE)_VERSION_STRING[ \t]+\"([.0-9]+)\".*" + "\\2" Half_VERSION "${_Half_VER_SEARCH}") + endif() + elseif(PC_Half_FOUND) + set(Half_VERSION "${PC_Half_VERSION}") + endif() + endif() + + # Override REQUIRED if package can be installed + if(OCIO_INSTALL_EXT_PACKAGES STREQUAL MISSING) + set(Half_FIND_REQUIRED FALSE) + endif() + + include(FindPackageHandleStandardArgs) + find_package_handle_standard_args(Half + REQUIRED_VARS + ${_Half_REQUIRED_VARS} + VERSION_VAR + Half_VERSION + ) +endif() + +############################################################################### +### Create target + +if (NOT TARGET IlmBase::Half) + add_library(IlmBase::Half UNKNOWN IMPORTED GLOBAL) + set(_Half_TARGET_CREATE TRUE) +endif() + +############################################################################### +### Install package from source ### + +if(NOT Half_FOUND) + include(ExternalProject) + include(GNUInstallDirs) + + set(_EXT_DIST_ROOT "${CMAKE_BINARY_DIR}/ext/dist") + set(_EXT_BUILD_ROOT "${CMAKE_BINARY_DIR}/ext/build") + + # Set find_package standard args + set(Half_FOUND TRUE) + set(Half_VERSION ${Half_FIND_VERSION}) + set(Half_INCLUDE_DIR "${_EXT_DIST_ROOT}/${CMAKE_INSTALL_INCLUDEDIR}") + + # Set the expected library name. "_d" is appended to Debug Windows builds + # <= OpenEXR 2.3.0. In newer versions, it is appended to Debug libs on + # all platforms. + if(BUILD_TYPE_DEBUG AND (WIN32 OR Half_VERSION VERSION_GREATER "2.3.0")) + set(_Half_LIB_SUFFIX "_d") + endif() + + set(Half_LIBRARY + "${_EXT_DIST_ROOT}/${CMAKE_INSTALL_LIBDIR}/${CMAKE_STATIC_LIBRARY_PREFIX}Half-${_Half_LIB_VER}${_Half_LIB_SUFFIX}${CMAKE_STATIC_LIBRARY_SUFFIX}") + + if(_Half_TARGET_CREATE) + if(UNIX) + set(Half_CXX_FLAGS "${Half_CXX_FLAGS} -fPIC") + endif() + + if(MSVC) + set(Half_CXX_FLAGS "${Half_CXX_FLAGS} /EHsc") + endif() + + string(STRIP "${Half_CXX_FLAGS}" Half_CXX_FLAGS) + + set(Half_CMAKE_ARGS + ${Half_CMAKE_ARGS} + -DCMAKE_INSTALL_PREFIX=${_EXT_DIST_ROOT} + -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE} + -DBUILD_SHARED_LIBS=OFF + -DBUILD_TESTING=OFF + -DOPENEXR_VIEWERS_ENABLE=OFF + -DPYILMBASE_ENABLE=OFF + -DCMAKE_CXX_FLAGS=${Half_CXX_FLAGS} + -DCMAKE_CXX_STANDARD=${CMAKE_CXX_STANDARD} + ) + + if(CMAKE_TOOLCHAIN_FILE) + set(Half_CMAKE_ARGS + ${Half_CMAKE_ARGS} -DCMAKE_TOOLCHAIN_FILE=${CMAKE_TOOLCHAIN_FILE}) + endif() + + # Hack to let imported target be built from ExternalProject_Add + file(MAKE_DIRECTORY ${Half_INCLUDE_DIR}) + + ExternalProject_Add(ilmbase_install + GIT_REPOSITORY "https://github.com/openexr/openexr.git" + GIT_TAG "v${Half_VERSION}" + GIT_CONFIG advice.detachedHead=false + GIT_SHALLOW TRUE + PREFIX "${_EXT_BUILD_ROOT}/openexr" + BUILD_BYPRODUCTS ${Half_LIBRARY} + CMAKE_ARGS ${Half_CMAKE_ARGS} + PATCH_COMMAND + ${CMAKE_COMMAND} -P "${CMAKE_SOURCE_DIR}/share/cmake/scripts/PatchOpenEXR.cmake" + BUILD_COMMAND + ${CMAKE_COMMAND} --build . + --config ${CMAKE_BUILD_TYPE} + --target Half + INSTALL_COMMAND + ${CMAKE_COMMAND} -DCMAKE_INSTALL_CONFIG_NAME=${CMAKE_BUILD_TYPE} + -P "IlmBase/Half/cmake_install.cmake" + EXCLUDE_FROM_ALL TRUE + ) + + add_dependencies(IlmBase::Half ilmbase_install) + message(STATUS "Installing Half (IlmBase): ${Half_LIBRARY} (version \"${Half_VERSION}\")") + endif() +endif() + +############################################################################### +### Configure target ### + +if(_Half_TARGET_CREATE) + set_target_properties(IlmBase::Half PROPERTIES + IMPORTED_LOCATION ${Half_LIBRARY} + INTERFACE_INCLUDE_DIRECTORIES ${Half_INCLUDE_DIR} + ) + + mark_as_advanced(Half_INCLUDE_DIR Half_LIBRARY Half_VERSION) +endif() diff --git a/share/cmake/modules/FindIlmBase.cmake b/share/cmake/modules/FindIlmBase.cmake deleted file mode 100644 index 74bcd20df0..0000000000 --- a/share/cmake/modules/FindIlmBase.cmake +++ /dev/null @@ -1,216 +0,0 @@ -# SPDX-License-Identifier: BSD-3-Clause -# Copyright Contributors to the OpenColorIO Project. -# -# Locate or install ilmbase -# -# Variables defined by this module: -# ILMBASE_FOUND - If FALSE, do not try to link to ilmbase -# ILMBASE_LIBRARY - Where to find Half -# ILMBASE_INCLUDE_DIR - Where to find half.h -# ILMBASE_VERSION - The version of the library -# -# Targets defined by this module: -# ilmbase::ilmbase - IMPORTED target, if found -# -# By default, the dynamic libraries of ilmbase will be found. To find the -# static ones instead, you must set the ILMBASE_STATIC_LIBRARY variable to -# TRUE before calling find_package(IlmBase ...). -# -# If ilmbase is not installed in a standard path, you can use the -# ILMBASE_DIRS variable to tell CMake where to find it. If it is not found -# and OCIO_INSTALL_EXT_PACKAGES is set to MISSING or ALL, ilmbase will be -# downloaded, built, and statically-linked into libOpenColorIO at build time. -# - -if (NOT TARGET ilmbase::ilmbase) - add_library(ilmbase::ilmbase UNKNOWN IMPORTED GLOBAL) - set(_ILMBASE_TARGET_CREATE TRUE) -endif() - -# IlmBase components may have the version in their name -set(_ILMBASE_LIB_VER "${IlmBase_FIND_VERSION_MAJOR}_${IlmBase_FIND_VERSION_MINOR}") - -############################################################################### -### Try to find package ### - -if(NOT OCIO_INSTALL_EXT_PACKAGES STREQUAL ALL) - set(_ILMBASE_SEARCH_DIRS - ${ILMBASE_DIRS} - ~/Library/Frameworks - /Library/Frameworks - /usr/local - /usr - /sw # Fink - /opt/local # DarwinPorts - /opt/csw # Blastwave - /opt - ) - - # Find include directory - find_path(ILMBASE_INCLUDE_DIR - NAMES - OpenEXR/half.h - HINTS - ${_ILMBASE_SEARCH_DIRS} - PATH_SUFFIXES - include - OpenEXR/include - ) - - # Lib names to search for - set(_ILMBASE_LIB_NAMES "Half-${_ILMBASE_LIB_VER}" Half) - if(BUILD_TYPE_DEBUG) - # Prefer Debug lib names - list(INSERT _ILMBASE_LIB_NAMES 0 "Half-${_ILMBASE_LIB_VER}_d") - endif() - - if(ILMBASE_STATIC_LIBRARY) - # Prefer static lib names - set(_ILMBASE_STATIC_LIB_NAMES - "${CMAKE_STATIC_LIBRARY_PREFIX}Half-${_ILMBASE_LIB_VER}_s${CMAKE_STATIC_LIBRARY_SUFFIX}" - "${CMAKE_STATIC_LIBRARY_PREFIX}Half${CMAKE_STATIC_LIBRARY_SUFFIX}" - ) - if(BUILD_TYPE_DEBUG) - # Prefer static Debug lib names - list(INSERT _ILMBASE_STATIC_LIB_NAMES 0 - "${CMAKE_STATIC_LIBRARY_PREFIX}Half-${_ILMBASE_LIB_VER}_s_d${CMAKE_STATIC_LIBRARY_SUFFIX}") - endif() - endif() - - # Find library - find_library(ILMBASE_LIBRARY - NAMES - ${_ILMBASE_STATIC_LIB_NAMES} - ${_ILMBASE_LIB_NAMES} - HINTS - ${_ILMBASE_SEARCH_DIRS} - PATH_SUFFIXES - lib64 lib - ) - - # Get version from config header file - if(ILMBASE_INCLUDE_DIR) - if(EXISTS "${ILMBASE_INCLUDE_DIR}/OpenEXR/IlmBaseConfig.h") - set(_ILMBASE_CONFIG "${ILMBASE_INCLUDE_DIR}/OpenEXR/IlmBaseConfig.h") - elseif(EXISTS "${ILMBASE_INCLUDE_DIR}/OpenEXR/OpenEXRConfig.h") - set(_ILMBASE_CONFIG "${ILMBASE_INCLUDE_DIR}/OpenEXR/OpenEXRConfig.h") - endif() - endif() - - if(_ILMBASE_CONFIG) - file(STRINGS "${_ILMBASE_CONFIG}" _ILMBASE_VER_SEARCH - REGEX "^[ \t]*#define[ \t]+(OPENEXR|ILMBASE)_VERSION_STRING[ \t]+\"[.0-9]+\".*$") - if(_ILMBASE_VER_SEARCH) - string(REGEX REPLACE ".*#define[ \t]+(OPENEXR|ILMBASE)_VERSION_STRING[ \t]+\"([.0-9]+)\".*" - "\\2" ILMBASE_VERSION "${_ILMBASE_VER_SEARCH}") - endif() - endif() - - # Override REQUIRED if package can be installed - if(OCIO_INSTALL_EXT_PACKAGES STREQUAL MISSING) - set(IlmBase_FIND_REQUIRED FALSE) - endif() - - include(FindPackageHandleStandardArgs) - find_package_handle_standard_args(IlmBase - REQUIRED_VARS - ILMBASE_INCLUDE_DIR - ILMBASE_LIBRARY - VERSION_VAR - ILMBASE_VERSION - ) - set(ILMBASE_FOUND ${IlmBase_FOUND}) -endif() - -############################################################################### -### Install package from source ### - -if(NOT ILMBASE_FOUND) - include(ExternalProject) - - set(_EXT_DIST_ROOT "${CMAKE_BINARY_DIR}/ext/dist") - set(_EXT_BUILD_ROOT "${CMAKE_BINARY_DIR}/ext/build") - - # Set find_package standard args - set(ILMBASE_FOUND TRUE) - set(ILMBASE_VERSION ${IlmBase_FIND_VERSION}) - set(ILMBASE_INCLUDE_DIR "${_EXT_DIST_ROOT}/include") - - # Set the expected library name. "_d" is appended to Debug Windows builds - # <= OpenEXR 2.3.0. In newer versions, it is appended to Debug libs on - # all platforms. - if(BUILD_TYPE_DEBUG AND (WIN32 OR ILMBASE_VERSION VERSION_GREATER "2.3.0")) - set(_ILMBASE_LIB_SUFFIX "_d") - endif() - - set(ILMBASE_LIBRARY - "${_EXT_DIST_ROOT}/lib/${CMAKE_STATIC_LIBRARY_PREFIX}Half-${_ILMBASE_LIB_VER}_s${_ILMBASE_LIB_SUFFIX}${CMAKE_STATIC_LIBRARY_SUFFIX}") - - if(_ILMBASE_TARGET_CREATE) - if(UNIX) - set(ILMBASE_CXX_FLAGS "${ILMBASE_CXX_FLAGS} -fPIC") - endif() - - if(MSVC) - set(ILMBASE_CXX_FLAGS "${ILMBASE_CXX_FLAGS} /EHsc") - endif() - - string(STRIP "${ILMBASE_CXX_FLAGS}" ILMBASE_CXX_FLAGS) - - set(ILMBASE_CMAKE_ARGS - ${ILMBASE_CMAKE_ARGS} - -DCMAKE_INSTALL_PREFIX=${_EXT_DIST_ROOT} - -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE} - -DOPENEXR_BUILD_ILMBASE:BOOL=ON - -DOPENEXR_BUILD_OPENEXR:BOOL=OFF - -DOPENEXR_BUILD_PYTHON_LIBS:BOOL=OFF - -DOPENEXR_BUILD_SHARED:BOOL=OFF - -DOPENEXR_BUILD_STATIC:BOOL=ON - -DOPENEXR_BUILD_UTILS:BOOL=OFF - -DOPENEXR_BUILD_TESTS:BOOL=OFF - -DCMAKE_CXX_FLAGS=${ILMBASE_CXX_FLAGS} - -DCMAKE_CXX_STANDARD=${CMAKE_CXX_STANDARD} - ) - - if(CMAKE_TOOLCHAIN_FILE) - set(ILMBASE_CMAKE_ARGS - ${ILMBASE_CMAKE_ARGS} -DCMAKE_TOOLCHAIN_FILE=${CMAKE_TOOLCHAIN_FILE}) - endif() - - # Hack to let imported target be built from ExternalProject_Add - file(MAKE_DIRECTORY ${ILMBASE_INCLUDE_DIR}) - - ExternalProject_Add(ilmbase_install - GIT_REPOSITORY "https://github.com/openexr/openexr.git" - GIT_TAG "v${ILMBASE_VERSION}" - GIT_CONFIG advice.detachedHead=false - GIT_SHALLOW TRUE - PREFIX "${_EXT_BUILD_ROOT}/openexr" - BUILD_BYPRODUCTS ${ILMBASE_LIBRARY} - CMAKE_ARGS ${ILMBASE_CMAKE_ARGS} - BUILD_COMMAND - ${CMAKE_COMMAND} --build . - --config ${CMAKE_BUILD_TYPE} - --target Half_static - INSTALL_COMMAND - ${CMAKE_COMMAND} -DCMAKE_INSTALL_CONFIG_NAME=${CMAKE_BUILD_TYPE} - -P "IlmBase/Half/cmake_install.cmake" - EXCLUDE_FROM_ALL TRUE - ) - - add_dependencies(ilmbase::ilmbase ilmbase_install) - message(STATUS "Installing IlmBase: ${ILMBASE_LIBRARY} (version ${ILMBASE_VERSION})") - endif() -endif() - -############################################################################### -### Configure target ### - -if(_ILMBASE_TARGET_CREATE) - set_target_properties(ilmbase::ilmbase PROPERTIES - IMPORTED_LOCATION ${ILMBASE_LIBRARY} - INTERFACE_INCLUDE_DIRECTORIES ${ILMBASE_INCLUDE_DIR} - ) - - mark_as_advanced(ILMBASE_INCLUDE_DIR ILMBASE_LIBRARY ILMBASE_VERSION) -endif() diff --git a/share/cmake/modules/FindOpenImageIO.cmake b/share/cmake/modules/FindOpenImageIO.cmake deleted file mode 100755 index ea82d59f4c..0000000000 --- a/share/cmake/modules/FindOpenImageIO.cmake +++ /dev/null @@ -1,36 +0,0 @@ -# SPDX-License-Identifier: BSD-3-Clause -# Copyright Contributors to the OpenColorIO Project. -# -# Variables defined by this module: -# OpenImageIO_FOUND -# -# Targets exported by this module: -# OpenImageIO -# -# Usage: -# FIND_PACKAGE( OpenImageIO ) -# FIND_PACKAGE( OpenImageIO REQUIRED ) -# - -find_path(OpenImageIO_INCLUDE_DIR OpenImageIO/imageio.h PATH_SUFFIXES include) -find_library(OpenImageIO_LIBRARIES NAMES OpenImageIO OIIO) -if(OpenImageIO_LIBRARIES) - get_filename_component(OpenImageIO_LIBRARY_DIR ${OpenImageIO_LIBRARIES} DIRECTORY) -endif() - -include(FindPackageHandleStandardArgs) -find_package_handle_standard_args(OpenImageIO REQUIRED_VARS OpenImageIO_LIBRARIES OpenImageIO_INCLUDE_DIR OpenImageIO_LIBRARY_DIR) -mark_as_advanced(OpenImageIO_LIBRARIES OpenImageIO_INCLUDE_DIR OpenImageIO_LIBRARY_DIR) - -if(OpenImageIO_FOUND) - # Due to OpenImageIO exposing IlmBase includes in its public headers, we must add the IlmBase Include dir - # to our include path to use OpenImageIO - find_package(IlmBase REQUIRED) - - add_library(OpenImageIO INTERFACE IMPORTED GLOBAL) - set(OpenImageIO_COMBINED_INCLUDES "") - list(APPEND OpenImageIO_COMBINED_INCLUDES ${OpenImageIO_INCLUDE_DIR}) - list(APPEND OpenImageIO_COMBINED_INCLUDES ${ILMBASE_INCLUDE_DIR}) - set_property(TARGET OpenImageIO PROPERTY INTERFACE_LINK_LIBRARIES ${OpenImageIO_LIBRARIES}) - set_property(TARGET OpenImageIO PROPERTY INTERFACE_INCLUDE_DIRECTORIES ${OpenImageIO_COMBINED_INCLUDES}) -endif() diff --git a/share/cmake/modules/FindSphinx.cmake b/share/cmake/modules/FindSphinx.cmake index b4749056f7..4a1ada1f60 100644 --- a/share/cmake/modules/FindSphinx.cmake +++ b/share/cmake/modules/FindSphinx.cmake @@ -4,8 +4,8 @@ # Locate or install Sphinx (Python documentation generator) # # Variables defined by this module: -# SPHINX_FOUND -# SPHINX_EXECUTABLE (CACHE) +# Sphinx_FOUND +# Sphinx_EXECUTABLE (CACHE) # # Targets defined by this module: # Sphinx - custom pip target, if package can be installed @@ -13,7 +13,7 @@ # Usage: # find_package(Sphinx) # -# If Sphinx is not installed in a standard path, add it to the SPHINX_DIRS +# If Sphinx is not installed in a standard path, add it to the Sphinx_ROOT # variable to tell CMake where to find it. If it is not found and # OCIO_INSTALL_EXT_PACKAGES is set to MISSING or ALL, Sphinx will be # installed via pip at build time. @@ -23,7 +23,7 @@ find_package(PythonInterp 2.7 QUIET) if(NOT TARGET Sphinx) add_custom_target(Sphinx) - set(_SPHINX_TARGET_CREATE TRUE) + set(_Sphinx_TARGET_CREATE TRUE) endif() if(PYTHONINTERP_FOUND AND WIN32) @@ -35,13 +35,12 @@ endif() ### Try to find package ### if(NOT OCIO_INSTALL_EXT_PACKAGES STREQUAL ALL) - # Find sphinx-build - find_program(SPHINX_EXECUTABLE + find_program(Sphinx_EXECUTABLE NAMES sphinx-build HINTS - ${SPHINX_DIRS} + ${Sphinx_ROOT} ${PYTHON_SCRIPTS_DIR} ) @@ -53,30 +52,30 @@ if(NOT OCIO_INSTALL_EXT_PACKAGES STREQUAL ALL) include(FindPackageHandleStandardArgs) find_package_handle_standard_args(Sphinx REQUIRED_VARS - SPHINX_EXECUTABLE + Sphinx_EXECUTABLE ) - set(SPHINX_FOUND ${Sphinx_FOUND}) + set(Sphinx_FOUND ${Sphinx_FOUND}) endif() ############################################################################### ### Install package from PyPi ### -if(NOT SPHINX_FOUND) +if(NOT Sphinx_FOUND) set(_EXT_DIST_ROOT "${CMAKE_BINARY_DIR}/ext/dist") # Set find_package standard args - set(SPHINX_FOUND TRUE) + set(Sphinx_FOUND TRUE) if(WIN32) - set(SPHINX_EXECUTABLE "${_EXT_DIST_ROOT}/Scripts/sphinx-build") + set(Sphinx_EXECUTABLE "${_EXT_DIST_ROOT}/Scripts/sphinx-build") # On Windows platform, pip is in the Scripts sub-directory. set(_PYTHON_PIP "${PYTHON_SCRIPTS_DIR}/pip.exe") else() - set(SPHINX_EXECUTABLE "${_EXT_DIST_ROOT}/bin/sphinx-build") + set(Sphinx_EXECUTABLE "${_EXT_DIST_ROOT}/bin/sphinx-build") set(_PYTHON_PIP "pip") endif() # Configure install target - if(_SPHINX_TARGET_CREATE) + if(_Sphinx_TARGET_CREATE) add_custom_command( TARGET Sphinx @@ -88,8 +87,8 @@ if(NOT SPHINX_FOUND) "${CMAKE_BINARY_DIR}" ) - message(STATUS "Installing Sphinx: ${SPHINX_EXECUTABLE} (version ${Sphinx_FIND_VERSION})") + message(STATUS "Installing Sphinx: ${Sphinx_EXECUTABLE} (version \"${Sphinx_FIND_VERSION}\")") endif() endif() -mark_as_advanced(SPHINX_EXECUTABLE) +mark_as_advanced(Sphinx_EXECUTABLE) diff --git a/share/cmake/modules/FindYamlCpp.cmake b/share/cmake/modules/FindYamlCpp.cmake deleted file mode 100644 index b306a78853..0000000000 --- a/share/cmake/modules/FindYamlCpp.cmake +++ /dev/null @@ -1,221 +0,0 @@ -# SPDX-License-Identifier: BSD-3-Clause -# Copyright Contributors to the OpenColorIO Project. -# -# Locate or install yaml-cpp -# -# Variables defined by this module: -# YAMLCPP_FOUND - If FALSE, do not try to link to yamlcpp -# YAMLCPP_LIBRARY - Where to find yaml-cpp -# YAMLCPP_INCLUDE_DIR - Where to find yaml.h -# YAMLCPP_VERSION - The version of the library -# -# Targets defined by this module: -# yamlcpp::yamlcpp - IMPORTED target, if found -# -# By default, the dynamic libraries of yaml-cpp will be found. To find the -# static ones instead, you must set the YAMLCPP_STATIC_LIBRARY variable to -# TRUE before calling find_package(YamlCpp ...). -# -# If yaml-cpp is not installed in a standard path, you can use the -# YAMLCPP_DIRS variable to tell CMake where to find it. If it is not found -# and OCIO_INSTALL_EXT_PACKAGES is set to MISSING or ALL, yaml-cpp will be -# downloaded, built, and statically-linked into libOpenColorIO at build time. -# - -if(NOT TARGET yamlcpp::yamlcpp) - add_library(yamlcpp::yamlcpp UNKNOWN IMPORTED GLOBAL) - set(_YAMLCPP_TARGET_CREATE TRUE) -endif() - -############################################################################### -### Try to find package ### - -if(NOT OCIO_INSTALL_EXT_PACKAGES STREQUAL ALL) - # Try to use pkg-config to get the version - find_package(PkgConfig QUIET) - pkg_check_modules(PC_YAMLCPP QUIET yaml-cpp) - - set(_YAMLCPP_SEARCH_DIRS - ${YAMLCPP_DIRS} - ~/Library/Frameworks - /Library/Frameworks - /usr/local - /usr - /sw # Fink - /opt/local # DarwinPorts - /opt/csw # Blastwave - /opt - ) - - # Find include directory - find_path(YAMLCPP_INCLUDE_DIR - NAMES - yaml-cpp/yaml.h - HINTS - ${_YAMLCPP_SEARCH_DIRS} - ${PC_YAMLCPP_INCLUDE_DIRS} - PATH_SUFFIXES - include - yaml-cpp/include - ) - - # Lib names to search for - set(_YAMLCPP_LIB_NAMES yaml-cpp) - if(WIN32 AND BUILD_TYPE_DEBUG) - # Prefer Debug lib names (Windows only) - list(INSERT _YAMLCPP_LIB_NAMES 0 yaml-cppd) - endif() - - if(YAMLCPP_STATIC_LIBRARY) - # Prefer static lib names - if(WIN32) - set(_YAMLCPP_LIB_SUFFIX "md") - endif() - set(_YAMLCPP_STATIC_LIB_NAMES - "libyaml-cpp${_YAMLCPP_LIB_SUFFIX}${CMAKE_STATIC_LIBRARY_SUFFIX}") - if(WIN32 AND BUILD_TYPE_DEBUG) - # Prefer static Debug lib names (Windows only) - list(INSERT _YAMLCPP_STATIC_LIB_NAMES 0 - "libyaml-cpp${_YAMLCPP_LIB_SUFFIX}d${CMAKE_STATIC_LIBRARY_SUFFIX}") - endif() - endif() - - # Find library - find_library(YAMLCPP_LIBRARY - NAMES - ${_YAMLCPP_STATIC_LIB_NAMES} - ${_YAMLCPP_LIB_NAMES} - HINTS - ${_YAMLCPP_SEARCH_DIRS} - ${PC_YAMLCPP_LIBRARY_DIRS} - PATH_SUFFIXES - lib64 lib - ) - - # Get version from config if it was found. - if(PC_YAMLCPP_VERSION) - set(YAMLCPP_VERSION "${PC_YAMLCPP_VERSION}") - elseif(EXISTS "${YAMLCPP_INCLUDE_DIR}/yaml-cpp/iterator.h") - set(YAMLCPP_VERSION "0.3.0") - elseif(EXISTS "${YAMLCPP_INCLUDE_DIR}/yaml-cpp/noncopyable.h") - # The version is higher than 0.3.0 but lower than 0.6.3 - # i.e. the version 0.6.3 removes the file 'yaml-cpp/noncopyable.h. - set(YAMLCPP_VERSION "0.5.3") - else() - # The only supported version. - set(YAMLCPP_VERSION "0.6.3") - endif() - - # Override REQUIRED if package can be installed - if(OCIO_INSTALL_EXT_PACKAGES STREQUAL MISSING) - set(YamlCpp_FIND_REQUIRED FALSE) - endif() - - include(FindPackageHandleStandardArgs) - find_package_handle_standard_args(YamlCpp - REQUIRED_VARS - YAMLCPP_INCLUDE_DIR - YAMLCPP_LIBRARY - VERSION_VAR - YAMLCPP_VERSION - ) - set(YAMLCPP_FOUND ${YamlCpp_FOUND}) -endif() - -############################################################################### -### Install package from source ### - -if(NOT YAMLCPP_FOUND) - include(ExternalProject) - - set(_EXT_DIST_ROOT "${CMAKE_BINARY_DIR}/ext/dist") - set(_EXT_BUILD_ROOT "${CMAKE_BINARY_DIR}/ext/build") - - # Set find_package standard args - set(YAMLCPP_FOUND TRUE) - set(YAMLCPP_VERSION ${YamlCpp_FIND_VERSION}) - set(YAMLCPP_INCLUDE_DIR "${_EXT_DIST_ROOT}/include") - - # Set the expected library name - if(WIN32) - set(_YAMLCPP_LIB_SUFFIX "md") - if(BUILD_TYPE_DEBUG) - string(APPEND _YAMLCPP_LIB_SUFFIX "d") - endif() - endif() - set(YAMLCPP_LIBRARY - "${_EXT_DIST_ROOT}/lib/libyaml-cpp${_YAMLCPP_LIB_SUFFIX}${CMAKE_STATIC_LIBRARY_SUFFIX}") - - if(_YAMLCPP_TARGET_CREATE) - if(MSVC) - set(YAMLCPP_CXX_FLAGS "${YAMLCPP_CXX_FLAGS} /EHsc") - endif() - - if(UNIX) - set(YAMLCPP_CXX_FLAGS "${YAMLCPP_CXX_FLAGS} -fvisibility=hidden -fPIC") - if(OCIO_INLINES_HIDDEN) - set(YAMLCPP_CXX_FLAGS "${YAMLCPP_CXX_FLAGS} -fvisibility-inlines-hidden") - endif() - endif() - - string(STRIP "${YAMLCPP_CXX_FLAGS}" YAMLCPP_CXX_FLAGS) - - set(YAMLCPP_CMAKE_ARGS - ${YAMLCPP_CMAKE_ARGS} - -DCMAKE_INSTALL_PREFIX=${_EXT_DIST_ROOT} - -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE} - -DBUILD_SHARED_LIBS:BOOL=OFF - -DYAML_BUILD_SHARED_LIBS:BOOL=OFF - -DYAML_CPP_BUILD_TESTS:BOOL=OFF - -DYAML_CPP_BUILD_TOOLS:BOOL=OFF - -DYAML_CPP_BUILD_CONTRIB:BOOL=OFF - -DCMAKE_CXX_FLAGS=${YAMLCPP_CXX_FLAGS} - -DCMAKE_CXX_STANDARD=${CMAKE_CXX_STANDARD} - ) - if(CMAKE_TOOLCHAIN_FILE) - set(YAMLCPP_CMAKE_ARGS - ${YAMLCPP_CMAKE_ARGS} -DCMAKE_TOOLCHAIN_FILE=${CMAKE_TOOLCHAIN_FILE}) - endif() - - if(NOT BUILD_SHARED_LIBS) - #TODO: Find a way to merge in the static libs when built with internal yamlcpp - message(WARNING - "Building STATIC libOpenColorIO using the in-built YamlCpp. " - "YampCpp symbols are NOT included in the output binary!" - ) - endif() - - set(YAMLCPP_GIT_TAG "yaml-cpp-${YAMLCPP_VERSION}") - - # Hack to let imported target be built from ExternalProject_Add - file(MAKE_DIRECTORY ${YAMLCPP_INCLUDE_DIR}) - - ExternalProject_Add(yamlcpp_install - GIT_REPOSITORY "https://github.com/jbeder/yaml-cpp.git" - GIT_TAG ${YAMLCPP_GIT_TAG} - GIT_CONFIG advice.detachedHead=false - GIT_SHALLOW TRUE - PREFIX "${_EXT_BUILD_ROOT}/yaml-cpp" - BUILD_BYPRODUCTS ${YAMLCPP_LIBRARY} - CMAKE_ARGS ${YAMLCPP_CMAKE_ARGS} - EXCLUDE_FROM_ALL TRUE - ) - - add_dependencies(yamlcpp::yamlcpp yamlcpp_install) - message(STATUS - "Installing YamlCpp: ${YAMLCPP_LIBRARY} (version ${YAMLCPP_VERSION})" - ) - endif() -endif() - -############################################################################### -### Configure target ### - -if(_YAMLCPP_TARGET_CREATE) - set_target_properties(yamlcpp::yamlcpp PROPERTIES - IMPORTED_LOCATION ${YAMLCPP_LIBRARY} - INTERFACE_INCLUDE_DIRECTORIES ${YAMLCPP_INCLUDE_DIR} - ) - - mark_as_advanced(YAMLCPP_INCLUDE_DIR YAMLCPP_LIBRARY YAMLCPP_VERSION) -endif() diff --git a/share/cmake/modules/Findexpat.cmake b/share/cmake/modules/Findexpat.cmake new file mode 100644 index 0000000000..9f9a2f3254 --- /dev/null +++ b/share/cmake/modules/Findexpat.cmake @@ -0,0 +1,218 @@ +# SPDX-License-Identifier: BSD-3-Clause +# Copyright Contributors to the OpenColorIO Project. +# +# Locate or install expat +# +# Variables defined by this module: +# expat_FOUND - If FALSE, do not try to link to expat +# expat_LIBRARY - expat library to link to +# expat_INCLUDE_DIR - Where to find expat.h +# expat_VERSION - The version of the library +# +# Targets defined by this module: +# expat::expat - IMPORTED target, if found +# +# By default, the dynamic libraries of expat will be found. To find the static +# ones instead, you must set the expat_STATIC_LIBRARY variable to TRUE +# before calling find_package(expat ...). +# +# If expat is not installed in a standard path, you can use the expat_ROOT +# variable to tell CMake where to find it. If it is not found and +# OCIO_INSTALL_EXT_PACKAGES is set to MISSING or ALL, expat will be downloaded, +# built, and statically-linked into libOpenColorIO at build time. +# + +############################################################################### +### Try to find package ### + +if(NOT OCIO_INSTALL_EXT_PACKAGES STREQUAL ALL) + set(_expat_REQUIRED_VARS expat_LIBRARY) + + if(NOT DEFINED expat_ROOT) + # Search for expat-config.cmake + find_package(expat ${expat_FIND_VERSION} CONFIG QUIET) + endif() + + if(expat_FOUND) + get_target_property(expat_LIBRARY expat::expat LOCATION) + else() + list(APPEND _expat_REQUIRED_VARS expat_INCLUDE_DIR) + + # Search for expat.pc + find_package(PkgConfig QUIET) + pkg_check_modules(PC_expat QUIET "expat>=${expat_FIND_VERSION}") + + # Find include directory + find_path(expat_INCLUDE_DIR + NAMES + expat.h + HINTS + ${expat_ROOT} + ${PC_expat_INCLUDE_DIRS} + PATH_SUFFIXES + include + expat/include + ) + + # Lib names to search for + set(_expat_LIB_NAMES expat libexpat) + if(WIN32 AND BUILD_TYPE_DEBUG) + # Prefer Debug lib names (Windows only) + list(INSERT _expat_LIB_NAMES 0 expatd) + endif() + + if(expat_STATIC_LIBRARY) + # Prefer static lib names + set(_expat_STATIC_LIB_NAMES + "${CMAKE_STATIC_LIBRARY_PREFIX}expat${CMAKE_STATIC_LIBRARY_SUFFIX}") + if(WIN32 AND BUILD_TYPE_DEBUG) + # Prefer static Debug lib names (Windows only) + list(INSERT _expat_STATIC_LIB_NAMES 0 + "${CMAKE_STATIC_LIBRARY_PREFIX}expatd${CMAKE_STATIC_LIBRARY_SUFFIX}") + endif() + endif() + + # Find library + find_library(expat_LIBRARY + NAMES + ${_expat_STATIC_LIB_NAMES} + ${_expat_LIB_NAMES} + HINTS + ${expat_ROOT} + ${PC_expat_LIBRARY_DIRS} + PATH_SUFFIXES + lib64 lib + ) + + # Get version from header or pkg-config + if(expat_INCLUDE_DIR AND EXISTS "${expat_INCLUDE_DIR}/expat.h") + file(STRINGS "${expat_INCLUDE_DIR}/expat.h" _expat_VER_SEARCH + REGEX "^[ \t]*#define[ \t]+XML_(MAJOR|MINOR|MICRO)_VERSION[ \t]+[0-9]+.*$") + if(_expat_VER_SEARCH) + foreach(_VER_PART MAJOR MINOR MICRO) + string(REGEX REPLACE ".*#define[ \t]+XML_${_VER_PART}_VERSION[ \t]+([0-9]+).*" + "\\1" expat_VERSION_${_VER_PART} "${_expat_VER_SEARCH}") + if(NOT expat_VERSION_${_VER_PART}) + set(expat_VERSION_${_VER_PART} 0) + endif() + endforeach() + set(expat_VERSION + "${expat_VERSION_MAJOR}.${expat_VERSION_MINOR}.${expat_VERSION_MICRO}") + endif() + elseif(PC_expat_FOUND) + set(expat_VERSION "${PC_expat_VERSION}") + endif() + endif() + + # Override REQUIRED if package can be installed + if(OCIO_INSTALL_EXT_PACKAGES STREQUAL MISSING) + set(expat_FIND_REQUIRED FALSE) + endif() + + include(FindPackageHandleStandardArgs) + find_package_handle_standard_args(expat + REQUIRED_VARS + ${_expat_REQUIRED_VARS} + VERSION_VAR + expat_VERSION + ) +endif() + +############################################################################### +### Create target + +if(NOT TARGET expat::expat) + add_library(expat::expat UNKNOWN IMPORTED GLOBAL) + set(_expat_TARGET_CREATE TRUE) +endif() + +############################################################################### +### Install package from source ### + +if(NOT expat_FOUND) + include(ExternalProject) + include(GNUInstallDirs) + + set(_EXT_DIST_ROOT "${CMAKE_BINARY_DIR}/ext/dist") + set(_EXT_BUILD_ROOT "${CMAKE_BINARY_DIR}/ext/build") + + # Set find_package standard args + set(expat_FOUND TRUE) + set(expat_VERSION ${expat_FIND_VERSION}) + set(expat_INCLUDE_DIR "${_EXT_DIST_ROOT}/${CMAKE_INSTALL_INCLUDEDIR}") + + # Set the expected library name + if(WIN32) + if(BUILD_TYPE_DEBUG) + set(_expat_LIB_SUFFIX "d") + endif() + # Static Linking, Multi-threaded Dll naming (>=2.2.8): + # https://github.com/libexpat/libexpat/blob/R_2_2_8/expat/win32/README.txt + set(_expat_LIB_SUFFIX "${_expat_LIB_SUFFIX}MD") + endif() + set(expat_LIBRARY + "${_EXT_DIST_ROOT}/${CMAKE_INSTALL_LIBDIR}/${CMAKE_STATIC_LIBRARY_PREFIX}expat${_expat_LIB_SUFFIX}${CMAKE_STATIC_LIBRARY_SUFFIX}") + + if(_expat_TARGET_CREATE) + if(UNIX) + set(EXPAT_C_FLAGS "${EXPAT_C_FLAGS} -fPIC") + set(EXPAT_CXX_FLAGS "${EXPAT_CXX_FLAGS} -fPIC") + endif() + + if(MSVC) + set(EXPAT_C_FLAGS "${EXPAT_C_FLAGS} /EHsc") + set(EXPAT_CXX_FLAGS "${EXPAT_CXX_FLAGS} /EHsc") + endif() + + string(STRIP "${EXPAT_C_FLAGS}" EXPAT_C_FLAGS) + string(STRIP "${EXPAT_CXX_FLAGS}" EXPAT_CXX_FLAGS) + + set(EXPAT_CMAKE_ARGS + ${EXPAT_CMAKE_ARGS} + -DCMAKE_INSTALL_PREFIX=${_EXT_DIST_ROOT} + -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE} + -DEXPAT_BUILD_TOOLS=OFF + -DEXPAT_BUILD_EXAMPLES=OFF + -DEXPAT_BUILD_TESTS=OFF + -DEXPAT_SHARED_LIBS=OFF + -DEXPAT_BUILD_DOCS=OFF + -DCMAKE_C_FLAGS=${EXPAT_C_FLAGS} + -DCMAKE_CXX_FLAGS=${EXPAT_CXX_FLAGS} + -DCMAKE_CXX_STANDARD=${CMAKE_CXX_STANDARD} + ) + if(CMAKE_TOOLCHAIN_FILE) + set(EXPAT_CMAKE_ARGS + ${EXPAT_CMAKE_ARGS} -DCMAKE_TOOLCHAIN_FILE=${CMAKE_TOOLCHAIN_FILE}) + endif() + + # Hack to let imported target be built from ExternalProject_Add + file(MAKE_DIRECTORY ${expat_INCLUDE_DIR}) + + ExternalProject_Add(expat_install + GIT_REPOSITORY "https://github.com/libexpat/libexpat.git" + GIT_TAG "R_${expat_FIND_VERSION_MAJOR}_${expat_FIND_VERSION_MINOR}_${expat_FIND_VERSION_PATCH}" + GIT_CONFIG advice.detachedHead=false + GIT_SHALLOW TRUE + PREFIX "${_EXT_BUILD_ROOT}/libexpat" + BUILD_BYPRODUCTS ${expat_LIBRARY} + SOURCE_SUBDIR expat + CMAKE_ARGS ${EXPAT_CMAKE_ARGS} + EXCLUDE_FROM_ALL TRUE + ) + + add_dependencies(expat::expat expat_install) + message(STATUS "Installing expat: ${expat_LIBRARY} (version \"${expat_VERSION}\")") + endif() +endif() + +############################################################################### +### Configure target ### + +if(_expat_TARGET_CREATE) + set_target_properties(expat::expat PROPERTIES + IMPORTED_LOCATION ${expat_LIBRARY} + INTERFACE_INCLUDE_DIRECTORIES ${expat_INCLUDE_DIR} + ) + + mark_as_advanced(expat_INCLUDE_DIR expat_LIBRARY expat_VERSION) +endif() diff --git a/share/cmake/modules/FindLCMS2.cmake b/share/cmake/modules/Findlcms2.cmake similarity index 51% rename from share/cmake/modules/FindLCMS2.cmake rename to share/cmake/modules/Findlcms2.cmake index 60501bfd50..8bc9832412 100644 --- a/share/cmake/modules/FindLCMS2.cmake +++ b/share/cmake/modules/Findlcms2.cmake @@ -4,27 +4,27 @@ # Locate or install lcms2 # # Variables defined by this module: -# LCMS2_FOUND - If FALSE, do not try to link to lcms -# LCMS2_LIBRARY - Where to find lcms -# LCMS2_INCLUDE_DIR - Where to find lcms2.h -# LCMS2_VERSION - The version of the library +# lcms2_FOUND - If FALSE, do not try to link to lcms +# lcms2_LIBRARY - Where to find lcms +# lcms2_INCLUDE_DIR - Where to find lcms2.h +# lcms2_VERSION - The version of the library # # Targets defined by this module: # lcms2::lcms2 - IMPORTED target, if found # -# By default, the dynamic libraries of LCMS2 will be found. To find the static -# ones instead, you must set the LCMS2_STATIC_LIBRARY variable to TRUE -# before calling find_package(LCMS2 ...). +# By default, the dynamic libraries of lcms2 will be found. To find the static +# ones instead, you must set the lcms2_STATIC_LIBRARY variable to TRUE +# before calling find_package(lcms2 ...). # -# If LCMS2 is not installed in a standard path, you can use the LCMS2_DIRS +# If lcms2 is not installed in a standard path, you can use the lcms2_ROOT # variable to tell CMake where to find it. If it is not found and -# OCIO_INSTALL_EXT_PACKAGES is set to MISSING or ALL, LCMS2 will be +# OCIO_INSTALL_EXT_PACKAGES is set to MISSING or ALL, lcms2 will be # downloaded, built, and statically-linked into libOpenColorIO at build time. # if(NOT TARGET lcms2::lcms2) add_library(lcms2::lcms2 UNKNOWN IMPORTED GLOBAL) - set(_LCMS2_TARGET_CREATE TRUE) + set(_lcms2_TARGET_CREATE TRUE) endif() ############################################################################### @@ -33,27 +33,15 @@ endif() if(NOT OCIO_INSTALL_EXT_PACKAGES STREQUAL ALL) # Try to use pkg-config to get the version find_package(PkgConfig QUIET) - pkg_check_modules(PC_LCMS2 QUIET lcms2) - - set(_LCMS2_SEARCH_DIRS - ${LCMS2_DIRS} - ~/Library/Frameworks - /Library/Frameworks - /usr/local - /usr - /sw # Fink - /opt/local # DarwinPorts - /opt/csw # Blastwave - /opt - ) + pkg_check_modules(PC_lcms2 QUIET "lcms2>=${lcms2_FIND_VERSION}") # Find include directory - find_path(LCMS2_INCLUDE_DIR + find_path(lcms2_INCLUDE_DIR NAMES lcms2.h HINTS - ${_LCMS2_SEARCH_DIRS} - ${PC_LCMS2_INCLUDE_DIRS} + ${lcms2_ROOT} + ${PC_lcms2_INCLUDE_DIRS} PATH_SUFFIXES include lcms2/include @@ -61,118 +49,118 @@ if(NOT OCIO_INSTALL_EXT_PACKAGES STREQUAL ALL) ) # Attempt to find static library first if this is set - if(LCMS2_STATIC_LIBRARY) - set(_LCMS2_STATIC "${CMAKE_STATIC_LIBRARY_PREFIX}lcms2${CMAKE_STATIC_LIBRARY_SUFFIX}") + if(lcms2_STATIC_LIBRARY) + set(_lcms2_STATIC "${CMAKE_STATIC_LIBRARY_PREFIX}lcms2${CMAKE_STATIC_LIBRARY_SUFFIX}") endif() # Find library - find_library(LCMS2_LIBRARY + find_library(lcms2_LIBRARY NAMES - ${_LCMS2_STATIC} lcms2 liblcms2 + ${_lcms2_STATIC} lcms2 liblcms2 HINTS - ${_LCMS2_SEARCH_DIRS} - ${PC_LCMS2_LIBRARY_DIRS} + ${_lcms2_SEARCH_DIRS} + ${PC_lcms2_LIBRARY_DIRS} PATH_SUFFIXES lib64 lib ) # Get version from config or header file - if(LCMS2_INCLUDE_DIR AND EXISTS "${LCMS2_INCLUDE_DIR}/lcms2.h") - file(STRINGS "${LCMS2_INCLUDE_DIR}/lcms2.h" _LCMS2_VER_SEARCH + if(lcms2_INCLUDE_DIR AND EXISTS "${lcms2_INCLUDE_DIR}/lcms2.h") + file(STRINGS "${lcms2_INCLUDE_DIR}/lcms2.h" _lcms2_VER_SEARCH REGEX "^[ \t]*//[ \t]+Version[ \t]+[.0-9]+.*$") - if(_LCMS2_VER_SEARCH) + if(_lcms2_VER_SEARCH) string(REGEX REPLACE ".*//[ \t]+Version[ \t]+([.0-9]+).*" - "\\1" LCMS2_VERSION "${_LCMS2_VER_SEARCH}") + "\\1" lcms2_VERSION "${_lcms2_VER_SEARCH}") endif() - elseif(PC_LCMS2_FOUND) - set(LCMS2_VERSION "${PC_LCMS2_VERSION}") + elseif(PC_lcms2_FOUND) + set(lcms2_VERSION "${PC_lcms2_VERSION}") endif() # Override REQUIRED if package can be installed if(OCIO_INSTALL_EXT_PACKAGES STREQUAL MISSING) - set(LCMS2_FIND_REQUIRED FALSE) + set(lcms2_FIND_REQUIRED FALSE) endif() include(FindPackageHandleStandardArgs) - find_package_handle_standard_args(LCMS2 + find_package_handle_standard_args(lcms2 REQUIRED_VARS - LCMS2_INCLUDE_DIR - LCMS2_LIBRARY + lcms2_INCLUDE_DIR + lcms2_LIBRARY VERSION_VAR - LCMS2_VERSION + lcms2_VERSION ) endif() ############################################################################### ### Install package from source ### -if(NOT LCMS2_FOUND) +if(NOT lcms2_FOUND) include(ExternalProject) set(_EXT_DIST_ROOT "${CMAKE_BINARY_DIR}/ext/dist") set(_EXT_BUILD_ROOT "${CMAKE_BINARY_DIR}/ext/build") # Set find_package standard args - set(LCMS2_FOUND TRUE) - set(LCMS2_VERSION ${LCMS2_FIND_VERSION}) - set(LCMS2_INCLUDE_DIR "${_EXT_DIST_ROOT}/include/lcms2") - set(LCMS2_LIBRARY + set(lcms2_FOUND TRUE) + set(lcms2_VERSION ${lcms2_FIND_VERSION}) + set(lcms2_INCLUDE_DIR "${_EXT_DIST_ROOT}/include/lcms2") + set(lcms2_LIBRARY "${_EXT_DIST_ROOT}/lib/${CMAKE_STATIC_LIBRARY_PREFIX}lcms2${CMAKE_STATIC_LIBRARY_SUFFIX}") - if(_LCMS2_TARGET_CREATE) + if(_lcms2_TARGET_CREATE) if(UNIX) - set(LCMS2_C_FLAGS "${LCMS2_C_FLAGS} -fPIC") + set(lcms2_C_FLAGS "${lcms2_C_FLAGS} -fPIC") endif() if("${CMAKE_CXX_COMPILER_ID}" MATCHES "GNU") - set(LCMS2_C_FLAGS "${LCMS2_C_FLAGS} -Wno-aggressive-loop-optimizations") + set(lcms2_C_FLAGS "${lcms2_C_FLAGS} -Wno-aggressive-loop-optimizations") endif() - string(STRIP "${LCMS2_C_FLAGS}" LCMS2_C_FLAGS) + string(STRIP "${lcms2_C_FLAGS}" lcms2_C_FLAGS) - set(LCMS2_CMAKE_ARGS - ${LCMS2_CMAKE_ARGS} + set(lcms2_CMAKE_ARGS + ${lcms2_CMAKE_ARGS} -DCMAKE_INSTALL_PREFIX=${_EXT_DIST_ROOT} -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE} - -DBUILD_SHARED_LIBS:BOOL=OFF - -DCMAKE_C_FLAGS=${LCMS2_C_FLAGS} + -DBUILD_SHARED_LIBS=OFF + -DCMAKE_C_FLAGS=${lcms2_C_FLAGS} ) if(CMAKE_TOOLCHAIN_FILE) - set(LCMS2_CMAKE_ARGS - ${LCMS2_CMAKE_ARGS} -DCMAKE_TOOLCHAIN_FILE=${CMAKE_TOOLCHAIN_FILE}) + set(lcms2_CMAKE_ARGS + ${lcms2_CMAKE_ARGS} -DCMAKE_TOOLCHAIN_FILE=${CMAKE_TOOLCHAIN_FILE}) endif() # Hack to let imported target be built from ExternalProject_Add - file(MAKE_DIRECTORY ${LCMS2_INCLUDE_DIR}) + file(MAKE_DIRECTORY ${lcms2_INCLUDE_DIR}) ExternalProject_Add(lcms2_install GIT_REPOSITORY "https://github.com/mm2/Little-CMS.git" - GIT_TAG "lcms${LCMS2_VERSION}" + GIT_TAG "lcms${lcms2_VERSION}" GIT_CONFIG advice.detachedHead=false GIT_SHALLOW TRUE PREFIX "${_EXT_BUILD_ROOT}/Little-CMS" - BUILD_BYPRODUCTS ${LCMS2_LIBRARY} + BUILD_BYPRODUCTS ${lcms2_LIBRARY} PATCH_COMMAND ${CMAKE_COMMAND} -E copy - "${CMAKE_SOURCE_DIR}/share/cmake/projects/BuildLCMS2.cmake" + "${CMAKE_SOURCE_DIR}/share/cmake/projects/Buildlcms2.cmake" "CMakeLists.txt" - CMAKE_ARGS ${LCMS2_CMAKE_ARGS} + CMAKE_ARGS ${lcms2_CMAKE_ARGS} EXCLUDE_FROM_ALL TRUE ) add_dependencies(lcms2::lcms2 lcms2_install) - message(STATUS "Installing LCMS2: ${LCMS2_LIBRARY} (version ${LCMS2_VERSION})") + message(STATUS "Installing lcms2: ${lcms2_LIBRARY} (version \"${lcms2_VERSION}\")") endif() endif() ############################################################################### ### Configure target ### -if(_LCMS2_TARGET_CREATE) +if(_lcms2_TARGET_CREATE) set_target_properties(lcms2::lcms2 PROPERTIES - IMPORTED_LOCATION ${LCMS2_LIBRARY} - INTERFACE_INCLUDE_DIRECTORIES ${LCMS2_INCLUDE_DIR} + IMPORTED_LOCATION ${lcms2_LIBRARY} + INTERFACE_INCLUDE_DIRECTORIES ${lcms2_INCLUDE_DIR} ) - mark_as_advanced(LCMS2_INCLUDE_DIR LCMS2_LIBRARY LCMS2_VERSION) + mark_as_advanced(lcms2_INCLUDE_DIR lcms2_LIBRARY lcms2_VERSION) endif() diff --git a/share/cmake/modules/Findpybind11.cmake b/share/cmake/modules/Findpybind11.cmake index 0467b71454..2f53c2aa2e 100644 --- a/share/cmake/modules/Findpybind11.cmake +++ b/share/cmake/modules/Findpybind11.cmake @@ -9,7 +9,7 @@ # pybind11::module - IMPORTED target, if found # # If pybind11 is not installed in a standard path, you can use the -# pybind11_DIRS variable to tell CMake where to find it. If it is not found +# pybind11_ROOT variable to tell CMake where to find it. If it is not found # and OCIO_INSTALL_EXT_PACKAGES is set to MISSING or ALL, pybind11 will be # downloaded at build time. # @@ -18,18 +18,21 @@ ### Try to find package ### if(NOT OCIO_INSTALL_EXT_PACKAGES STREQUAL ALL) - if(DEFINED pybind11_DIRS) - # Try user defined search path first. Ignore all default cmake and - # system paths, and fall back on a system CMake config. + if(NOT DEFINED pybind11_ROOT) + # Search for pybind11Config.cmake + find_package(pybind11 ${pybind11_FIND_VERSION} CONFIG QUIET) + endif() + + if(NOT pybind11_FOUND) + # Find include directory find_path(pybind11_INCLUDE_DIR NAMES pybind11/pybind11.h HINTS - ${pybind11_DIRS} + ${pybind11_ROOT} PATH_SUFFIXES include pybind11/include - NO_DEFAULT_PATH ) # Version information can be extracted from this header @@ -48,67 +51,56 @@ if(NOT OCIO_INSTALL_EXT_PACKAGES STREQUAL ALL) "\\1" _pybind11_PATCH "${_pybind11_VER_SEARCH}") set(pybind11_VERSION "${_pybind11_MAJOR}.${_pybind11_MINOR}.${_pybind11_PATCH}") - message(STATUS - "Using user defined search path for pybind11 " - "(found version \"${pybind11_VERSION}\")" - ) endif() endif() endif() - if(NOT DEFINED pybind11_VERSION) - # Search for a CMake config, which should have been installed with - # pybind11, and will provide version information. - find_package(pybind11 ${pybind11_FIND_VERSION} CONFIG) - - if(NOT pybind11_FOUND) - # No CMake config found. Check if pybind11 was installed as a - # Python package (i.e. with "pip install pybind11"). This requires - # a Python interpreter. - find_package(PythonInterp 2.7 QUIET) + if(NOT pybind11_VERSION) + # Check if pybind11 was installed as a Python package (i.e. with + # "pip install pybind11"). This requires a Python interpreter. + find_package(PythonInterp 2.7 QUIET) + + if(PYTHONINTERP_FOUND) + execute_process( + COMMAND + "${PYTHON_EXECUTABLE}" -c + "print(__import__('pybind11').__version__)" + RESULTS_VARIABLE + _pybind11_VER_RESULTS + OUTPUT_VARIABLE + _pybind11_VER_OUTPUT + ERROR_QUIET + ) + if(_pybind11_VER_OUTPUT) + # Strip \n from python output + string(STRIP ${_pybind11_VER_OUTPUT} _pybind11_VER_OUTPUT) + endif() - if(PYTHONINTERP_FOUND) + if(_pybind11_VER_RESULTS EQUAL 0 AND "${_pybind11_VER_OUTPUT}" MATCHES "[.0-9]+") execute_process( COMMAND "${PYTHON_EXECUTABLE}" -c - "print(__import__('pybind11').__version__)" + "import os;\ + import pybind11;\ + print(os.path.join(os.path.dirname(pybind11.__file__), 'include'))" RESULTS_VARIABLE - _pybind11_VER_RESULTS + _pybind11_DIR_RESULTS OUTPUT_VARIABLE - _pybind11_VER_OUTPUT + _pybind11_DIR_OUTPUT ERROR_QUIET ) - if(_pybind11_VER_OUTPUT) + if(_pybind11_DIR_OUTPUT) # Strip \n from python output - string(STRIP ${_pybind11_VER_OUTPUT} _pybind11_VER_OUTPUT) + string(STRIP ${_pybind11_DIR_OUTPUT} _pybind11_DIR_OUTPUT) endif() - if(_pybind11_VER_RESULTS EQUAL 0 AND "${_pybind11_VER_OUTPUT}" MATCHES "[.0-9]+") - execute_process( - COMMAND - "${PYTHON_EXECUTABLE}" -c - "import os;\ - import pybind11;\ - print(os.path.join(os.path.dirname(pybind11.__file__), 'include'))" - RESULTS_VARIABLE - _pybind11_DIR_RESULTS - OUTPUT_VARIABLE - _pybind11_DIR_OUTPUT - ERROR_QUIET + if(_pybind11_DIR_RESULTS EQUAL 0 AND EXISTS "${_pybind11_DIR_OUTPUT}") + set(pybind11_VERSION ${_pybind11_VER_OUTPUT}) + set(pybind11_INCLUDE_DIR ${_pybind11_DIR_OUTPUT}) + message(STATUS + "Using pybind11 python package (version \"${pybind11_VERSION}\", " + "found in python \"${PYTHON_VERSION_STRING}\")" ) - if(_pybind11_DIR_OUTPUT) - # Strip \n from python output - string(STRIP ${_pybind11_DIR_OUTPUT} _pybind11_DIR_OUTPUT) - endif() - - if(_pybind11_DIR_RESULTS EQUAL 0 AND EXISTS "${_pybind11_DIR_OUTPUT}") - set(pybind11_VERSION ${_pybind11_VER_OUTPUT}) - set(pybind11_INCLUDE_DIR ${_pybind11_DIR_OUTPUT}) - message(STATUS - "Using pybind11 python package (version \"${pybind11_VERSION}\", " - "found in python \"${PYTHON_VERSION_STRING}\")" - ) - endif() endif() endif() endif() @@ -141,6 +133,7 @@ endif() if(NOT pybind11_FOUND) include(ExternalProject) + include(GNUInstallDirs) set(_EXT_DIST_ROOT "${CMAKE_BINARY_DIR}/ext/dist") set(_EXT_BUILD_ROOT "${CMAKE_BINARY_DIR}/ext/build") @@ -148,7 +141,7 @@ if(NOT pybind11_FOUND) # Set find_package standard args set(pybind11_FOUND TRUE) set(pybind11_VERSION ${pybind11_FIND_VERSION}) - set(pybind11_INCLUDE_DIR "${_EXT_DIST_ROOT}/include") + set(pybind11_INCLUDE_DIR "${_EXT_DIST_ROOT}/${CMAKE_INSTALL_INCLUDEDIR}") if(_pybind11_TARGET_CREATE) # Hack to let imported target be built from ExternalProject_Add @@ -157,8 +150,8 @@ if(NOT pybind11_FOUND) set(pybind11_CMAKE_ARGS ${pybind11_CMAKE_ARGS} -DCMAKE_INSTALL_PREFIX=${_EXT_DIST_ROOT} - -DPYBIND11_INSTALL:BOOL=ON - -DPYBIND11_TEST:BOOL=OFF + -DPYBIND11_INSTALL=ON + -DPYBIND11_TEST=OFF ) ExternalProject_Add(pybind11_install @@ -172,7 +165,7 @@ if(NOT pybind11_FOUND) ) add_dependencies(pybind11::module pybind11_install) - message(STATUS "Installing pybind11: ${pybind11_INCLUDE_DIR} (version ${pybind11_VERSION})") + message(STATUS "Installing pybind11: ${pybind11_INCLUDE_DIR} (version \"${pybind11_VERSION}\")") endif() endif() diff --git a/share/cmake/modules/FindPystring.cmake b/share/cmake/modules/Findpystring.cmake similarity index 57% rename from share/cmake/modules/FindPystring.cmake rename to share/cmake/modules/Findpystring.cmake index 01bef2c074..a519f47d5a 100644 --- a/share/cmake/modules/FindPystring.cmake +++ b/share/cmake/modules/Findpystring.cmake @@ -4,166 +4,154 @@ # Locate or install pystring # # Variables defined by this module: -# PYSTRING_FOUND - If FALSE, do not try to link to pystring -# PYSTRING_LIBRARY - Where to find pystring -# PYSTRING_INCLUDE_DIR - Where to find pystring.h +# pystring_FOUND - If FALSE, do not try to link to pystring +# pystring_LIBRARY - Where to find pystring +# pystring_INCLUDE_DIR - Where to find pystring.h # # Targets defined by this module: # pystring::pystring - IMPORTED target, if found # # By default, the dynamic libraries of pystring will be found. To find the -# static ones instead, you must set the PYSTRING_STATIC_LIBRARY variable to -# TRUE before calling find_package(Pystring ...). +# static ones instead, you must set the pystring_STATIC_LIBRARY variable to +# TRUE before calling find_package(pystring ...). # # If pystring is not installed in a standard path, you can use the -# PYSTRING_DIRS variable to tell CMake where to find it. If it is not found +# pystring_ROOT variable to tell CMake where to find it. If it is not found # and OCIO_INSTALL_EXT_PACKAGES is set to MISSING or ALL, pystring will be # downloaded, built, and statically-linked into libOpenColorIO at build time. # if(NOT TARGET pystring::pystring) add_library(pystring::pystring UNKNOWN IMPORTED GLOBAL) - set(_PYSTRING_TARGET_CREATE TRUE) + set(_pystring_TARGET_CREATE TRUE) endif() ############################################################################### ### Try to find package ### if(NOT OCIO_INSTALL_EXT_PACKAGES STREQUAL ALL) - set(_PYSTRING_SEARCH_DIRS - ${PYSTRING_DIRS} - ~/Library/Frameworks - /Library/Frameworks - /usr/local - /usr - /sw # Fink - /opt/local # DarwinPorts - /opt/csw # Blastwave - /opt - ) - # Find include directory - find_path(PYSTRING_INCLUDE_DIR + find_path(pystring_INCLUDE_DIR NAMES pystring/pystring.h HINTS - ${_PYSTRING_SEARCH_DIRS} + ${pystring_ROOT} PATH_SUFFIXES include pystring/include ) # Attempt to find static library first if this is set - if(PYSTRING_STATIC_LIBRARY) - set(_PYSTRING_STATIC + if(pystring_STATIC_LIBRARY) + set(_pystring_STATIC "${CMAKE_STATIC_LIBRARY_PREFIX}pystring${CMAKE_STATIC_LIBRARY_SUFFIX}") endif() # Find library - find_library(PYSTRING_LIBRARY + find_library(pystring_LIBRARY NAMES - ${_PYSTRING_STATIC} pystring + ${_pystring_STATIC} pystring HINTS - ${_PYSTRING_SEARCH_DIRS} + ${_pystring_SEARCH_DIRS} PATH_SUFFIXES lib64 lib ) # Override REQUIRED if package can be installed if(OCIO_INSTALL_EXT_PACKAGES STREQUAL MISSING) - set(Pystring_FIND_REQUIRED FALSE) + set(pystring_FIND_REQUIRED FALSE) endif() include(FindPackageHandleStandardArgs) - find_package_handle_standard_args(Pystring + find_package_handle_standard_args(pystring REQUIRED_VARS - PYSTRING_INCLUDE_DIR - PYSTRING_LIBRARY + pystring_INCLUDE_DIR + pystring_LIBRARY ) - set(PYSTRING_FOUND ${Pystring_FOUND}) + set(pystring_FOUND ${pystring_FOUND}) endif() ############################################################################### ### Install package from source ### -if(NOT PYSTRING_FOUND) +if(NOT pystring_FOUND) include(ExternalProject) set(_EXT_DIST_ROOT "${CMAKE_BINARY_DIR}/ext/dist") set(_EXT_BUILD_ROOT "${CMAKE_BINARY_DIR}/ext/build") # Set find_package standard args - set(PYSTRING_FOUND TRUE) - set(PYSTRING_VERSION ${Pystring_FIND_VERSION}) - set(PYSTRING_INCLUDE_DIR "${_EXT_DIST_ROOT}/include") - set(PYSTRING_LIBRARY + set(pystring_FOUND TRUE) + set(pystring_VERSION ${pystring_FIND_VERSION}) + set(pystring_INCLUDE_DIR "${_EXT_DIST_ROOT}/include") + set(pystring_LIBRARY "${_EXT_DIST_ROOT}/lib/${CMAKE_STATIC_LIBRARY_PREFIX}pystring${CMAKE_STATIC_LIBRARY_SUFFIX}") - if(_PYSTRING_TARGET_CREATE) + if(_pystring_TARGET_CREATE) if(UNIX) - set(PYSTRING_CXX_FLAGS "${PYSTRING_CXX_FLAGS} -fvisibility=hidden -fPIC") + set(pystring_CXX_FLAGS "${pystring_CXX_FLAGS} -fvisibility=hidden -fPIC") if(OCIO_INLINES_HIDDEN) - set(PYSTRING_CXX_FLAGS "${PYSTRING_CXX_FLAGS} -fvisibility-inlines-hidden") + set(pystring_CXX_FLAGS "${pystring_CXX_FLAGS} -fvisibility-inlines-hidden") endif() endif() if(MSVC) - set(PYSTRING_CXX_FLAGS "${PYSTRING_CXX_FLAGS} /EHsc") + set(pystring_CXX_FLAGS "${pystring_CXX_FLAGS} /EHsc") endif() - string(STRIP "${PYSTRING_CXX_FLAGS}" PYSTRING_CXX_FLAGS) + string(STRIP "${pystring_CXX_FLAGS}" pystring_CXX_FLAGS) - set(PYSTRING_CMAKE_ARGS - ${PYSTRING_CMAKE_ARGS} + set(pystring_CMAKE_ARGS + ${pystring_CMAKE_ARGS} -DCMAKE_INSTALL_PREFIX=${_EXT_DIST_ROOT} -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE} - -DCMAKE_CXX_FLAGS=${PYSTRING_CXX_FLAGS} + -DCMAKE_CXX_FLAGS=${pystring_CXX_FLAGS} -DCMAKE_CXX_STANDARD=${CMAKE_CXX_STANDARD} ) if(CMAKE_TOOLCHAIN_FILE) - set(PYSTRING_CMAKE_ARGS - ${PYSTRING_CMAKE_ARGS} -DCMAKE_TOOLCHAIN_FILE=${CMAKE_TOOLCHAIN_FILE}) + set(pystring_CMAKE_ARGS + ${pystring_CMAKE_ARGS} -DCMAKE_TOOLCHAIN_FILE=${CMAKE_TOOLCHAIN_FILE}) endif() if(NOT BUILD_SHARED_LIBS) #TODO: Find a way to merge in the static libs when built with internal pystring message(WARNING - "Building STATIC libOpenColorIO using the in-built Pystring. " - "Pystring symbols are NOT included in the output binary!" + "Building STATIC libOpenColorIO using the in-built pystring. " + "pystring symbols are NOT included in the output binary!" ) endif() # Hack to let imported target be built from ExternalProject_Add - file(MAKE_DIRECTORY ${PYSTRING_INCLUDE_DIR}) + file(MAKE_DIRECTORY ${pystring_INCLUDE_DIR}) ExternalProject_Add(pystring_install GIT_REPOSITORY "https://github.com/imageworks/pystring.git" - GIT_TAG "v${Pystring_FIND_VERSION}" + GIT_TAG "v${pystring_FIND_VERSION}" GIT_CONFIG advice.detachedHead=false GIT_SHALLOW TRUE PREFIX "${_EXT_BUILD_ROOT}/pystring" - BUILD_BYPRODUCTS ${PYSTRING_LIBRARY} + BUILD_BYPRODUCTS ${pystring_LIBRARY} PATCH_COMMAND ${CMAKE_COMMAND} -E copy - "${CMAKE_SOURCE_DIR}/share/cmake/projects/BuildPystring.cmake" + "${CMAKE_SOURCE_DIR}/share/cmake/projects/Buildpystring.cmake" "CMakeLists.txt" - CMAKE_ARGS ${PYSTRING_CMAKE_ARGS} + CMAKE_ARGS ${pystring_CMAKE_ARGS} EXCLUDE_FROM_ALL TRUE ) add_dependencies(pystring::pystring pystring_install) - message(STATUS "Installing Pystring: ${PYSTRING_LIBRARY} (version ${PYSTRING_VERSION})") + message(STATUS "Installing pystring: ${pystring_LIBRARY} (version \"${pystring_VERSION}\")") endif() endif() ############################################################################### ### Configure target ### -if(_PYSTRING_TARGET_CREATE) +if(_pystring_TARGET_CREATE) set_target_properties(pystring::pystring PROPERTIES - IMPORTED_LOCATION ${PYSTRING_LIBRARY} - INTERFACE_INCLUDE_DIRECTORIES ${PYSTRING_INCLUDE_DIR} + IMPORTED_LOCATION ${pystring_LIBRARY} + INTERFACE_INCLUDE_DIRECTORIES ${pystring_INCLUDE_DIR} ) - mark_as_advanced(PYSTRING_INCLUDE_DIR PYSTRING_LIBRARY PYSTRING_VERSION) + mark_as_advanced(pystring_INCLUDE_DIR pystring_LIBRARY pystring_VERSION) endif() diff --git a/share/cmake/modules/Findyaml-cpp.cmake b/share/cmake/modules/Findyaml-cpp.cmake new file mode 100644 index 0000000000..67aa488f11 --- /dev/null +++ b/share/cmake/modules/Findyaml-cpp.cmake @@ -0,0 +1,219 @@ +# SPDX-License-Identifier: BSD-3-Clause +# Copyright Contributors to the OpenColorIO Project. +# +# Locate or install yaml-cpp +# +# Variables defined by this module: +# yaml-cpp_FOUND - If FALSE, do not try to link to yamlcpp +# yaml-cpp_LIBRARY - yaml-cpp library to link to +# yaml-cpp_INCLUDE_DIR - Where to find yaml.h +# yaml-cpp_VERSION - The version of the library +# +# Targets defined by this module: +# yaml-cpp - IMPORTED target, if found +# +# By default, the dynamic libraries of yaml-cpp will be found. To find the +# static ones instead, you must set the yaml-cpp_STATIC_LIBRARY variable to +# TRUE before calling find_package(yaml-cpp ...). +# +# If yaml-cpp is not installed in a standard path, you can use the +# yaml-cpp_ROOT variable to tell CMake where to find it. If it is not found +# and OCIO_INSTALL_EXT_PACKAGES is set to MISSING or ALL, yaml-cpp will be +# downloaded, built, and statically-linked into libOpenColorIO at build time. +# + +############################################################################### +### Try to find package ### + +if(NOT OCIO_INSTALL_EXT_PACKAGES STREQUAL ALL) + if(NOT DEFINED yaml-cpp_ROOT) + # Search for yaml-cpp-config.cmake + find_package(yaml-cpp ${yaml-cpp_FIND_VERSION} CONFIG QUIET) + endif() + + if(yaml-cpp_FOUND) + set(yaml-cpp_LIBRARY "${YAML_CPP_LIBRARIES}") + set(yaml-cpp_INCLUDE_DIR "${YAML_CPP_INCLUDE_DIR}") + else() + # Search for yaml-cpp.pc + find_package(PkgConfig QUIET) + pkg_check_modules(PC_yaml-cpp QUIET "yaml-cpp>=${yaml-cpp_FIND_VERSION}") + + # Find include directory + find_path(yaml-cpp_INCLUDE_DIR + NAMES + yaml-cpp/yaml.h + HINTS + ${yaml-cpp_ROOT} + ${PC_yaml-cpp_INCLUDE_DIRS} + PATH_SUFFIXES + include + yaml-cpp/include + ) + + # Lib names to search for + set(_yaml-cpp_LIB_NAMES yaml-cpp) + if(WIN32 AND BUILD_TYPE_DEBUG) + # Prefer Debug lib names (Windows only) + list(INSERT _yaml-cpp_LIB_NAMES 0 yaml-cppd) + endif() + + if(yaml-cpp_STATIC_LIBRARY) + # Prefer static lib names + if(WIN32) + set(_yaml-cpp_LIB_SUFFIX "md") + endif() + set(_yaml-cpp_STATIC_LIB_NAMES + "libyaml-cpp${_yaml-cpp_LIB_SUFFIX}${CMAKE_STATIC_LIBRARY_SUFFIX}") + if(WIN32 AND BUILD_TYPE_DEBUG) + # Prefer static Debug lib names (Windows only) + list(INSERT _yaml-cpp_STATIC_LIB_NAMES 0 + "libyaml-cpp${_yaml-cpp_LIB_SUFFIX}d${CMAKE_STATIC_LIBRARY_SUFFIX}") + endif() + endif() + + # Find library + find_library(yaml-cpp_LIBRARY + NAMES + ${_yaml-cpp_STATIC_LIB_NAMES} + ${_yaml-cpp_LIB_NAMES} + HINTS + ${_yaml-cpp_ROOT} + ${PC_yaml-cpp_LIBRARY_DIRS} + PATH_SUFFIXES + lib64 lib + ) + + # Get version from pkg-config if it was found. + if(PC_yaml-cpp_FOUND) + set(yaml-cpp_VERSION "${PC_yaml-cpp_VERSION}") + endif() + endif() + + # Override REQUIRED if package can be installed + if(OCIO_INSTALL_EXT_PACKAGES STREQUAL MISSING) + set(yaml-cpp_FIND_REQUIRED FALSE) + endif() + + include(FindPackageHandleStandardArgs) + find_package_handle_standard_args(yaml-cpp + REQUIRED_VARS + yaml-cpp_INCLUDE_DIR + yaml-cpp_LIBRARY + VERSION_VAR + yaml-cpp_VERSION + ) +endif() + +############################################################################### +### Create target (if previous 'find_package' call hasn't) ### + +if(NOT TARGET yaml-cpp) + add_library(yaml-cpp UNKNOWN IMPORTED GLOBAL) + set(_yaml-cpp_TARGET_CREATE TRUE) +endif() + +############################################################################### +### Install package from source ### + +if(NOT yaml-cpp_FOUND) + include(ExternalProject) + # TODO: yaml-cpp master is using GNUInstallDirs to define include and lib + # dir names. Once that change is released and OCIO updates the + # minimum yaml-cpp version, toggle the three disabled lines below. + #include(GNUInstallDirs) + + set(_EXT_DIST_ROOT "${CMAKE_BINARY_DIR}/ext/dist") + set(_EXT_BUILD_ROOT "${CMAKE_BINARY_DIR}/ext/build") + + # Set find_package standard args + set(yaml-cpp_FOUND TRUE) + set(yaml-cpp_VERSION ${yaml-cpp_FIND_VERSION}) + set(yaml-cpp_INCLUDE_DIR "${_EXT_DIST_ROOT}/include") + #set(yaml-cpp_INCLUDE_DIR "${_EXT_DIST_ROOT}/${CMAKE_INSTALL_INCLUDEDIR}") + + # Set the expected library name + if(WIN32) + set(_yaml-cpp_LIB_SUFFIX "md") + if(BUILD_TYPE_DEBUG) + string(APPEND _yaml-cpp_LIB_SUFFIX "d") + endif() + endif() + set(yaml-cpp_LIBRARY + "${_EXT_DIST_ROOT}/lib/libyaml-cpp${_yaml-cpp_LIB_SUFFIX}${CMAKE_STATIC_LIBRARY_SUFFIX}") + # set(yaml-cpp_LIBRARY + # "${_EXT_DIST_ROOT}/${CMAKE_INSTALL_LIBDIR}/libyaml-cpp${_yaml-cpp_LIB_SUFFIX}${CMAKE_STATIC_LIBRARY_SUFFIX}") + + if(_yaml-cpp_TARGET_CREATE) + if(MSVC) + set(yaml-cpp_CXX_FLAGS "${yaml-cpp_CXX_FLAGS} /EHsc") + endif() + + if(UNIX) + set(yaml-cpp_CXX_FLAGS "${yaml-cpp_CXX_FLAGS} -fvisibility=hidden -fPIC") + if(OCIO_INLINES_HIDDEN) + set(yaml-cpp_CXX_FLAGS "${yaml-cpp_CXX_FLAGS} -fvisibility-inlines-hidden") + endif() + endif() + + string(STRIP "${yaml-cpp_CXX_FLAGS}" yaml-cpp_CXX_FLAGS) + + set(yaml-cpp_CMAKE_ARGS + ${yaml-cpp_CMAKE_ARGS} + -DCMAKE_INSTALL_PREFIX=${_EXT_DIST_ROOT} + -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE} + -DBUILD_SHARED_LIBS=OFF + -DYAML_BUILD_SHARED_LIBS=OFF + -DYAML_CPP_BUILD_TESTS=OFF + -DYAML_CPP_BUILD_TOOLS=OFF + -DYAML_CPP_BUILD_CONTRIB=OFF + -DCMAKE_CXX_FLAGS=${yaml-cpp_CXX_FLAGS} + -DCMAKE_CXX_STANDARD=${CMAKE_CXX_STANDARD} + ) + if(CMAKE_TOOLCHAIN_FILE) + set(yaml-cpp_CMAKE_ARGS + ${yaml-cpp_CMAKE_ARGS} -DCMAKE_TOOLCHAIN_FILE=${CMAKE_TOOLCHAIN_FILE}) + endif() + + if(NOT BUILD_SHARED_LIBS) + #TODO: Find a way to merge in the static libs when built with internal yamlcpp + message(WARNING + "Building STATIC libOpenColorIO using the in-built yaml-cpp. " + "yaml-cpp symbols are NOT included in the output binary!" + ) + endif() + + set(yaml-cpp_GIT_TAG "yaml-cpp-${yaml-cpp_VERSION}") + + # Hack to let imported target be built from ExternalProject_Add + file(MAKE_DIRECTORY ${yaml-cpp_INCLUDE_DIR}) + + ExternalProject_Add(yaml-cpp_install + GIT_REPOSITORY "https://github.com/jbeder/yaml-cpp.git" + GIT_TAG ${yaml-cpp_GIT_TAG} + GIT_CONFIG advice.detachedHead=false + GIT_SHALLOW TRUE + PREFIX "${_EXT_BUILD_ROOT}/yaml-cpp" + BUILD_BYPRODUCTS ${yaml-cpp_LIBRARY} + CMAKE_ARGS ${yaml-cpp_CMAKE_ARGS} + EXCLUDE_FROM_ALL TRUE + ) + + add_dependencies(yaml-cpp yaml-cpp_install) + message(STATUS + "Installing yaml-cpp: ${yaml-cpp_LIBRARY} (version \"${yaml-cpp_VERSION}\")" + ) + endif() +endif() + +############################################################################### +### Configure target ### + +if(_yaml-cpp_TARGET_CREATE) + set_target_properties(yaml-cpp PROPERTIES + IMPORTED_LOCATION ${yaml-cpp_LIBRARY} + INTERFACE_INCLUDE_DIRECTORIES ${yaml-cpp_INCLUDE_DIR} + ) + + mark_as_advanced(yaml-cpp_INCLUDE_DIR yaml-cpp_LIBRARY yaml-cpp_VERSION) +endif() diff --git a/share/cmake/projects/BuildLCMS2.cmake b/share/cmake/projects/Buildlcms2.cmake similarity index 100% rename from share/cmake/projects/BuildLCMS2.cmake rename to share/cmake/projects/Buildlcms2.cmake diff --git a/share/cmake/projects/BuildPystring.cmake b/share/cmake/projects/Buildpystring.cmake similarity index 81% rename from share/cmake/projects/BuildPystring.cmake rename to share/cmake/projects/Buildpystring.cmake index 9d90b076ad..0a6dee7939 100644 --- a/share/cmake/projects/BuildPystring.cmake +++ b/share/cmake/projects/Buildpystring.cmake @@ -16,11 +16,11 @@ set(SOURCES add_library(${PROJECT_NAME} STATIC ${HEADERS} ${SOURCES}) if(UNIX) - set(PYSTRING_CXX_FLAGS "${PYSTRING_CXX_FLAGS} -fPIC") + set(pystring_CXX_FLAGS "${pystring_CXX_FLAGS} -fPIC") endif() set_target_properties(${PROJECT_NAME} PROPERTIES - COMPILE_FLAGS "${PLATFORM_COMPILE_FLAGS} ${PYSTRING_CXX_FLAGS}" + COMPILE_FLAGS "${PLATFORM_COMPILE_FLAGS} ${pystring_CXX_FLAGS}" PUBLIC_HEADER "${HEADERS}" ) diff --git a/share/cmake/scripts/PatchOpenEXR.cmake b/share/cmake/scripts/PatchOpenEXR.cmake new file mode 100644 index 0000000000..e885d71794 --- /dev/null +++ b/share/cmake/scripts/PatchOpenEXR.cmake @@ -0,0 +1,9 @@ +# SPDX-License-Identifier: BSD-3-Clause +# Copyright Contributors to the OpenColorIO Project. + +# Disable OpenEXR in the root CMakeLists.txt file, so that only IlmBase is +# configured. +file(READ CMakeLists.txt _OpenEXR_CMAKE_DATA) +string(REGEX REPLACE "^(.*)(add_subdirectory\\(OpenEXR\\))(.*)$" "\\1#\\2\\3" + _OpenEXR_CMAKE_DATA "${_OpenEXR_CMAKE_DATA}") +file(WRITE CMakeLists.txt "${_OpenEXR_CMAKE_DATA}") diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index cf69e8876f..f78654e02c 100755 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -5,7 +5,10 @@ # These apps may also require the building of openglbuilder from utils # but because the builder also needs GLEW, we only conditionally build # this lib -find_package(OpenImageIO QUIET) + +# OpenImageIO +# https://github.com/OpenImageIO/oiio +find_package(OpenImageIO 2.1.9 CONFIG) # The order defines the architecture of the project i.e. layers and dependencies. diff --git a/src/OpenColorIO/CMakeLists.txt b/src/OpenColorIO/CMakeLists.txt index 52b61d3023..4f23df26f1 100755 --- a/src/OpenColorIO/CMakeLists.txt +++ b/src/OpenColorIO/CMakeLists.txt @@ -174,11 +174,11 @@ target_link_libraries(OpenColorIO public_api PRIVATE expat::expat - ilmbase::ilmbase + IlmBase::Half pystring::pystring sampleicc::sampleicc utils::strings - yamlcpp::yamlcpp + yaml-cpp ) if(NOT BUILD_SHARED_LIBS) diff --git a/src/apps/CMakeLists.txt b/src/apps/CMakeLists.txt index 39446decce..52bac9fbce 100755 --- a/src/apps/CMakeLists.txt +++ b/src/apps/CMakeLists.txt @@ -8,12 +8,12 @@ if(OCIO_BUILD_APPS) add_subdirectory(ociomakeclf) add_subdirectory(ociowrite) - if(TARGET OpenImageIO) + if(TARGET OpenImageIO::OpenImageIO) add_subdirectory(ociolutimage) add_subdirectory(ocioconvert) add_subdirectory(ociodisplay) add_subdirectory(ocioperf) else() - message(WARNING "OpenImageIO Not found. Skipping build for ociolutimage, ocioconvert, ociodisplay and ocioperf") + message(WARNING "Could NOT find OpenImageIO. Skipping build for ociolutimage, ocioconvert, ociodisplay and ocioperf") endif() endif() diff --git a/src/apps/ocioconvert/CMakeLists.txt b/src/apps/ocioconvert/CMakeLists.txt index 9487b872ee..d1a9d907cd 100755 --- a/src/apps/ocioconvert/CMakeLists.txt +++ b/src/apps/ocioconvert/CMakeLists.txt @@ -27,11 +27,11 @@ set_target_properties(ocioconvert PROPERTIES target_link_libraries(ocioconvert PRIVATE apputils - ilmbase::ilmbase + IlmBase::Half ${OCIO_GL_LIB} oiiohelpers OpenColorIO - OpenImageIO + OpenImageIO::OpenImageIO ) install(TARGETS ocioconvert diff --git a/src/apps/ociodisplay/CMakeLists.txt b/src/apps/ociodisplay/CMakeLists.txt index 562eb2224f..d4af73ff7d 100755 --- a/src/apps/ociodisplay/CMakeLists.txt +++ b/src/apps/ociodisplay/CMakeLists.txt @@ -36,7 +36,7 @@ target_link_libraries(ociodisplay oglapphelpers OpenColorIO ${OPENGL_LIBRARIES} - OpenImageIO + OpenImageIO::OpenImageIO ) install(TARGETS ociodisplay RUNTIME DESTINATION bin diff --git a/src/apps/ociolutimage/CMakeLists.txt b/src/apps/ociolutimage/CMakeLists.txt index b44911ca28..ef24e6bba7 100755 --- a/src/apps/ociolutimage/CMakeLists.txt +++ b/src/apps/ociolutimage/CMakeLists.txt @@ -21,7 +21,7 @@ target_link_libraries(ociolutimage PRIVATE apputils OpenColorIO - OpenImageIO + OpenImageIO::OpenImageIO utils::strings ) diff --git a/src/apps/ocioperf/CMakeLists.txt b/src/apps/ocioperf/CMakeLists.txt index baa0039e84..69e9ba4c59 100644 --- a/src/apps/ocioperf/CMakeLists.txt +++ b/src/apps/ocioperf/CMakeLists.txt @@ -20,10 +20,10 @@ set_target_properties(ocioperf PROPERTIES target_link_libraries(ocioperf PRIVATE apputils - ilmbase::ilmbase + IlmBase::Half oiiohelpers OpenColorIO - OpenImageIO + OpenImageIO::OpenImageIO utils::strings ) diff --git a/src/bindings/python/CMakeLists.txt b/src/bindings/python/CMakeLists.txt index 983f27120c..d530bbf38f 100644 --- a/src/bindings/python/CMakeLists.txt +++ b/src/bindings/python/CMakeLists.txt @@ -7,11 +7,6 @@ find_package(PythonInterp 2.7 REQUIRED) find_package(PythonLibs 2.7 REQUIRED) -# pybind11 -# https://github.com/pybind/pybind11 -set(pybind11_MIN_VERSION 2.4.3) -find_package(pybind11 ${pybind11_MIN_VERSION} REQUIRED) - ############################################################################### # PyDoc generation # file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/include") diff --git a/src/libutils/oiiohelpers/CMakeLists.txt b/src/libutils/oiiohelpers/CMakeLists.txt index 84e16101a5..d34334b2ad 100644 --- a/src/libutils/oiiohelpers/CMakeLists.txt +++ b/src/libutils/oiiohelpers/CMakeLists.txt @@ -31,11 +31,11 @@ target_include_directories(oiiohelpers target_link_libraries(oiiohelpers PUBLIC - OpenImageIO + OpenImageIO::OpenImageIO PRIVATE OpenColorIO - ilmbase::ilmbase + IlmBase::Half utils::strings ) diff --git a/tests/cpu/CMakeLists.txt b/tests/cpu/CMakeLists.txt index 38773a64d5..bb2c535b17 100755 --- a/tests/cpu/CMakeLists.txt +++ b/tests/cpu/CMakeLists.txt @@ -1,8 +1,6 @@ # SPDX-License-Identifier: BSD-3-Clause # Copyright Contributors to the OpenColorIO Project. -include(ExternalProject) - # Define used for tests in tests/cpu/Context_tests.cpp add_definitions("-DOCIO_SOURCE_DIR=${CMAKE_SOURCE_DIR}") @@ -20,12 +18,12 @@ function(add_ocio_test NAME SOURCES PRIVATE_INCLUDES) public_api PRIVATE expat::expat - ilmbase::ilmbase + IlmBase::Half pystring::pystring sampleicc::sampleicc unittest_data utils::strings - yamlcpp::yamlcpp + yaml-cpp testutils ) if(PRIVATE_INCLUDES) From 5a991413fae6b2dbc62a671806c54a4ab412ab0b Mon Sep 17 00:00:00 2001 From: Michael Dolan Date: Thu, 14 May 2020 09:52:45 -0400 Subject: [PATCH 02/33] Use OpenGL find_package messaging Signed-off-by: Michael Dolan --- CMakeLists.txt | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 6ad50de66a..f833de8cf5 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -86,21 +86,18 @@ option(OCIO_WARNING_AS_ERROR "Set build error level for CI testing" OFF) if(OCIO_BUILD_GPU_TESTS OR OCIO_BUILD_APPS) set(OCIO_GL_ENABLED ON) - find_package(OpenGL QUIET) + find_package(OpenGL) if(NOT OpenGL_FOUND) - message(WARNING "Could NOT find OpenGL.") set(OCIO_GL_ENABLED OFF) endif() if(NOT APPLE) - find_package(GLEW QUIET) + find_package(GLEW) if(NOT GLEW_FOUND) - message(WARNING "Coule NOT find GLEW.") set(OCIO_GL_ENABLED OFF) endif() endif() - find_package(GLUT QUIET) + find_package(GLUT) if(NOT GLUT_FOUND) - message(WARNING "Could NOT find GLUT.") set(OCIO_GL_ENABLED OFF) endif() endif() From f52d9755904f9fb72ead3759001adbb7bff20494 Mon Sep 17 00:00:00 2001 From: Michael Dolan Date: Sat, 16 May 2020 23:38:47 -0400 Subject: [PATCH 03/33] Fix FindHalf.cmake documentation Signed-off-by: Michael Dolan --- share/cmake/modules/FindHalf.cmake | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/share/cmake/modules/FindHalf.cmake b/share/cmake/modules/FindHalf.cmake index 38a74c8dd6..01bb30d9cc 100644 --- a/share/cmake/modules/FindHalf.cmake +++ b/share/cmake/modules/FindHalf.cmake @@ -14,11 +14,11 @@ # # By default, the dynamic libraries of ilmbase will be found. To find the # static ones instead, you must set the Half_STATIC_LIBRARY variable to -# TRUE before calling find_package(IlmBase ...). +# TRUE before calling find_package(Half ...). # -# If ilmbase is not installed in a standard path, you can use the +# If IlmBase is not installed in a standard path, you can use the # Half_ROOT variable to tell CMake where to find it. If it is not found -# and OCIO_INSTALL_EXT_PACKAGES is set to MISSING or ALL, ilmbase will be +# and OCIO_INSTALL_EXT_PACKAGES is set to MISSING or ALL, IlmBase will be # downloaded, built, and statically-linked into libOpenColorIO at build time. # From bda13d94d0df6a7665d131636d6eed1c177f4b66 Mon Sep 17 00:00:00 2001 From: Bernard Lefebvre <37628108+BernardLefebvre@users.noreply.github.com> Date: Thu, 14 May 2020 15:13:15 -0400 Subject: [PATCH 04/33] Fix View serialization in Config: view transform was not saved. (#1015) Add a test for View serialization. Signed-off-by: Bernard Lefebvre --- src/OpenColorIO/OCIOYaml.cpp | 3 ++- tests/cpu/Config_tests.cpp | 24 ++++++++++++++++++++++++ 2 files changed, 26 insertions(+), 1 deletion(-) diff --git a/src/OpenColorIO/OCIOYaml.cpp b/src/OpenColorIO/OCIOYaml.cpp index dd45d4c1ef..9642052c24 100644 --- a/src/OpenColorIO/OCIOYaml.cpp +++ b/src/OpenColorIO/OCIOYaml.cpp @@ -3345,7 +3345,8 @@ inline void save(YAML::Emitter & out, const Config & config) { View dview; dview.m_name = config.getView(display, v); - dview.m_colorspace = config.getDisplayViewTransformName(display, dview.m_name.c_str()); + dview.m_viewTransform = config.getDisplayViewTransformName(display, + dview.m_name.c_str()); dview.m_colorspace = config.getDisplayColorSpaceName(display, dview.m_name.c_str()); if(config.getDisplayLooks(display, dview.m_name.c_str()) != NULL) { diff --git a/tests/cpu/Config_tests.cpp b/tests/cpu/Config_tests.cpp index 0fde8af9e3..41f428d98a 100644 --- a/tests/cpu/Config_tests.cpp +++ b/tests/cpu/Config_tests.cpp @@ -4073,6 +4073,30 @@ OCIO_ADD_TEST(Config, display_view) OCIO_CHECK_EQUAL(config->getNumDisplays(), 1); OCIO_CHECK_EQUAL(config->getNumViews(display.c_str()), 2); + + // Check that views are saved and loaded properly. + config->setMajorVersion(2); + std::ostringstream oss; + config->serialize(oss); + + std::istringstream is; + is.str(oss.str()); + OCIO::ConstConfigRcPtr configRead; + OCIO_CHECK_NO_THROW(configRead = OCIO::Config::CreateFromStream(is)); + OCIO_CHECK_EQUAL(configRead->getNumViews("display"), 2); + const std::string v1{ configRead->getView("display", 0) }; + OCIO_CHECK_EQUAL(v1, "view1"); + OCIO_CHECK_EQUAL(std::string("scs"), + configRead->getDisplayColorSpaceName("display", v1.c_str())); + OCIO_CHECK_EQUAL(std::string(""), + configRead->getDisplayViewTransformName("display", v1.c_str())); + const std::string v2{ configRead->getView("display", 1) }; + OCIO_CHECK_EQUAL(v2, "view2"); + OCIO_CHECK_EQUAL(std::string("dcs"), + configRead->getDisplayColorSpaceName("display", v2.c_str())); + OCIO_CHECK_EQUAL(std::string("view_transform"), + configRead->getDisplayViewTransformName("display", v2.c_str())); + // Using nullptr for any parameter does nothing. OCIO_CHECK_NO_THROW(config->addDisplay(nullptr, "view1", "scs", "")); OCIO_CHECK_NO_THROW(config->addDisplay(display.c_str(), nullptr, "scs", "")); From 5fb3382942e7b69937826889627a3b50b4e0d5ed Mon Sep 17 00:00:00 2001 From: doug-walker <43830961+doug-walker@users.noreply.github.com> Date: Tue, 19 May 2020 08:18:22 -0400 Subject: [PATCH 05/33] Adsk Contrib - Enhance CLF tests (#1011) * Refactor CLF tests Signed-off-by: Doug Walker * Address review comments Signed-off-by: Doug Walker * Tweak test names Signed-off-by: Doug Walker * Transform_missing build break fix Signed-off-by: Doug Walker * Windows build break fix Signed-off-by: Doug Walker --- include/OpenColorIO/OpenColorTypes.h | 10 +- .../fileformats/ctf/CTFReaderHelper.cpp | 183 +- .../fileformats/ctf/CTFReaderHelper.h | 4 +- tests/cpu/fileformats/FileFormatCTF_tests.cpp | 2840 +- tests/cpu/ops/lut1d/Lut1DOp_tests.cpp | 2 +- tests/cpu/ops/lut3d/Lut3DOpData_tests.cpp | 6 +- tests/cpu/ops/lut3d/Lut3DOp_tests.cpp | 6 +- .../ops/reference/ReferenceOpData_tests.cpp | 2 +- tests/cpu/transforms/FileTransform_tests.cpp | 12 +- tests/data/files/cdl_invalidSOP.clf | 17 - tests/data/files/cdl_invalidSat.clf | 17 - tests/data/files/clf/cdl_all_styles.clf | 44 + tests/data/files/{ => clf}/cdl_clamp_fwd.clf | 2 +- .../cdl_missing_sat.clf} | 6 +- .../cdl_missing_sop.clf} | 4 +- .../files/{ => clf}/cdl_missing_style.clf | 7 +- tests/data/files/clf/difficult_syntax.clf | 71 + tests/data/files/clf/exponent_all_styles.clf | 47 + .../illegal/array_bad_dimension.clf} | 4 +- .../illegal/array_bad_value.clf} | 6 +- .../illegal}/array_missing_values.clf | 5 +- .../illegal}/array_too_many_values.clf | 6 +- .../illegal/cdl_bad_power.clf} | 8 +- tests/data/files/clf/illegal/cdl_bad_sat.clf | 14 + .../data/files/clf/illegal/cdl_bad_slope.clf | 14 + .../illegal/cdl_bad_style.clf} | 7 +- .../{ => clf/illegal}/cdl_missing_offset.clf | 10 +- .../files/clf/illegal/cdl_missing_power.clf | 14 + .../{ => clf/illegal}/cdl_missing_slope.clf | 9 +- .../files/clf/illegal/exponent_bad_param.clf | 7 + .../files/clf/illegal/exponent_bad_value.clf | 7 + .../files/{ => clf/illegal}/image_png.clf | Bin .../data/files/clf/illegal/indexMap_test2.clf | 19 + .../data/files/clf/illegal/log_bad_param.clf | 7 + .../data/files/clf/illegal/log_bad_style.clf | 6 + .../illegal/log_bad_version.clf} | 2 +- .../clf/illegal/log_missing_breakpnt.clf | 8 + .../lut1d_half_domain_missing_values.clf | 42 + .../illegal/lut1d_half_domain_set_false.clf | 42 + .../clf/illegal/lut1d_raw_half_set_false.clf | 42 + .../files/clf/illegal/lut3d_unequal_size.clf | 20 + .../{ => clf/illegal}/matrix_end_missing.clf | 3 +- .../clf/illegal/process_list_bad_version.clf | 11 + .../illegal/process_list_higher_version.clf | 11 + .../illegal/process_list_missing.clf} | 3 +- .../files/clf/illegal/range_bad_noclamp.clf | 8 + .../illegal/range_empty.clf} | 3 +- .../clf/illegal/range_nonmatching_clamp.clf | 9 + .../illegal/transform_bad_outdepth.clf} | 8 +- .../illegal}/transform_bitdepth_mismatch.clf | 8 +- .../clf/illegal/transform_corrupted_tag.clf | 12 + .../illegal/transform_element_end_missing.clf | 11 + .../{ => clf/illegal}/transform_empty.clf | 3 +- .../files/clf/illegal/transform_id_empty.clf | 5 + .../illegal/transform_missing.clf} | 0 .../clf/illegal/transform_missing_id.clf | 5 + .../illegal/transform_missing_inbitdepth.clf | 10 + .../illegal/transform_missing_outbitdepth.clf | 10 + .../{ => clf/illegal}/unknown_elements.clf | 8 +- tests/data/files/clf/info_example.clf | 40 + .../inverseOf_id_test.clf} | 6 +- tests/data/files/clf/log_all_styles.clf | 47 + tests/data/files/clf/lut1d_32f_example.clf | 8 + tests/data/files/{ => clf}/lut1d_comp.clf | 4 +- tests/data/files/clf/lut1d_example.clf | 10 + .../lut1d_half_domain_raw_half_set.clf | 5 +- .../lut3by1d_nan_infinity_example.clf | 3 +- .../{ => clf}/lut3d_17x17x17_10i_12i.clf | 4 +- tests/data/files/{ => clf}/lut3d_bizarre.clf | 8 +- .../data/files/clf/lut3d_identity_12i_16f.clf | 17 + tests/data/files/clf/matrix_3x4_example.clf | 13 + tests/data/files/{ => clf}/matrix_example.clf | 7 +- .../files/{ => clf}/matrix_example_utf8.clf | 6 +- tests/data/files/{ => clf}/matrix_windows.clf | 20 +- tests/data/files/{ => clf}/multiple_ops.clf | 32 +- tests/data/files/clf/range.clf | 13 + tests/data/files/clf/range_test1_clamp.clf | 10 + tests/data/files/clf/range_test1_noclamp.clf | 10 + tests/data/files/clf/range_test2.clf | 10 + tests/data/files/clf/tabulation_support.clf | 35 + tests/data/files/{ => clf}/xyz_to_rgb.clf | 8 +- tests/data/files/clf_version_future.clf | 18 - tests/data/files/gamma_wrong_power.ctf | 7 - ...Map_test1.clf => indexMap_test1_clfv2.clf} | 1 + ...Map_test2.clf => indexMap_test2_clfv2.clf} | 1 + ...{indexMap_test3.clf => indexMap_test3.ctf} | 2 +- ...Map_test4.clf => indexMap_test4_clfv2.clf} | 0 ...ap_example.clf => indexMap_test_clfv2.clf} | 0 tests/data/files/log_antilog10.ctf | 9 - tests/data/files/log_antilog2.ctf | 9 - tests/data/files/log_invalidstyle.ctf | 9 - tests/data/files/log_log10.ctf | 9 - tests/data/files/log_log2.ctf | 9 - tests/data/files/log_logtolinv2.ctf | 7 + tests/data/files/lut1d_32f_example.clf | 8 - tests/data/files/lut1d_example.clf | 8 - .../lut1d_half_domain_invalid_entries.clf | 43 - .../files/lut1d_half_domain_set_false.clf | 43 - ...clf => lut1d_hue_adjust_invalid_style.ctf} | 0 tests/data/files/lut1d_raw_half_set_false.clf | 43 - tests/data/files/lut3d_17x17x17_32f_12i.clf | 4921 --- tests/data/files/lut3d_2x2x2_32f_32f.clf | 15 - tests/data/files/lut3d_identity_12i_16f.clf | 17 - tests/data/files/matrix_3x4_example.clf | 13 - tests/data/files/matrix_bitdepth_illegal.clf | 14 - .../data/files/{metadata.clf => metadata.ctf} | 0 tests/data/files/range.clf | 11 - tests/data/files/range_test1.clf | 9 - tests/data/files/range_test2.clf | 9 - tests/data/files/reference_nested_2.ctf | 2 +- tests/data/files/reference_one_matrix.ctf | 2 +- tests/data/files/references_same_twice.ctf | 4 +- tests/data/files/references_some_inverted.ctf | 6 +- tests/data/files/tabulation_support.clf | 35944 ---------------- tests/data/files/transform_corrupted_tag.clf | 3 - .../files/transform_element_end_missing.clf | 2 - tests/data/files/transform_id_empty.clf | 3 - tests/data/files/transform_missing_id.clf | 3 - .../files/transform_missing_inbitdepth.clf | 5 - .../files/transform_missing_outbitdepth.clf | 5 - 120 files changed, 2638 insertions(+), 42599 deletions(-) delete mode 100644 tests/data/files/cdl_invalidSOP.clf delete mode 100644 tests/data/files/cdl_invalidSat.clf create mode 100644 tests/data/files/clf/cdl_all_styles.clf rename tests/data/files/{ => clf}/cdl_clamp_fwd.clf (91%) rename tests/data/files/{cdl_noSat.clf => clf/cdl_missing_sat.clf} (59%) rename tests/data/files/{cdl_noSOP.clf => clf/cdl_missing_sop.clf} (73%) rename tests/data/files/{ => clf}/cdl_missing_style.clf (57%) create mode 100644 tests/data/files/clf/difficult_syntax.clf create mode 100644 tests/data/files/clf/exponent_all_styles.clf rename tests/data/files/{array_illegal_dimension.clf => clf/illegal/array_bad_dimension.clf} (81%) rename tests/data/files/{array_illegal_values.clf => clf/illegal/array_bad_value.clf} (74%) rename tests/data/files/{ => clf/illegal}/array_missing_values.clf (52%) rename tests/data/files/{ => clf/illegal}/array_too_many_values.clf (79%) rename tests/data/files/{cdl_missing_power.clf => clf/illegal/cdl_bad_power.clf} (55%) create mode 100644 tests/data/files/clf/illegal/cdl_bad_sat.clf create mode 100644 tests/data/files/clf/illegal/cdl_bad_slope.clf rename tests/data/files/{cdl_invalid_style.clf => clf/illegal/cdl_bad_style.clf} (59%) rename tests/data/files/{ => clf/illegal}/cdl_missing_offset.clf (51%) create mode 100644 tests/data/files/clf/illegal/cdl_missing_power.clf rename tests/data/files/{ => clf/illegal}/cdl_missing_slope.clf (54%) create mode 100644 tests/data/files/clf/illegal/exponent_bad_param.clf create mode 100644 tests/data/files/clf/illegal/exponent_bad_value.clf rename tests/data/files/{ => clf/illegal}/image_png.clf (100%) create mode 100644 tests/data/files/clf/illegal/indexMap_test2.clf create mode 100644 tests/data/files/clf/illegal/log_bad_param.clf create mode 100644 tests/data/files/clf/illegal/log_bad_style.clf rename tests/data/files/{log_log10_faulty_version.ctf => clf/illegal/log_bad_version.clf} (76%) create mode 100644 tests/data/files/clf/illegal/log_missing_breakpnt.clf create mode 100644 tests/data/files/clf/illegal/lut1d_half_domain_missing_values.clf create mode 100644 tests/data/files/clf/illegal/lut1d_half_domain_set_false.clf create mode 100644 tests/data/files/clf/illegal/lut1d_raw_half_set_false.clf create mode 100644 tests/data/files/clf/illegal/lut3d_unequal_size.clf rename tests/data/files/{ => clf/illegal}/matrix_end_missing.clf (72%) create mode 100644 tests/data/files/clf/illegal/process_list_bad_version.clf create mode 100644 tests/data/files/clf/illegal/process_list_higher_version.clf rename tests/data/files/{not_a_ctf.xml => clf/illegal/process_list_missing.clf} (64%) create mode 100644 tests/data/files/clf/illegal/range_bad_noclamp.clf rename tests/data/files/{range_test3.clf => clf/illegal/range_empty.clf} (59%) create mode 100644 tests/data/files/clf/illegal/range_nonmatching_clamp.clf rename tests/data/files/{unknown_outdepth.clf => clf/illegal/transform_bad_outdepth.clf} (70%) rename tests/data/files/{ => clf/illegal}/transform_bitdepth_mismatch.clf (72%) create mode 100644 tests/data/files/clf/illegal/transform_corrupted_tag.clf create mode 100644 tests/data/files/clf/illegal/transform_element_end_missing.clf rename tests/data/files/{ => clf/illegal}/transform_empty.clf (58%) create mode 100644 tests/data/files/clf/illegal/transform_id_empty.clf rename tests/data/files/{transform_invalid.clf => clf/illegal/transform_missing.clf} (100%) create mode 100644 tests/data/files/clf/illegal/transform_missing_id.clf create mode 100644 tests/data/files/clf/illegal/transform_missing_inbitdepth.clf create mode 100644 tests/data/files/clf/illegal/transform_missing_outbitdepth.clf rename tests/data/files/{ => clf/illegal}/unknown_elements.clf (85%) create mode 100644 tests/data/files/clf/info_example.clf rename tests/data/files/{inverseOfId_test.clf => clf/inverseOf_id_test.clf} (61%) create mode 100644 tests/data/files/clf/log_all_styles.clf create mode 100644 tests/data/files/clf/lut1d_32f_example.clf rename tests/data/files/{ => clf}/lut1d_comp.clf (94%) create mode 100644 tests/data/files/clf/lut1d_example.clf rename tests/data/files/{ => clf}/lut1d_half_domain_raw_half_set.clf (99%) rename tests/data/files/{ => clf}/lut3by1d_nan_infinity_example.clf (59%) rename tests/data/files/{ => clf}/lut3d_17x17x17_10i_12i.clf (99%) rename tests/data/files/{ => clf}/lut3d_bizarre.clf (66%) create mode 100644 tests/data/files/clf/lut3d_identity_12i_16f.clf create mode 100644 tests/data/files/clf/matrix_3x4_example.clf rename tests/data/files/{ => clf}/matrix_example.clf (60%) rename tests/data/files/{ => clf}/matrix_example_utf8.clf (59%) rename tests/data/files/{ => clf}/matrix_windows.clf (56%) rename tests/data/files/{ => clf}/multiple_ops.clf (58%) create mode 100644 tests/data/files/clf/range.clf create mode 100644 tests/data/files/clf/range_test1_clamp.clf create mode 100644 tests/data/files/clf/range_test1_noclamp.clf create mode 100644 tests/data/files/clf/range_test2.clf create mode 100644 tests/data/files/clf/tabulation_support.clf rename tests/data/files/{ => clf}/xyz_to_rgb.clf (80%) delete mode 100644 tests/data/files/clf_version_future.clf delete mode 100644 tests/data/files/gamma_wrong_power.ctf rename tests/data/files/{indexMap_test1.clf => indexMap_test1_clfv2.clf} (89%) rename tests/data/files/{indexMap_test2.clf => indexMap_test2_clfv2.clf} (86%) rename tests/data/files/{indexMap_test3.clf => indexMap_test3.ctf} (92%) rename tests/data/files/{indexMap_test4.clf => indexMap_test4_clfv2.clf} (100%) rename tests/data/files/{lut1d_indexmap_example.clf => indexMap_test_clfv2.clf} (100%) delete mode 100644 tests/data/files/log_antilog10.ctf delete mode 100644 tests/data/files/log_antilog2.ctf delete mode 100644 tests/data/files/log_invalidstyle.ctf delete mode 100644 tests/data/files/log_log10.ctf delete mode 100644 tests/data/files/log_log2.ctf create mode 100644 tests/data/files/log_logtolinv2.ctf delete mode 100644 tests/data/files/lut1d_32f_example.clf delete mode 100644 tests/data/files/lut1d_example.clf delete mode 100644 tests/data/files/lut1d_half_domain_invalid_entries.clf delete mode 100644 tests/data/files/lut1d_half_domain_set_false.clf rename tests/data/files/{lut1d_hue_adjust_invalid_style.clf => lut1d_hue_adjust_invalid_style.ctf} (100%) delete mode 100644 tests/data/files/lut1d_raw_half_set_false.clf delete mode 100644 tests/data/files/lut3d_17x17x17_32f_12i.clf delete mode 100644 tests/data/files/lut3d_2x2x2_32f_32f.clf delete mode 100644 tests/data/files/lut3d_identity_12i_16f.clf delete mode 100644 tests/data/files/matrix_3x4_example.clf delete mode 100644 tests/data/files/matrix_bitdepth_illegal.clf rename tests/data/files/{metadata.clf => metadata.ctf} (100%) delete mode 100644 tests/data/files/range.clf delete mode 100644 tests/data/files/range_test1.clf delete mode 100644 tests/data/files/range_test2.clf delete mode 100644 tests/data/files/tabulation_support.clf delete mode 100644 tests/data/files/transform_corrupted_tag.clf delete mode 100644 tests/data/files/transform_element_end_missing.clf delete mode 100644 tests/data/files/transform_id_empty.clf delete mode 100644 tests/data/files/transform_missing_id.clf delete mode 100644 tests/data/files/transform_missing_inbitdepth.clf delete mode 100644 tests/data/files/transform_missing_outbitdepth.clf diff --git a/include/OpenColorIO/OpenColorTypes.h b/include/OpenColorIO/OpenColorTypes.h index 2fc8b0e766..97aa40e07f 100644 --- a/include/OpenColorIO/OpenColorTypes.h +++ b/include/OpenColorIO/OpenColorTypes.h @@ -360,10 +360,10 @@ enum TransformDirection enum Interpolation { INTERP_UNKNOWN = 0, - INTERP_NEAREST = 1, //! nearest neighbor in all dimensions - INTERP_LINEAR = 2, //! linear interpolation in all dimensions - INTERP_TETRAHEDRAL = 3, //! tetrahedral interpolation in all directions - INTERP_CUBIC = 4, //! cubic interpolation in all dimensions + INTERP_NEAREST = 1, //! nearest neighbor + INTERP_LINEAR = 2, //! linear interpolation (trilinear for Lut3D) + INTERP_TETRAHEDRAL = 3, //! tetrahedral interpolation (Lut3D only) + INTERP_CUBIC = 4, //! cubic interpolation (not supported) INTERP_DEFAULT = 254, //! the default interpolation type INTERP_BEST = 255 //! the 'best' suitable interpolation type @@ -466,6 +466,8 @@ enum CDLStyle CDL_ASC = 0, //! ASC CDL specification v1.2 CDL_NO_CLAMP, //! CDL that does not clamp + // Note: The default for reading .cc/.ccc/.cdl files, config file YAML, and CDLTransform is no-clamp, + // since that is what is primarily desired in VFX. However, the CLF format default is ASC. CDL_TRANSFORM_DEFAULT = CDL_NO_CLAMP }; diff --git a/src/OpenColorIO/fileformats/ctf/CTFReaderHelper.cpp b/src/OpenColorIO/fileformats/ctf/CTFReaderHelper.cpp index c01ced2495..f6f8c5d8e8 100644 --- a/src/OpenColorIO/fileformats/ctf/CTFReaderHelper.cpp +++ b/src/OpenColorIO/fileformats/ctf/CTFReaderHelper.cpp @@ -1324,9 +1324,11 @@ void CTFReaderCDLElt::start(const char ** atts) } } + // Although the OCIO default for CDL style is no-clamp, the default specified in + // the CLF v3 spec is ASC. if (!isStyleFound) { - throwMessage("CTF/CLF CDL parsing. Required attribute 'style' is missing."); + m_cdl->setStyle(CDLOpData::CDL_V1_2_FWD); } } @@ -1837,6 +1839,10 @@ void CTFReaderGammaElt::start(const char ** atts) } m_gamma->setStyle(style); isStyleFound = true; + + // Set default parameters for all channels. + const GammaOpData::Params params = GammaOpData::getIdentityParameters(m_gamma->getStyle()); + m_gamma->setParams(params); } i += 2; @@ -1857,10 +1863,6 @@ void CTFReaderGammaElt::end() { CTFReaderOpElt::end(); - // Set default alpha parameters. - const GammaOpData::Params paramsA = GammaOpData::getIdentityParameters(m_gamma->getStyle()); - m_gamma->setAlphaParams(paramsA); - // Validate the end result. try { @@ -1906,21 +1908,6 @@ bool CTFReaderGammaElt::isValid(const GammaOpData::Style style) const noexcept return false; } -void CTFReaderGammaElt_1_5::end() -{ - CTFReaderOpElt::end(); - - // Validate the end result. - try - { - getGamma()->validateParameters(); - } - catch (Exception & ce) - { - ThrowM(*this, "Invalid parameters: ", ce.what(), "."); - } -} - CTFReaderGammaParamsEltRcPtr CTFReaderGammaElt_1_5::createGammaParamsElt( const std::string & name, ContainerEltRcPtr pParent, @@ -2669,59 +2656,10 @@ bool CTFReaderLogParamsElt::parseCineon(const char ** atts, unsigned i, return false; } -void CTFReaderLogParamsElt::start(const char ** atts) +void CTFReaderLogParamsElt::setCineon(LogUtil::CTFParams & legacyParams, int chan, + double gamma, double refWhite, + double refBlack, double highlight, double shadow) { - CTFReaderLogElt * pLogElt = dynamic_cast(getParent().get()); - - LogUtil::CTFParams & legacyParams = pLogElt->getCTFParams(); - - // Attributes we want to extract. - - int chan = -1; - - // Legacy Log/Lin parameters: - double gamma = std::numeric_limits::quiet_NaN(); - double refWhite = std::numeric_limits::quiet_NaN(); - double refBlack = std::numeric_limits::quiet_NaN(); - double highlight = std::numeric_limits::quiet_NaN(); - double shadow = std::numeric_limits::quiet_NaN(); - - // Try extracting the attributes. - unsigned i = 0; - while (atts[i]) - { - if (0 == Platform::Strcasecmp(ATTR_CHAN, atts[i])) - { - if (0 == Platform::Strcasecmp("R", atts[i + 1])) - { - chan = 0; - } - else if (0 == Platform::Strcasecmp("G", atts[i + 1])) - { - chan = 1; - } - else if (0 == Platform::Strcasecmp("B", atts[i + 1])) - { - chan = 2; - } - // Chan is optional but, if present, must be legal. - else - { - std::ostringstream arg; - arg << "Illegal channel attribute value '"; - arg << atts[i + 1] << "'."; - - throwMessage(arg.str()); - } - } - else if (!parseCineon(atts, i, gamma, refWhite, refBlack, highlight, shadow)) - { - logParameterWarning(atts[i]); - } - - i += 2; - } - // Validate the attributes are appropriate for the log style and set // the parameters (numeric validation is done by LogOpData::validate). @@ -2761,8 +2699,6 @@ void CTFReaderLogParamsElt::start(const char ** atts) // Assign the parameters to the object. - auto logOp = OCIO_DYNAMIC_POINTER_CAST(pLogElt->getOp()); - switch (chan) { case -1: @@ -2782,6 +2718,62 @@ void CTFReaderLogParamsElt::start(const char ** atts) } } +void CTFReaderLogParamsElt::start(const char ** atts) +{ + CTFReaderLogElt * pLogElt = dynamic_cast(getParent().get()); + + LogUtil::CTFParams & legacyParams = pLogElt->getCTFParams(); + + // Attributes we want to extract. + + int chan = -1; + + // Legacy Log/Lin parameters: + double gamma = std::numeric_limits::quiet_NaN(); + double refWhite = std::numeric_limits::quiet_NaN(); + double refBlack = std::numeric_limits::quiet_NaN(); + double highlight = std::numeric_limits::quiet_NaN(); + double shadow = std::numeric_limits::quiet_NaN(); + + // Try extracting the attributes. + unsigned i = 0; + while (atts[i]) + { + if (0 == Platform::Strcasecmp(ATTR_CHAN, atts[i])) + { + if (0 == Platform::Strcasecmp("R", atts[i + 1])) + { + chan = 0; + } + else if (0 == Platform::Strcasecmp("G", atts[i + 1])) + { + chan = 1; + } + else if (0 == Platform::Strcasecmp("B", atts[i + 1])) + { + chan = 2; + } + // Chan is optional but, if present, must be legal. + else + { + std::ostringstream arg; + arg << "Illegal channel attribute value '"; + arg << atts[i + 1] << "'."; + + throwMessage(arg.str()); + } + } + else if (!parseCineon(atts, i, gamma, refWhite, refBlack, highlight, shadow)) + { + logParameterWarning(atts[i]); + } + + i += 2; + } + + setCineon(legacyParams, chan, gamma, refWhite, refBlack, highlight, shadow); +} + void CTFReaderLogParamsElt::end() { } @@ -2815,11 +2807,11 @@ void CTFReaderLogParamsElt_2_0::start(const char ** atts) double linearSlope = std::numeric_limits::quiet_NaN(); // Legacy Log/Lin parameters (if allowed for CTF v2 onward: - double gamma = std::numeric_limits::quiet_NaN(); - double refWhite = std::numeric_limits::quiet_NaN(); - double refBlack = std::numeric_limits::quiet_NaN(); + double gamma = std::numeric_limits::quiet_NaN(); + double refWhite = std::numeric_limits::quiet_NaN(); + double refBlack = std::numeric_limits::quiet_NaN(); double highlight = std::numeric_limits::quiet_NaN(); - double shadow = std::numeric_limits::quiet_NaN(); + double shadow = std::numeric_limits::quiet_NaN(); // Try extracting the attributes. unsigned i = 0; @@ -2902,6 +2894,12 @@ void CTFReaderLogParamsElt_2_0::start(const char ** atts) i += 2; } + if (legacyParams.getType() == LogUtil::CTFParams::CINEON) + { + setCineon(legacyParams, chan, gamma, refWhite, refBlack, highlight, shadow); + return; + } + // Validate the attributes are appropriate for the log style and set // the parameters (numeric validation is done by LogOpData::validate). @@ -2918,23 +2916,34 @@ void CTFReaderLogParamsElt_2_0::start(const char ** atts) pLogElt->setBase(base); } - if (cameraStyle) + // The LogOpData does not have a style member, so some validation needs to happen here. + + if (!IsNan(linSideBreak)) { - if (!IsNan(linSideBreak)) + if (!cameraStyle) { - newParams.push_back(linSideBreak); - } - else - { - ThrowM(*this, "Parameters '", ATTR_LINSIDEBREAK, "' should be defined for style '", + ThrowM(*this, "Parameter '", ATTR_LINSIDEBREAK, "' is only allowed for style '", LogUtil::ConvertStyleToString(LogUtil::CAMERA_LOG_TO_LIN), "' or '", LogUtil::ConvertStyleToString(LogUtil::CAMERA_LIN_TO_LOG), "'."); } + newParams.push_back(linSideBreak); + } + else if (cameraStyle) + { + ThrowM(*this, "Parameter '", ATTR_LINSIDEBREAK, "' should be defined for style '", + LogUtil::ConvertStyleToString(LogUtil::CAMERA_LOG_TO_LIN), "' or '", + LogUtil::ConvertStyleToString(LogUtil::CAMERA_LIN_TO_LOG), "'. "); + } - if (!IsNan(linearSlope)) + if (!IsNan(linearSlope)) + { + if (!cameraStyle) { - newParams.push_back(linearSlope); + ThrowM(*this, "Parameter '", ATTR_LINEARSLOPE, "' is only allowed for style '", + LogUtil::ConvertStyleToString(LogUtil::CAMERA_LOG_TO_LIN), "' or '", + LogUtil::ConvertStyleToString(LogUtil::CAMERA_LIN_TO_LOG), "'. "); } + newParams.push_back(linearSlope); } auto logOp = OCIO_DYNAMIC_POINTER_CAST(pLogElt->getOp()); diff --git a/src/OpenColorIO/fileformats/ctf/CTFReaderHelper.h b/src/OpenColorIO/fileformats/ctf/CTFReaderHelper.h index 06f6d283fd..1024b24be4 100644 --- a/src/OpenColorIO/fileformats/ctf/CTFReaderHelper.h +++ b/src/OpenColorIO/fileformats/ctf/CTFReaderHelper.h @@ -543,8 +543,6 @@ class CTFReaderGammaElt_1_5 : public CTFReaderGammaElt CTFReaderGammaElt_1_5() : CTFReaderGammaElt() {} ~CTFReaderGammaElt_1_5() {} - void end() override; - CTFReaderGammaParamsEltRcPtr createGammaParamsElt( const std::string & name, ContainerEltRcPtr pParent, @@ -730,6 +728,8 @@ class CTFReaderLogParamsElt : public XmlReaderPlainElt bool parseCineon(const char ** atts, unsigned i, double & gamma, double & refWhite, double & refBlack, double & highlight, double & shadow); + void setCineon(LogUtil::CTFParams & legacyParams, int chan, double gamma, + double refWhite, double refBlack, double highlight, double shadow); }; class CTFReaderLogParamsElt_2_0 : public CTFReaderLogParamsElt diff --git a/tests/cpu/fileformats/FileFormatCTF_tests.cpp b/tests/cpu/fileformats/FileFormatCTF_tests.cpp index c9d08c514b..2547dd5c11 100644 --- a/tests/cpu/fileformats/FileFormatCTF_tests.cpp +++ b/tests/cpu/fileformats/FileFormatCTF_tests.cpp @@ -37,24 +37,11 @@ OCIO_ADD_TEST(FileFormatCTF, missing_file) "Error opening test file."); } -OCIO_ADD_TEST(FileFormatCTF, wrong_format) -{ - OCIO::LocalCachedFileRcPtr cachedFile; - { - const std::string ctfFile("logtolin_8to8.lut"); - OCIO_CHECK_THROW_WHAT(cachedFile = LoadCLFFile(ctfFile), - OCIO::Exception, - "not a CTF/CLF file."); - OCIO_CHECK_ASSERT(!(bool)cachedFile); - } -} - -OCIO_ADD_TEST(FileFormatCTF, clf_spec) +OCIO_ADD_TEST(FileFormatCTF, clf_examples) { - // Parse examples from the specifications document S-2014-006. OCIO::LocalCachedFileRcPtr cachedFile; { - const std::string ctfFile("lut1d_example.clf"); + const std::string ctfFile("clf/lut1d_example.clf"); OCIO_CHECK_NO_THROW(cachedFile = LoadCLFFile(ctfFile)); OCIO_REQUIRE_ASSERT((bool)cachedFile); OCIO_CHECK_EQUAL(cachedFile->m_transform->getName(), @@ -62,7 +49,7 @@ OCIO_ADD_TEST(FileFormatCTF, clf_spec) OCIO_CHECK_EQUAL(cachedFile->m_transform->getID(), "exlut1"); OCIO_CHECK_EQUAL(cachedFile->m_transform->getDescriptions().size(), 1); OCIO_CHECK_EQUAL(cachedFile->m_transform->getDescriptions()[0], - " Turn 4 grey levels into 4 inverted codes using a 1D "); + "1D LUT with legal out of range values"); const OCIO::ConstOpDataVec & opList = cachedFile->m_transform->getOps(); OCIO_REQUIRE_EQUAL(opList.size(), 1); OCIO_CHECK_EQUAL(opList[0]->getType(), OCIO::OpData::Lut1DType); @@ -75,11 +62,11 @@ OCIO_ADD_TEST(FileFormatCTF, clf_spec) GetElementsValues(opList[0]->getFormatMetadata().getChildrenElements(), OCIO::TAG_DESCRIPTION, desc); OCIO_REQUIRE_EQUAL(desc.size(), 1); - OCIO_CHECK_EQUAL(desc[0], " 1D LUT "); + OCIO_CHECK_EQUAL(desc[0], "Note that the bit-depth does not constrain the legal range of values."); } { - const std::string ctfFile("lut3d_identity_12i_16f.clf"); + const std::string ctfFile("clf/lut3d_identity_12i_16f.clf"); OCIO_CHECK_NO_THROW(cachedFile = LoadCLFFile(ctfFile)); OCIO_REQUIRE_ASSERT((bool)cachedFile); OCIO_CHECK_EQUAL(cachedFile->m_transform->getName(), @@ -87,13 +74,14 @@ OCIO_ADD_TEST(FileFormatCTF, clf_spec) OCIO_CHECK_EQUAL(cachedFile->m_transform->getID(), "exlut2"); OCIO_REQUIRE_EQUAL(cachedFile->m_transform->getDescriptions().size(), 1); OCIO_CHECK_EQUAL(cachedFile->m_transform->getDescriptions()[0], - " 3D LUT example from spec "); + " 3D LUT example "); const OCIO::ConstOpDataVec & opList = cachedFile->m_transform->getOps(); OCIO_REQUIRE_EQUAL(opList.size(), 1); OCIO_CHECK_EQUAL(opList[0]->getName(), "identity"); OCIO_CHECK_EQUAL(opList[0]->getID(), "lut-24"); auto lut = OCIO::DynamicPtrCast(opList[0]); OCIO_REQUIRE_ASSERT(lut); + OCIO_CHECK_EQUAL(lut->getInterpolation(), OCIO::INTERP_TETRAHEDRAL); OCIO_CHECK_EQUAL(lut->getFileOutputBitDepth(), OCIO::BIT_DEPTH_F16); StringUtils::StringVec desc; GetElementsValues(opList[0]->getFormatMetadata().getChildrenElements(), @@ -103,7 +91,7 @@ OCIO_ADD_TEST(FileFormatCTF, clf_spec) } { - const std::string ctfFile("matrix_3x4_example.clf"); + const std::string ctfFile("clf/matrix_3x4_example.clf"); OCIO_CHECK_NO_THROW(cachedFile = LoadCLFFile(ctfFile)); OCIO_REQUIRE_ASSERT((bool)cachedFile); OCIO_CHECK_EQUAL(cachedFile->m_transform->getName(), @@ -111,7 +99,7 @@ OCIO_ADD_TEST(FileFormatCTF, clf_spec) OCIO_CHECK_EQUAL(cachedFile->m_transform->getID(), "exmat1"); OCIO_REQUIRE_EQUAL(cachedFile->m_transform->getDescriptions().size(), 2); OCIO_CHECK_EQUAL(cachedFile->m_transform->getDescriptions()[0], - " Matrix example from spec "); + " Matrix example "); OCIO_CHECK_EQUAL(cachedFile->m_transform->getDescriptions()[1], " Used by unit tests "); const OCIO::ConstOpDataVec & opList = cachedFile->m_transform->getOps(); @@ -121,17 +109,56 @@ OCIO_ADD_TEST(FileFormatCTF, clf_spec) auto mat = OCIO::DynamicPtrCast(opList[0]); OCIO_REQUIRE_ASSERT(mat); OCIO_CHECK_EQUAL(mat->getFileInputBitDepth(), OCIO::BIT_DEPTH_UINT10); - OCIO_CHECK_EQUAL(mat->getFileOutputBitDepth(), OCIO::BIT_DEPTH_UINT10); + OCIO_CHECK_EQUAL(mat->getFileOutputBitDepth(), OCIO::BIT_DEPTH_UINT12); StringUtils::StringVec desc; GetElementsValues(opList[0]->getFormatMetadata().getChildrenElements(), OCIO::TAG_DESCRIPTION, desc); OCIO_REQUIRE_EQUAL(desc.size(), 1); OCIO_CHECK_EQUAL(desc[0], " 3x4 Matrix , 4th column is offset "); + + // In file, matrix is defined by a 4x4 array. + const OCIO::ArrayDouble & array = mat->getArray(); + OCIO_CHECK_EQUAL(array.getLength(), 4); + OCIO_CHECK_EQUAL(array.getNumColorComponents(), 4); + OCIO_CHECK_EQUAL(array.getNumValues(), + array.getLength()*array.getLength()); + + const double oscale = OCIO::GetBitDepthMaxValue(OCIO::BIT_DEPTH_UINT12); + const double scale = oscale / OCIO::GetBitDepthMaxValue(OCIO::BIT_DEPTH_UINT10); + + // Check matrix ... + OCIO_REQUIRE_EQUAL(array.getValues().size(), array.getNumValues()); + OCIO_CHECK_EQUAL(array.getValues()[0] * scale, 4.80); + OCIO_CHECK_EQUAL(array.getValues()[1] * scale, 0.10); + OCIO_CHECK_EQUAL(array.getValues()[2] * scale, -0.20); + OCIO_CHECK_EQUAL(array.getValues()[3], 0.0); + + OCIO_CHECK_EQUAL(array.getValues()[4] * scale, 0.40); + OCIO_CHECK_EQUAL(array.getValues()[5] * scale, 3.50); + OCIO_CHECK_EQUAL(array.getValues()[6] * scale, 0.10); + OCIO_CHECK_EQUAL(array.getValues()[7], 0.0); + + OCIO_CHECK_EQUAL(array.getValues()[8] * scale, 0.60); + OCIO_CHECK_EQUAL(array.getValues()[9] * scale,-0.70); + OCIO_CHECK_EQUAL(array.getValues()[10] * scale, 4.20); + OCIO_CHECK_EQUAL(array.getValues()[11], 0.0); + + OCIO_CHECK_EQUAL(array.getValues()[12], 0.0); + OCIO_CHECK_EQUAL(array.getValues()[13], 0.0); + OCIO_CHECK_EQUAL(array.getValues()[14], 0.0); + OCIO_CHECK_EQUAL(array.getValues()[15], 1.0); + + const OCIO::MatrixOpData::Offsets & offsets = mat->getOffsets(); + // ... offsets. + OCIO_CHECK_EQUAL(offsets[0] * oscale, 0.30); + OCIO_CHECK_EQUAL(offsets[1] * oscale, -0.05); + OCIO_CHECK_EQUAL(offsets[2] * oscale, -0.40); + OCIO_CHECK_EQUAL(offsets[3], 0.0); } { // Test two-entries IndexMap support. - const std::string ctfFile("lut1d_indexmap_example.clf"); + const std::string ctfFile("indexMap_test_clfv2.clf"); OCIO_CHECK_NO_THROW(cachedFile = LoadCLFFile(ctfFile)); OCIO_REQUIRE_ASSERT((bool)cachedFile); OCIO_CHECK_EQUAL(cachedFile->m_transform->getName(), @@ -164,80 +191,6 @@ OCIO_ADD_TEST(FileFormatCTF, clf_spec) } } -OCIO_ADD_TEST(FileFormatCTF, lut_1d) -{ - OCIO::LocalCachedFileRcPtr cachedFile; - { - const std::string ctfFile("lut1d_32_10i_10i.ctf"); - OCIO_CHECK_NO_THROW(cachedFile = LoadCLFFile(ctfFile)); - OCIO_REQUIRE_ASSERT((bool)cachedFile); - OCIO_CHECK_EQUAL(cachedFile->m_transform->getName(), "1d-lut example"); - OCIO_CHECK_EQUAL(cachedFile->m_transform->getID(), - "9843a859-e41e-40a8-a51c-840889c3774e"); - OCIO_REQUIRE_EQUAL(cachedFile->m_transform->getDescriptions().size(), 1); - OCIO_CHECK_EQUAL(cachedFile->m_transform->getDescriptions()[0], - "Apply a 1/2.2 gamma."); - OCIO_CHECK_EQUAL(cachedFile->m_transform->getInputDescriptor(), "RGB"); - OCIO_CHECK_EQUAL(cachedFile->m_transform->getOutputDescriptor(), "RGB"); - const OCIO::ConstOpDataVec & opList = cachedFile->m_transform->getOps(); - OCIO_REQUIRE_EQUAL(opList.size(), 1); - - auto pLut = std::dynamic_pointer_cast(opList[0]); - OCIO_REQUIRE_ASSERT(pLut); - - StringUtils::StringVec desc; - GetElementsValues(pLut->getFormatMetadata().getChildrenElements(), - OCIO::TAG_DESCRIPTION, desc); - OCIO_REQUIRE_EQUAL(desc.size(), 1); - - OCIO_CHECK_ASSERT(!pLut->isInputHalfDomain()); - OCIO_CHECK_ASSERT(!pLut->isOutputRawHalfs()); - OCIO_CHECK_EQUAL(pLut->getHueAdjust(), OCIO::HUE_NONE); - - OCIO_CHECK_EQUAL(pLut->getFileOutputBitDepth(), OCIO::BIT_DEPTH_UINT10); - OCIO_CHECK_ASSERT(pLut->getName() == "1d-lut example op"); - - // TODO: bypass is for CTF - // OCIO_CHECK_ASSERT(!pLut->getBypass()->isDynamic()); - - // LUT is defined with a 32x1 array. - // Array is extended to 32x3 by duplicating the available component. - const OCIO::Array & array = pLut->getArray(); - OCIO_CHECK_EQUAL(array.getLength(), 32); - OCIO_CHECK_EQUAL(array.getNumColorComponents(), 1); - OCIO_CHECK_EQUAL(array.getNumValues(), - array.getLength() - *pLut->getArray().getMaxColorComponents()); - - OCIO_REQUIRE_EQUAL(array.getValues().size(), 96); - OCIO_CHECK_EQUAL(array.getValues()[0], 0.0f); - OCIO_CHECK_EQUAL(array.getValues()[1], 0.0f); - OCIO_CHECK_EQUAL(array.getValues()[2], 0.0f); - OCIO_CHECK_EQUAL(array.getValues()[3], 215.0f / 1023.0f); - OCIO_CHECK_EQUAL(array.getValues()[4], 215.0f / 1023.0f); - OCIO_CHECK_EQUAL(array.getValues()[5], 215.0f / 1023.0f); - OCIO_CHECK_EQUAL(array.getValues()[6], 294.0f / 1023.0f); - // and many more - OCIO_CHECK_EQUAL(array.getValues()[92], 1008.0f / 1023.0f); - OCIO_CHECK_EQUAL(array.getValues()[93], 1023.0f / 1023.0f); - OCIO_CHECK_EQUAL(array.getValues()[94], 1023.0f / 1023.0f); - OCIO_CHECK_EQUAL(array.getValues()[95], 1023.0f / 1023.0f); - } - - // Test the hue adjust attribute. - { - const std::string ctfFile("lut1d_hue_adjust_test.ctf"); - OCIO_CHECK_NO_THROW(cachedFile = LoadCLFFile(ctfFile)); - OCIO_REQUIRE_ASSERT((bool)cachedFile); - - const OCIO::ConstOpDataVec & opList = cachedFile->m_transform->getOps(); - OCIO_REQUIRE_EQUAL(opList.size(), 1); - auto pLut = std::dynamic_pointer_cast(opList[0]); - OCIO_REQUIRE_ASSERT(pLut); - OCIO_CHECK_EQUAL(pLut->getHueAdjust(), OCIO::HUE_DW3); - } -} - OCIO_ADD_TEST(FileFormatCTF, matrix4x4) { OCIO::LocalCachedFileRcPtr cachedFile; @@ -297,6 +250,65 @@ OCIO_ADD_TEST(FileFormatCTF, matrix4x4) OCIO_CHECK_EQUAL(offsets[3], 0.0); } +OCIO_ADD_TEST(FileFormatCTF, matrix_with_offset) +{ + OCIO::LocalCachedFileRcPtr cachedFile; + const std::string ctfFile("matrix_offsets_example.ctf"); + OCIO_CHECK_NO_THROW(cachedFile = LoadCLFFile(ctfFile)); + OCIO_REQUIRE_ASSERT((bool)cachedFile); + // Note that the ProcessList does not have a version attribute and + // therefore defaults to 1.2. + // The "4x4x3" Array syntax is only allowed in versions 1.2 or earlier. + const OCIO::CTFVersion ctfVersion = + cachedFile->m_transform->getCTFVersion(); + OCIO_CHECK_EQUAL(OCIO::CTF_PROCESS_LIST_VERSION_1_2, ctfVersion); + + const OCIO::ConstOpDataVec & opList = cachedFile->m_transform->getOps(); + OCIO_REQUIRE_EQUAL(opList.size(), 1); + auto pMatrix = std::dynamic_pointer_cast(opList[0]); + OCIO_REQUIRE_ASSERT(pMatrix); + + const OCIO::ArrayDouble & array = pMatrix->getArray(); + OCIO_CHECK_EQUAL(array.getLength(), 4); + OCIO_CHECK_EQUAL(array.getNumColorComponents(), 4); + OCIO_CHECK_EQUAL(array.getNumValues(), + array.getLength()*array.getLength()); + + OCIO_REQUIRE_EQUAL(array.getValues().size(), array.getNumValues()); + OCIO_CHECK_EQUAL(array.getValues()[0], 3.24); + OCIO_CHECK_EQUAL(array.getValues()[1], -1.537); + OCIO_CHECK_EQUAL(array.getValues()[2], -0.49850); + OCIO_CHECK_EQUAL(array.getValues()[3], 0.0); + + OCIO_CHECK_EQUAL(array.getValues()[4], -0.96930); + OCIO_CHECK_EQUAL(array.getValues()[5], 1.876); + OCIO_CHECK_EQUAL(array.getValues()[6], 0.04156); + OCIO_CHECK_EQUAL(array.getValues()[7], 0.0); + + OCIO_CHECK_EQUAL(array.getValues()[8], 0.05560); + OCIO_CHECK_EQUAL(array.getValues()[9], -0.204); + OCIO_CHECK_EQUAL(array.getValues()[10], 1.0573); + OCIO_CHECK_EQUAL(array.getValues()[11], 0.0); + + OCIO_CHECK_EQUAL(array.getValues()[12], 0.0); + OCIO_CHECK_EQUAL(array.getValues()[13], 0.0); + OCIO_CHECK_EQUAL(array.getValues()[14], 0.0); + OCIO_CHECK_EQUAL(array.getValues()[15], 1.0); + + OCIO_CHECK_EQUAL(pMatrix->getOffsets()[0], 1.0); + OCIO_CHECK_EQUAL(pMatrix->getOffsets()[1], 2.0); + OCIO_CHECK_EQUAL(pMatrix->getOffsets()[2], 3.0); +} + +OCIO_ADD_TEST(FileFormatCTF, matrix_with_offset_1_3) +{ + // Matrix 4 4 3 only valid up to version 1.2. + const std::string ctfFile("matrix_offsets_example_1_3.ctf"); + OCIO_CHECK_THROW_WHAT(LoadCLFFile(ctfFile), + OCIO::Exception, + "Illegal array dimensions 4 4 3"); +} + OCIO_ADD_TEST(FileFormatCTF, matrix_1_3_3x3) { // Version 1.3, array 3x3x3: matrix with no alpha and no offsets. @@ -614,67 +626,237 @@ OCIO_ADD_TEST(FileFormatCTF, matrix_identity) CheckIdentity(ctf, __LINE__); } -OCIO_ADD_TEST(FileFormatCTF, 3by1d_lut) +OCIO_ADD_TEST(FileFormatCTF, lut_1d) { OCIO::LocalCachedFileRcPtr cachedFile; - const std::string ctfFile("xyz_to_rgb.clf"); - OCIO_CHECK_NO_THROW(cachedFile = LoadCLFFile(ctfFile)); - OCIO_REQUIRE_ASSERT((bool)cachedFile); - - const OCIO::ConstOpDataVec & opList = cachedFile->m_transform->getOps(); - OCIO_REQUIRE_EQUAL(opList.size(), 2); - auto pMatrix = std::dynamic_pointer_cast(opList[0]); - OCIO_REQUIRE_ASSERT(pMatrix); + { + const std::string ctfFile("lut1d_32_10i_10i.ctf"); + OCIO_CHECK_NO_THROW(cachedFile = LoadCLFFile(ctfFile)); + OCIO_REQUIRE_ASSERT((bool)cachedFile); + OCIO_CHECK_EQUAL(cachedFile->m_transform->getName(), "1d-lut example"); + OCIO_CHECK_EQUAL(cachedFile->m_transform->getID(), + "9843a859-e41e-40a8-a51c-840889c3774e"); + OCIO_REQUIRE_EQUAL(cachedFile->m_transform->getDescriptions().size(), 1); + OCIO_CHECK_EQUAL(cachedFile->m_transform->getDescriptions()[0], + "Apply a 1/2.2 gamma."); + OCIO_CHECK_EQUAL(cachedFile->m_transform->getInputDescriptor(), "RGB"); + OCIO_CHECK_EQUAL(cachedFile->m_transform->getOutputDescriptor(), "RGB"); + const OCIO::ConstOpDataVec & opList = cachedFile->m_transform->getOps(); + OCIO_REQUIRE_EQUAL(opList.size(), 1); - const OCIO::ArrayDouble & a1 = pMatrix->getArray(); - OCIO_CHECK_EQUAL(a1.getLength(), 4); - OCIO_CHECK_EQUAL(a1.getNumColorComponents(), 4); - OCIO_CHECK_EQUAL(a1.getNumValues(), a1.getLength()*a1.getLength()); + auto pLut = std::dynamic_pointer_cast(opList[0]); + OCIO_REQUIRE_ASSERT(pLut); - OCIO_REQUIRE_EQUAL(a1.getValues().size(), a1.getNumValues()); - OCIO_CHECK_EQUAL(a1.getValues()[0], 3.24); - OCIO_CHECK_EQUAL(a1.getValues()[1], -1.537); - OCIO_CHECK_EQUAL(a1.getValues()[2], -0.49850); - OCIO_CHECK_EQUAL(a1.getValues()[3], 0.0); + StringUtils::StringVec desc; + GetElementsValues(pLut->getFormatMetadata().getChildrenElements(), + OCIO::TAG_DESCRIPTION, desc); + OCIO_REQUIRE_EQUAL(desc.size(), 1); - OCIO_CHECK_EQUAL(a1.getValues()[4], -0.96930); - OCIO_CHECK_EQUAL(a1.getValues()[5], 1.876); - OCIO_CHECK_EQUAL(a1.getValues()[6], 0.04156); - OCIO_CHECK_EQUAL(a1.getValues()[7], 0.0); + OCIO_CHECK_ASSERT(!pLut->isInputHalfDomain()); + OCIO_CHECK_ASSERT(!pLut->isOutputRawHalfs()); + OCIO_CHECK_EQUAL(pLut->getHueAdjust(), OCIO::HUE_NONE); - OCIO_CHECK_EQUAL(a1.getValues()[8], 0.05560); - OCIO_CHECK_EQUAL(a1.getValues()[9], -0.204); - OCIO_CHECK_EQUAL(a1.getValues()[10], 1.0573); - OCIO_CHECK_EQUAL(a1.getValues()[11], 0.0); + OCIO_CHECK_EQUAL(pLut->getFileOutputBitDepth(), OCIO::BIT_DEPTH_UINT10); + OCIO_CHECK_ASSERT(pLut->getName() == "1d-lut example op"); - OCIO_CHECK_EQUAL(a1.getValues()[12], 0.0); - OCIO_CHECK_EQUAL(a1.getValues()[13], 0.0); - OCIO_CHECK_EQUAL(a1.getValues()[14], 0.0); - OCIO_CHECK_EQUAL(a1.getValues()[15], 1.0); + // TODO: bypass is for CTF + // OCIO_CHECK_ASSERT(!pLut->getBypass()->isDynamic()); - auto pLut = - std::dynamic_pointer_cast(opList[1]); - OCIO_REQUIRE_ASSERT(pLut); - OCIO_CHECK_EQUAL(pLut->getDirection(), OCIO::TRANSFORM_DIR_FORWARD); - OCIO_CHECK_EQUAL(pLut->getFileOutputBitDepth(), OCIO::BIT_DEPTH_F32); + // LUT is defined with a 32x1 array. + // Array is extended to 32x3 by duplicating the available component. + const OCIO::Array & array = pLut->getArray(); + OCIO_CHECK_EQUAL(array.getLength(), 32); + OCIO_CHECK_EQUAL(array.getNumColorComponents(), 1); + OCIO_CHECK_EQUAL(array.getNumValues(), + array.getLength() + *pLut->getArray().getMaxColorComponents()); - const OCIO::Array & a2 = pLut->getArray(); - OCIO_CHECK_EQUAL(a2.getLength(), 17); - OCIO_CHECK_EQUAL(a2.getNumColorComponents(), 3); - OCIO_CHECK_EQUAL(a2.getNumValues(), - a2.getLength()*pLut->getArray().getMaxColorComponents()); + OCIO_REQUIRE_EQUAL(array.getValues().size(), 96); + OCIO_CHECK_EQUAL(array.getValues()[0], 0.0f); + OCIO_CHECK_EQUAL(array.getValues()[1], 0.0f); + OCIO_CHECK_EQUAL(array.getValues()[2], 0.0f); + OCIO_CHECK_EQUAL(array.getValues()[3], 215.0f / 1023.0f); + OCIO_CHECK_EQUAL(array.getValues()[4], 215.0f / 1023.0f); + OCIO_CHECK_EQUAL(array.getValues()[5], 215.0f / 1023.0f); + OCIO_CHECK_EQUAL(array.getValues()[6], 294.0f / 1023.0f); + // and many more + OCIO_CHECK_EQUAL(array.getValues()[92], 1008.0f / 1023.0f); + OCIO_CHECK_EQUAL(array.getValues()[93], 1023.0f / 1023.0f); + OCIO_CHECK_EQUAL(array.getValues()[94], 1023.0f / 1023.0f); + OCIO_CHECK_EQUAL(array.getValues()[95], 1023.0f / 1023.0f); + } - OCIO_REQUIRE_EQUAL(a2.getValues().size(), a2.getNumValues()); - OCIO_CHECK_EQUAL(a2.getValues()[0], 0.0f); - OCIO_CHECK_EQUAL(a2.getValues()[1], 0.0f); - OCIO_CHECK_EQUAL(a2.getValues()[2], 0.0f); - OCIO_CHECK_EQUAL(a2.getValues()[3], 0.28358f); + // Test the hue adjust attribute. + { + const std::string ctfFile("lut1d_hue_adjust_test.ctf"); + OCIO_CHECK_NO_THROW(cachedFile = LoadCLFFile(ctfFile)); + OCIO_REQUIRE_ASSERT((bool)cachedFile); - OCIO_CHECK_EQUAL(a2.getValues()[21], 0.68677f); - OCIO_CHECK_EQUAL(a2.getValues()[22], 0.68677f); - OCIO_CHECK_EQUAL(a2.getValues()[23], 0.68677f); + const OCIO::ConstOpDataVec & opList = cachedFile->m_transform->getOps(); + OCIO_REQUIRE_EQUAL(opList.size(), 1); + auto pLut = std::dynamic_pointer_cast(opList[0]); + OCIO_REQUIRE_ASSERT(pLut); + OCIO_CHECK_EQUAL(pLut->getHueAdjust(), OCIO::HUE_DW3); + } +} - OCIO_CHECK_EQUAL(a2.getValues()[48], 1.0f); +OCIO_ADD_TEST(FileFormatCTF, lut1d_hue_adjust_invalid_style) +{ + const std::string ctfFile("lut1d_hue_adjust_invalid_style.ctf"); + OCIO_CHECK_THROW_WHAT(LoadCLFFile(ctfFile), OCIO::Exception, + "Illegal 'hueAdjust' attribute"); +} + +OCIO_ADD_TEST(FileFormatCTF, lut_3by1d_with_nan_infinity) +{ + OCIO::LocalCachedFileRcPtr cachedFile; + const std::string ctfFile("clf/lut3by1d_nan_infinity_example.clf"); + OCIO_CHECK_NO_THROW(cachedFile = LoadCLFFile(ctfFile)); + OCIO_REQUIRE_ASSERT((bool)cachedFile); + + const OCIO::ConstOpDataVec & opList = cachedFile->m_transform->getOps(); + OCIO_REQUIRE_EQUAL(opList.size(), 1); + auto pLut1d = std::dynamic_pointer_cast(opList[0]); + OCIO_REQUIRE_ASSERT(pLut1d); + + const OCIO::Array & array = pLut1d->getArray(); + + OCIO_REQUIRE_EQUAL(array.getValues().size(), array.getNumValues()); + OCIO_CHECK_ASSERT(OCIO::IsNan(array.getValues()[0])); + OCIO_CHECK_ASSERT(OCIO::IsNan(array.getValues()[1])); + OCIO_CHECK_ASSERT(OCIO::IsNan(array.getValues()[2])); + OCIO_CHECK_ASSERT(OCIO::IsNan(array.getValues()[3])); + OCIO_CHECK_ASSERT(OCIO::IsNan(array.getValues()[4])); + OCIO_CHECK_EQUAL(array.getValues()[5], + std::numeric_limits::infinity()); + OCIO_CHECK_EQUAL(array.getValues()[6], + std::numeric_limits::infinity()); + OCIO_CHECK_EQUAL(array.getValues()[7], + std::numeric_limits::infinity()); + OCIO_CHECK_EQUAL(array.getValues()[8], + -std::numeric_limits::infinity()); + OCIO_CHECK_EQUAL(array.getValues()[9], + -std::numeric_limits::infinity()); +} + +OCIO_ADD_TEST(FileFormatCTF, lut1d_half_domain_set_false) +{ + // Should throw an exception because the 'half_domain' tag + // was found but set to something other than 'true'. + const std::string ctfFile("clf/illegal/lut1d_half_domain_set_false.clf"); + OCIO_CHECK_THROW_WHAT(LoadCLFFile(ctfFile), + OCIO::Exception, + "Illegal 'halfDomain' attribute"); +} + +OCIO_ADD_TEST(FileFormatCTF, lut1d_raw_half_set_false) +{ + // Should throw an exception because the 'raw_halfs' tag + // was found but set to something other than 'true'. + const std::string ctfFile("clf/illegal/lut1d_raw_half_set_false.clf"); + OCIO_CHECK_THROW_WHAT(LoadCLFFile(ctfFile), + OCIO::Exception, + "Illegal 'rawHalfs' attribute"); +} + +OCIO_ADD_TEST(FileFormatCTF, lut1d_half_domain_raw_half_set) +{ + OCIO::LocalCachedFileRcPtr cachedFile; + const std::string ctfFile("clf/lut1d_half_domain_raw_half_set.clf"); + OCIO_CHECK_NO_THROW(cachedFile = LoadCLFFile(ctfFile)); + OCIO_REQUIRE_ASSERT((bool)cachedFile); + + const OCIO::ConstOpDataVec & opList = cachedFile->m_transform->getOps(); + OCIO_REQUIRE_EQUAL(opList.size(), 1); + auto pLut1d = std::dynamic_pointer_cast(opList[0]); + OCIO_REQUIRE_ASSERT(pLut1d); + + OCIO_CHECK_ASSERT(pLut1d->isInputHalfDomain()); + OCIO_CHECK_ASSERT(pLut1d->isOutputRawHalfs()); + + OCIO_CHECK_EQUAL(pLut1d->getArray().getValues()[0] * 1023.0f, + OCIO::ConvertHalfBitsToFloat(0)); + OCIO_CHECK_EQUAL(pLut1d->getArray().getValues()[3] * 1023.0f, + OCIO::ConvertHalfBitsToFloat(215)); + OCIO_CHECK_EQUAL(pLut1d->getArray().getValues()[6] * 1023.0f, + OCIO::ConvertHalfBitsToFloat(294)); + OCIO_CHECK_EQUAL(pLut1d->getArray().getValues()[9] * 1023.0f, + OCIO::ConvertHalfBitsToFloat(354)); + OCIO_CHECK_EQUAL(pLut1d->getArray().getValues()[12] * 1023.0f, + OCIO::ConvertHalfBitsToFloat(403)); +} + +OCIO_ADD_TEST(FileFormatCTF, lut1d_half_domain_missing_values) +{ + const std::string ctfFile("clf/illegal/lut1d_half_domain_missing_values.clf"); + // This should fail with invalid entries exception because the number + // of entries in the op is not 65536 (required when using half domain). + OCIO_CHECK_THROW_WHAT(LoadCLFFile(ctfFile), + OCIO::Exception, + "65536 required for halfDomain"); +} + +OCIO_ADD_TEST(FileFormatCTF, 3by1d_lut) +{ + OCIO::LocalCachedFileRcPtr cachedFile; + const std::string ctfFile("clf/xyz_to_rgb.clf"); + OCIO_CHECK_NO_THROW(cachedFile = LoadCLFFile(ctfFile)); + OCIO_REQUIRE_ASSERT((bool)cachedFile); + + const OCIO::ConstOpDataVec & opList = cachedFile->m_transform->getOps(); + OCIO_REQUIRE_EQUAL(opList.size(), 2); + auto pMatrix = std::dynamic_pointer_cast(opList[0]); + OCIO_REQUIRE_ASSERT(pMatrix); + + const OCIO::ArrayDouble & a1 = pMatrix->getArray(); + OCIO_CHECK_EQUAL(a1.getLength(), 4); + OCIO_CHECK_EQUAL(a1.getNumColorComponents(), 4); + OCIO_CHECK_EQUAL(a1.getNumValues(), a1.getLength()*a1.getLength()); + + OCIO_REQUIRE_EQUAL(a1.getValues().size(), a1.getNumValues()); + OCIO_CHECK_EQUAL(a1.getValues()[0], 3.24); + OCIO_CHECK_EQUAL(a1.getValues()[1], -1.537); + OCIO_CHECK_EQUAL(a1.getValues()[2], -0.49850); + OCIO_CHECK_EQUAL(a1.getValues()[3], 0.0); + + OCIO_CHECK_EQUAL(a1.getValues()[4], -0.96930); + OCIO_CHECK_EQUAL(a1.getValues()[5], 1.876); + OCIO_CHECK_EQUAL(a1.getValues()[6], 0.04156); + OCIO_CHECK_EQUAL(a1.getValues()[7], 0.0); + + OCIO_CHECK_EQUAL(a1.getValues()[8], 0.05560); + OCIO_CHECK_EQUAL(a1.getValues()[9], -0.204); + OCIO_CHECK_EQUAL(a1.getValues()[10], 1.0573); + OCIO_CHECK_EQUAL(a1.getValues()[11], 0.0); + + OCIO_CHECK_EQUAL(a1.getValues()[12], 0.0); + OCIO_CHECK_EQUAL(a1.getValues()[13], 0.0); + OCIO_CHECK_EQUAL(a1.getValues()[14], 0.0); + OCIO_CHECK_EQUAL(a1.getValues()[15], 1.0); + + auto pLut = + std::dynamic_pointer_cast(opList[1]); + OCIO_REQUIRE_ASSERT(pLut); + OCIO_CHECK_EQUAL(pLut->getDirection(), OCIO::TRANSFORM_DIR_FORWARD); + OCIO_CHECK_EQUAL(pLut->getFileOutputBitDepth(), OCIO::BIT_DEPTH_F32); + + const OCIO::Array & a2 = pLut->getArray(); + OCIO_CHECK_EQUAL(a2.getLength(), 17); + OCIO_CHECK_EQUAL(a2.getNumColorComponents(), 3); + OCIO_CHECK_EQUAL(a2.getNumValues(), + a2.getLength()*pLut->getArray().getMaxColorComponents()); + + OCIO_REQUIRE_EQUAL(a2.getValues().size(), a2.getNumValues()); + OCIO_CHECK_EQUAL(a2.getValues()[0], 0.0f); + OCIO_CHECK_EQUAL(a2.getValues()[1], 0.0f); + OCIO_CHECK_EQUAL(a2.getValues()[2], 0.0f); + OCIO_CHECK_EQUAL(a2.getValues()[3], 0.28358f); + + OCIO_CHECK_EQUAL(a2.getValues()[21], 0.68677f); + OCIO_CHECK_EQUAL(a2.getValues()[22], 0.68677f); + OCIO_CHECK_EQUAL(a2.getValues()[23], 0.68677f); + + OCIO_CHECK_EQUAL(a2.getValues()[48], 1.0f); OCIO_CHECK_EQUAL(a2.getValues()[49], 1.0f); OCIO_CHECK_EQUAL(a2.getValues()[50], 1.0f); } @@ -766,7 +948,7 @@ OCIO::LocalCachedFileRcPtr ParseString(const std::string & str) OCIO_ADD_TEST(FileFormatCTF, invlut1d_clf) { const std::string clf{ R"( - + 0 1 2 @@ -791,13 +973,13 @@ OCIO_ADD_TEST(FileFormatCTF, invlut1d_clf) )" }; OCIO_CHECK_THROW_WHAT(ParseString(clf), OCIO::Exception, - "CLF file version '2' does not support operator 'InverseLUT1D'"); + "CLF file version '3' does not support operator 'InverseLUT1D'"); } OCIO_ADD_TEST(FileFormatCTF, lut3d) { OCIO::LocalCachedFileRcPtr cachedFile; - const std::string ctfFile("lut3d_17x17x17_32f_12i.clf"); + const std::string ctfFile("clf/lut3d_17x17x17_10i_12i.clf"); OCIO_CHECK_NO_THROW(cachedFile = LoadCLFFile(ctfFile)); OCIO_REQUIRE_ASSERT((bool)cachedFile); @@ -808,6 +990,8 @@ OCIO_ADD_TEST(FileFormatCTF, lut3d) OCIO_REQUIRE_ASSERT(pLut); OCIO_CHECK_EQUAL(pLut->getDirection(), OCIO::TRANSFORM_DIR_FORWARD); OCIO_CHECK_EQUAL(pLut->getFileOutputBitDepth(), OCIO::BIT_DEPTH_UINT12); + // Interpolation is not defined in the file. + OCIO_CHECK_EQUAL(pLut->getInterpolation(), OCIO::INTERP_DEFAULT); const OCIO::Array & array = pLut->getArray(); OCIO_CHECK_EQUAL(array.getLength(), 17); @@ -818,17 +1002,18 @@ OCIO_ADD_TEST(FileFormatCTF, lut3d) *pLut->getArray().getMaxColorComponents()); OCIO_REQUIRE_EQUAL(array.getValues().size(), array.getNumValues()); - OCIO_CHECK_EQUAL(array.getValues()[0], 10.0f / 4095.0f); - OCIO_CHECK_EQUAL(array.getValues()[1], 0.0f); - OCIO_CHECK_EQUAL(array.getValues()[2], 5.0f / 4095.0f); + const float tol = 2e-8f; + OCIO_CHECK_CLOSE(array.getValues()[0], 0.0f / 4095.0f, tol); + OCIO_CHECK_CLOSE(array.getValues()[1], 12.0f / 4095.0f, tol); + OCIO_CHECK_CLOSE(array.getValues()[2], 13.0f / 4095.0f, tol); - OCIO_CHECK_CLOSE(array.getValues()[18], 26.0f / 4095.0f, 1e-8f); - OCIO_CHECK_EQUAL(array.getValues()[19], 308.0f / 4095.0f); - OCIO_CHECK_EQUAL(array.getValues()[20], 580.0f / 4095.0f); + OCIO_CHECK_CLOSE(array.getValues()[18], 0.0f / 4095.0f, tol); + OCIO_CHECK_CLOSE(array.getValues()[19], 203.0f / 4095.0f, tol); + OCIO_CHECK_CLOSE(array.getValues()[20], 399.0f / 4095.0f, tol); - OCIO_CHECK_EQUAL(array.getValues()[30], 0.0f); - OCIO_CHECK_EQUAL(array.getValues()[31], 586.0f / 4095.0f); - OCIO_CHECK_EQUAL(array.getValues()[32], 1350.0f / 4095.0f); + OCIO_CHECK_CLOSE(array.getValues()[30], 54.0f / 4095.0f, tol); + OCIO_CHECK_CLOSE(array.getValues()[31], 490.0f / 4095.0f, tol); + OCIO_CHECK_CLOSE(array.getValues()[32], 987.0f / 4095.0f, tol); } OCIO_ADD_TEST(FileFormatCTF, lut3d_inv) @@ -870,10 +1055,77 @@ OCIO_ADD_TEST(FileFormatCTF, lut3d_inv) OCIO_CHECK_EQUAL(array.getValues()[32], 1350.0f / 4095.0f); } +OCIO_ADD_TEST(FileFormatCTF, lut3d_unequal_size) +{ + std::string fileName("clf/illegal/lut3d_unequal_size.clf"); + OCIO_CHECK_THROW_WHAT(LoadCLFFile(fileName), OCIO::Exception, + "Illegal array dimensions 2 2 3 3"); +} + +OCIO_ADD_TEST(FileFormatCTF, tabluation_support) +{ + OCIO::LocalCachedFileRcPtr cachedFile; + // This clf file contains tabulations used as delimiters for a + // series of numbers. + const std::string ctfFile("clf/tabulation_support.clf"); + OCIO_CHECK_NO_THROW(cachedFile = LoadCLFFile(ctfFile)); + const OCIO::ConstOpDataVec & opList = cachedFile->m_transform->getOps(); + OCIO_CHECK_EQUAL(cachedFile->m_transform->getID(), "e0a0ae4b-adc2-4c25-ad70-fa6f31ba219d"); + OCIO_REQUIRE_EQUAL(opList.size(), 1); + + auto pL = std::dynamic_pointer_cast(opList[0]); + OCIO_REQUIRE_ASSERT(pL); + + OCIO_CHECK_EQUAL(pL->getFileOutputBitDepth(), OCIO::BIT_DEPTH_UINT10); + OCIO_CHECK_EQUAL(pL->getInterpolation(), OCIO::INTERP_LINEAR); + + const OCIO::Array & array = pL->getArray(); + OCIO_CHECK_EQUAL(array.getLength(), 3U); + OCIO_CHECK_EQUAL(array.getNumColorComponents(), 3U); + OCIO_CHECK_EQUAL(array.getNumValues(), 81U); + OCIO_REQUIRE_EQUAL(array.getValues().size(), 81U); + + const float scale = (float)OCIO::GetBitDepthMaxValue(OCIO::BIT_DEPTH_UINT10); + OCIO_CHECK_EQUAL(array.getValues()[0] * scale,-60.0f); + OCIO_CHECK_EQUAL(array.getValues()[1] * scale, 5.0f); + OCIO_CHECK_EQUAL(array.getValues()[2] * scale, 75.0f); + + OCIO_CHECK_EQUAL(array.getValues()[3] * scale, -10.0f); + OCIO_CHECK_CLOSE(array.getValues()[4] * scale, 50.0f, 1e-5f); + OCIO_CHECK_CLOSE(array.getValues()[5] * scale, 400.0f, 1e-4f); + + OCIO_CHECK_EQUAL(array.getValues()[6] * scale, 0.0f); + OCIO_CHECK_CLOSE(array.getValues()[7] * scale, 100.0f, 1e-4f); + OCIO_CHECK_EQUAL(array.getValues()[8] * scale, 1200.0f); + + OCIO_CHECK_EQUAL(array.getValues()[9] * scale, -40.0f); + OCIO_CHECK_EQUAL(array.getValues()[10] * scale, 500.0f); + OCIO_CHECK_EQUAL(array.getValues()[11] * scale, -30.0f); + + OCIO_CHECK_EQUAL(array.getValues()[3 * 26 + 0] * scale, 1110.0f); + OCIO_CHECK_EQUAL(array.getValues()[3 * 26 + 1] * scale, 900.0f); + OCIO_CHECK_EQUAL(array.getValues()[3 * 26 + 2] * scale, 1200.0f); +} + +OCIO_ADD_TEST(FileFormatCTF, matrix_windows_eol) +{ + OCIO::LocalCachedFileRcPtr cachedFile; + // This file uses windows end of line character and does not start + // with the ?xml header. + const std::string ctfFile("clf/matrix_windows.clf"); + OCIO_CHECK_NO_THROW(cachedFile = LoadCLFFile(ctfFile)); + const OCIO::ConstOpDataVec & opList = cachedFile->m_transform->getOps(); + OCIO_CHECK_EQUAL(cachedFile->m_transform->getID(), "42"); + OCIO_REQUIRE_EQUAL(opList.size(), 1); + OCIO_CHECK_EQUAL(opList[0]->getType(), OCIO::OpData::MatrixType); + OCIO_CHECK_EQUAL(opList[0]->getID(), ""); + OCIO_CHECK_EQUAL(opList[0]->getName(), "identity matrix"); +} + OCIO_ADD_TEST(FileFormatCTF, check_utf8) { OCIO::LocalCachedFileRcPtr cachedFile; - const std::string ctfFile("matrix_example_utf8.clf"); + const std::string ctfFile("clf/matrix_example_utf8.clf"); OCIO_CHECK_NO_THROW(cachedFile = LoadCLFFile(ctfFile)); OCIO_REQUIRE_ASSERT((bool)cachedFile); @@ -894,152 +1146,199 @@ OCIO_ADD_TEST(FileFormatCTF, check_utf8) } -OCIO_ADD_TEST(FileFormatCTF, error_checker) +OCIO_ADD_TEST(FileFormatCTF, info_example) { OCIO::LocalCachedFileRcPtr cachedFile; + const std::string ctfFile("clf/info_example.clf"); + OCIO_CHECK_NO_THROW(cachedFile = LoadCLFFile(ctfFile)); + OCIO_REQUIRE_ASSERT((bool)cachedFile); - { - constexpr static const char ErrorOutputs[3][1024] = - { - "(34): Unrecognized element 'B' where its parent is 'ProcessList' (2): Unknown element", - "(34): Unrecognized element 'C' where its parent is 'B' (34)", - "(36): Unrecognized element 'A' where its parent is 'Description' (36)" - }; - - OCIO::LogGuard guard; - OCIO::SetLoggingLevel(OCIO::LOGGING_LEVEL_WARNING); - - // NB: This file has some added unknown elements A, B, and C as a test. - const std::string ctfFile("unknown_elements.clf"); - OCIO_CHECK_NO_THROW(cachedFile = LoadCLFFile(ctfFile)); - OCIO_REQUIRE_ASSERT((bool)cachedFile); - - const StringUtils::StringVec parts = StringUtils::SplitByLines(StringUtils::RightTrim(guard.output())); - OCIO_REQUIRE_EQUAL(parts.size(), 3); - - for (size_t i = 0; i < parts.size(); ++i) - { - OCIO_CHECK_NE(std::string::npos, StringUtils::Find(parts[i], ErrorOutputs[i])); - } - } + OCIO_CHECK_EQUAL(cachedFile->m_transform->getDescriptions().size(), 2); + OCIO_CHECK_EQUAL(cachedFile->m_transform->getDescriptions()[0], + "Example of using the Info element"); + OCIO_CHECK_EQUAL(cachedFile->m_transform->getDescriptions()[1], + "A second description"); + OCIO_CHECK_EQUAL(cachedFile->m_transform->getInputDescriptor(), + "input desc"); + OCIO_CHECK_EQUAL(cachedFile->m_transform->getOutputDescriptor(), + "output desc"); + // Ensure ops were not affected by metadata parsing. const OCIO::ConstOpDataVec & opList = cachedFile->m_transform->getOps(); - OCIO_REQUIRE_EQUAL(opList.size(), 4); + OCIO_REQUIRE_EQUAL(opList.size(), 1); - auto pMatrix = std::dynamic_pointer_cast(opList[0]); + auto pMatrix = + std::dynamic_pointer_cast(opList[0]); OCIO_REQUIRE_ASSERT(pMatrix); + OCIO_CHECK_EQUAL(pMatrix->getName(), "identity"); - const OCIO::ArrayDouble & a1 = pMatrix->getArray(); - OCIO_CHECK_EQUAL(a1.getLength(), 4); - OCIO_CHECK_EQUAL(a1.getNumColorComponents(), 4); - OCIO_CHECK_EQUAL(a1.getNumValues(), a1.getLength()*a1.getLength()); + OCIO_CHECK_EQUAL(pMatrix->getFileInputBitDepth(), OCIO::BIT_DEPTH_F32); + OCIO_CHECK_EQUAL(pMatrix->getFileOutputBitDepth(), OCIO::BIT_DEPTH_UINT12); - OCIO_REQUIRE_EQUAL(a1.getValues().size(), a1.getNumValues()); - OCIO_CHECK_EQUAL(a1.getValues()[0], 3.24); - OCIO_CHECK_EQUAL(a1.getValues()[1], -1.537); - OCIO_CHECK_EQUAL(a1.getValues()[2], -0.49850); - OCIO_CHECK_EQUAL(a1.getValues()[3], 0.0); + const OCIO::FormatMetadataImpl & info = cachedFile->m_transform->getInfoMetadata(); - OCIO_CHECK_EQUAL(a1.getValues()[4], -0.96930); - OCIO_CHECK_EQUAL(a1.getValues()[5], 1.876); - OCIO_CHECK_EQUAL(a1.getValues()[6], 0.04156); - OCIO_CHECK_EQUAL(a1.getValues()[7], 0.0); + // Check element values. + // + OCIO_CHECK_EQUAL(std::string(info.getName()), OCIO::METADATA_INFO); + auto items = info.getChildrenElements(); + OCIO_REQUIRE_EQUAL(items.size(), 6); + OCIO_CHECK_EQUAL(std::string(items[0].getName()), "Copyright"); + OCIO_CHECK_EQUAL(std::string(items[0].getValue()), "Copyright Contributors to the OpenColorIO Project."); + OCIO_CHECK_EQUAL(std::string(items[1].getName()), "AppRelease"); + OCIO_CHECK_EQUAL(std::string(items[1].getValue()), "2020.0.63"); + OCIO_CHECK_EQUAL(std::string(items[2].getName()), "Revision"); + OCIO_CHECK_EQUAL(std::string(items[2].getValue()), "1"); - OCIO_CHECK_EQUAL(a1.getValues()[8], 0.05560); - OCIO_CHECK_EQUAL(a1.getValues()[9], -0.204); - OCIO_CHECK_EQUAL(a1.getValues()[10], 1.0573); - OCIO_CHECK_EQUAL(a1.getValues()[11], 0.0); - - OCIO_CHECK_EQUAL(a1.getValues()[12], 0.0); - OCIO_CHECK_EQUAL(a1.getValues()[13], 0.0); - OCIO_CHECK_EQUAL(a1.getValues()[14], 0.0); - OCIO_CHECK_EQUAL(a1.getValues()[15], 1.0); + OCIO_CHECK_EQUAL(std::string(items[3].getName()), "Category"); + OCIO_CHECK_EQUAL(std::string(items[3].getValue()), ""); + auto catItems = items[3].getChildrenElements(); + OCIO_REQUIRE_EQUAL(catItems.size(), 1); + OCIO_CHECK_EQUAL(std::string(catItems[0].getName()), "Tags"); + auto tagsItems = catItems[0].getChildrenElements(); + OCIO_REQUIRE_EQUAL(tagsItems.size(), 2); + OCIO_CHECK_EQUAL(std::string(tagsItems[0].getName()), "SceneLinearWorkingSpace"); + OCIO_CHECK_EQUAL(std::string(tagsItems[0].getValue()), ""); + OCIO_CHECK_EQUAL(std::string(tagsItems[1].getName()), "Input"); + OCIO_CHECK_EQUAL(std::string(tagsItems[1].getValue()), ""); + + OCIO_CHECK_EQUAL(std::string(items[4].getName()), "InputColorSpace"); + OCIO_CHECK_EQUAL(std::string(items[4].getValue()), ""); + auto icItems = items[4].getChildrenElements(); + OCIO_REQUIRE_EQUAL(icItems.size(), 4); + OCIO_CHECK_EQUAL(std::string(icItems[0].getName()), OCIO::METADATA_DESCRIPTION); + OCIO_CHECK_EQUAL(std::string(icItems[0].getValue()), "Input color space description"); + OCIO_CHECK_EQUAL(std::string(icItems[1].getName()), "ImageState"); + OCIO_CHECK_EQUAL(std::string(icItems[1].getValue()), "video"); + OCIO_CHECK_EQUAL(std::string(icItems[2].getName()), "ShortName"); + OCIO_CHECK_EQUAL(std::string(icItems[2].getValue()), "no_version"); + OCIO_CHECK_EQUAL(std::string(icItems[3].getName()), "ID"); + OCIO_CHECK_EQUAL(std::string(icItems[3].getValue()), "387b23d1-f1ce-3f69-8544-e5601f45f78b"); + + OCIO_CHECK_EQUAL(std::string(items[5].getName()), "OutputColorSpace"); + OCIO_CHECK_EQUAL(std::string(items[5].getValue()), ""); + auto ocItems = items[5].getChildrenElements(); + OCIO_REQUIRE_EQUAL(ocItems.size(), 3); + auto attribs = items[5].getAttributes(); + OCIO_REQUIRE_EQUAL(attribs.size(), 2); + OCIO_CHECK_EQUAL(attribs[0].first, "att1"); + OCIO_CHECK_EQUAL(attribs[0].second, "test1"); + OCIO_CHECK_EQUAL(attribs[1].first, "att2"); + OCIO_CHECK_EQUAL(attribs[1].second, "test2"); + OCIO_CHECK_EQUAL(std::string(ocItems[0].getName()), "ImageState"); + OCIO_CHECK_EQUAL(std::string(ocItems[0].getValue()), "scene"); + OCIO_CHECK_EQUAL(std::string(ocItems[1].getName()), "ShortName"); + OCIO_CHECK_EQUAL(std::string(ocItems[1].getValue()), "ACES"); + OCIO_CHECK_EQUAL(std::string(ocItems[2].getName()), "ID"); + OCIO_CHECK_EQUAL(std::string(ocItems[2].getValue()), "1"); +} - auto pLut1 = std::dynamic_pointer_cast(opList[1]); - OCIO_REQUIRE_ASSERT(pLut1); +OCIO_ADD_TEST(FileFormatCTF, difficult_syntax) +{ + // This file contains a lot of unusual (but still legal) ways of writing the XML. + // It is intended to stress test that the XML parsing is working robustly. - const OCIO::Array & a2 = pLut1->getArray(); - OCIO_CHECK_EQUAL(a2.getLength(), 17); - OCIO_CHECK_EQUAL(a2.getNumColorComponents(), 3); - OCIO_CHECK_EQUAL(a2.getNumValues(), - a2.getLength() - *pLut1->getArray().getMaxColorComponents()); + OCIO::LocalCachedFileRcPtr cachedFile; + const std::string ctfFile("clf/difficult_syntax.clf"); - OCIO_REQUIRE_EQUAL(a2.getValues().size(), a2.getNumValues()); - OCIO_CHECK_EQUAL(a2.getValues()[0], 0.0f); - OCIO_CHECK_EQUAL(a2.getValues()[1], 0.0f); - OCIO_CHECK_EQUAL(a2.getValues()[2], 0.01f); - OCIO_CHECK_EQUAL(a2.getValues()[3], 0.28358f); - OCIO_CHECK_EQUAL(a2.getValues()[4], 0.28358f); - OCIO_CHECK_EQUAL(a2.getValues()[5], 100.0f); - OCIO_CHECK_EQUAL(a2.getValues()[6], 0.38860f); - OCIO_CHECK_EQUAL(a2.getValues()[7], 0.38860f); - OCIO_CHECK_EQUAL(a2.getValues()[8], 127.0f); + OCIO_CHECK_NO_THROW(cachedFile = LoadCLFFile(ctfFile)); + OCIO_REQUIRE_ASSERT((bool)cachedFile); - OCIO_CHECK_EQUAL(a2.getValues()[21], 0.68677f); - OCIO_CHECK_EQUAL(a2.getValues()[22], 0.68677f); - OCIO_CHECK_EQUAL(a2.getValues()[23], 0.68677f); + const OCIO::CTFVersion clfVersion = cachedFile->m_transform->getCLFVersion(); + const OCIO::CTFVersion ver(3, 0, 0); + OCIO_CHECK_EQUAL(clfVersion, ver); - OCIO_CHECK_EQUAL(a2.getValues()[48], 1.0f); - OCIO_CHECK_EQUAL(a2.getValues()[49], 1.0f); - OCIO_CHECK_EQUAL(a2.getValues()[50], 1.0f); + OCIO_CHECK_EQUAL(cachedFile->m_transform->getID(), "id1"); - auto pLut2 = std::dynamic_pointer_cast(opList[2]); - OCIO_REQUIRE_ASSERT(pLut2); - OCIO_CHECK_EQUAL(pLut2->getFileOutputBitDepth(), OCIO::BIT_DEPTH_UINT10); + OCIO_REQUIRE_EQUAL(cachedFile->m_transform->getDescriptions().size(), 2); + OCIO_CHECK_EQUAL(cachedFile->m_transform->getDescriptions()[0], + "This is the ProcessList description."); + OCIO_CHECK_EQUAL(cachedFile->m_transform->getDescriptions()[1], + "yet 'another' \"valid\" desc"); - const OCIO::Array & array = pLut2->getArray(); - OCIO_CHECK_EQUAL(array.getLength(), 32); - OCIO_CHECK_EQUAL(array.getNumColorComponents(), 1); - OCIO_CHECK_EQUAL(array.getNumValues(), - array.getLength() - *pLut2->getArray().getMaxColorComponents()); + const OCIO::FormatMetadataImpl & info = cachedFile->m_transform->getInfoMetadata(); + OCIO_CHECK_EQUAL(std::string(info.getName()), OCIO::METADATA_INFO); + auto items = info.getChildrenElements(); + OCIO_REQUIRE_EQUAL(items.size(), 1); + OCIO_CHECK_EQUAL(std::string(items[0].getName()), "Stuff"); + OCIO_CHECK_EQUAL(std::string(items[0].getValue()), "This is a \"difficult\" but 'legal' color transform file."); - OCIO_REQUIRE_EQUAL(array.getValues().size(), 96); - OCIO_CHECK_EQUAL(array.getValues()[0], 0.0f); - OCIO_CHECK_EQUAL(array.getValues()[1], 0.0f); - OCIO_CHECK_EQUAL(array.getValues()[2], 0.0f); - OCIO_CHECK_EQUAL(array.getValues()[3], 215.0f / 1023.0f); - OCIO_CHECK_EQUAL(array.getValues()[4], 215.0f / 1023.0f); - OCIO_CHECK_EQUAL(array.getValues()[5], 215.0f / 1023.0f); - OCIO_CHECK_EQUAL(array.getValues()[6], 294.0f / 1023.0f); - // and many more - OCIO_CHECK_EQUAL(array.getValues()[92], 1008.0f / 1023.0f); - OCIO_CHECK_EQUAL(array.getValues()[93], 1023.0f / 1023.0f); - OCIO_CHECK_EQUAL(array.getValues()[94], 1023.0f / 1023.0f); - OCIO_CHECK_EQUAL(array.getValues()[95], 1023.0f / 1023.0f); + const OCIO::ConstOpDataVec & opList = cachedFile->m_transform->getOps(); + OCIO_REQUIRE_EQUAL(opList.size(), 2); + { + auto pMatrix = std::dynamic_pointer_cast(opList[0]); + OCIO_REQUIRE_ASSERT(pMatrix); - auto pLut3 = std::dynamic_pointer_cast(opList[3]); - OCIO_REQUIRE_ASSERT(pLut3); - OCIO_CHECK_EQUAL(pLut3->getFileOutputBitDepth(), OCIO::BIT_DEPTH_UINT10); + OCIO_CHECK_EQUAL(pMatrix->getID(), "'mat-25'"); + OCIO_CHECK_EQUAL(pMatrix->getName(), "\"quote\""); - const OCIO::Array & a3 = pLut3->getArray(); - OCIO_CHECK_EQUAL(a3.getLength(), 3); - OCIO_CHECK_EQUAL(a3.getNumColorComponents(), 3); - OCIO_CHECK_EQUAL(a3.getNumValues(), - a3.getLength()*a3.getLength()*a3.getLength() - *pLut3->getArray().getMaxColorComponents()); + StringUtils::StringVec desc; + GetElementsValues(pMatrix->getFormatMetadata().getChildrenElements(), + OCIO::TAG_DESCRIPTION, desc); + OCIO_REQUIRE_EQUAL(desc.size(), 1); + OCIO_CHECK_EQUAL(desc[0], "third array dim value is ignored"); + + const OCIO::ArrayDouble & array = pMatrix->getArray(); + OCIO_CHECK_EQUAL(array.getLength(), 4u); + OCIO_CHECK_EQUAL(array.getNumColorComponents(), 4u); + OCIO_CHECK_EQUAL(array.getNumValues(), array.getLength()*array.getLength()); + + OCIO_REQUIRE_EQUAL(array.getValues().size(), array.getNumValues()); + OCIO_CHECK_EQUAL(array.getValues()[0], 3.24); + OCIO_CHECK_EQUAL(array.getValues()[1], -1.537); + OCIO_CHECK_EQUAL(array.getValues()[2], -0.4985); + OCIO_CHECK_EQUAL(array.getValues()[3], 0.0); + + OCIO_CHECK_EQUAL(array.getValues()[4], -0.96930); + OCIO_CHECK_EQUAL(array.getValues()[5], 1.876); + OCIO_CHECK_EQUAL(array.getValues()[6], 0.04156); + OCIO_CHECK_EQUAL(array.getValues()[7], 0.0); + + OCIO_CHECK_EQUAL(array.getValues()[8], 0.0556); + OCIO_CHECK_EQUAL(array.getValues()[9], -0.204); + OCIO_CHECK_EQUAL(array.getValues()[10], 0.105730e+1); + OCIO_CHECK_EQUAL(array.getValues()[11], 0.0); + + OCIO_CHECK_EQUAL(array.getValues()[12], 0.0); + OCIO_CHECK_EQUAL(array.getValues()[13], 0.0); + OCIO_CHECK_EQUAL(array.getValues()[14], 0.0); + OCIO_CHECK_EQUAL(array.getValues()[15], 1.0); + } + { + auto pLut = std::dynamic_pointer_cast(opList[1]); + OCIO_REQUIRE_ASSERT(pLut); - OCIO_REQUIRE_EQUAL(a3.getValues().size(), a3.getNumValues()); - OCIO_CHECK_EQUAL(a3.getValues()[0], 0.0f); - OCIO_CHECK_EQUAL(a3.getValues()[1], 30.0f / 1023.0f); - OCIO_CHECK_EQUAL(a3.getValues()[2], 33.0f / 1023.0f); - OCIO_CHECK_EQUAL(a3.getValues()[3], 0.0f); - OCIO_CHECK_EQUAL(a3.getValues()[4], 0.0f); - OCIO_CHECK_EQUAL(a3.getValues()[5], 133.0f / 1023.0f); + OCIO_CHECK_EQUAL(pLut->getName(), "a multi-line name"); - OCIO_CHECK_EQUAL(a3.getValues()[78], 1023.0f / 1023.0f); - OCIO_CHECK_EQUAL(a3.getValues()[79], 1023.0f / 1023.0f); - OCIO_CHECK_EQUAL(a3.getValues()[80], 1023.0f / 1023.0f); -} + StringUtils::StringVec desc; + GetElementsValues(pLut->getFormatMetadata().getChildrenElements(), + OCIO::TAG_DESCRIPTION, desc); + OCIO_REQUIRE_EQUAL(desc.size(), 3); + OCIO_CHECK_EQUAL(desc[0], "the n–dash description"); // the string here uses opt-dash + OCIO_CHECK_EQUAL(desc[1], "another valid description element "); + OCIO_CHECK_EQUAL(desc[2], "& another desc"); + + const OCIO::Array & array2 = pLut->getArray(); + OCIO_CHECK_EQUAL(array2.getLength(), 17); + OCIO_CHECK_EQUAL(array2.getNumColorComponents(), 3); + OCIO_CHECK_EQUAL(array2.getNumValues(), + array2.getLength() + *pLut->getArray().getMaxColorComponents()); -OCIO_ADD_TEST(FileFormatCTF, binary_file) -{ - const std::string ctfFile("image_png.clf"); - OCIO_CHECK_THROW_WHAT(LoadCLFFile(ctfFile), OCIO::Exception, "is not a CTF/CLF file."); + OCIO_REQUIRE_EQUAL(array2.getValues().size(), 51); + OCIO_CHECK_EQUAL(array2.getValues()[0], 0.0f); + OCIO_CHECK_EQUAL(array2.getValues()[1], 0.0f); + OCIO_CHECK_EQUAL(array2.getValues()[2], 0.0f); + OCIO_CHECK_EQUAL(array2.getValues()[3], 0.28358f); + OCIO_CHECK_EQUAL(array2.getValues()[4], 0.28358f); + OCIO_CHECK_EQUAL(array2.getValues()[5], 0.28358f); + OCIO_CHECK_EQUAL(array2.getValues()[6], 0.38860f); + OCIO_CHECK_EQUAL(array2.getValues()[45], 0.97109f); + OCIO_CHECK_EQUAL(array2.getValues()[46], 0.97109f); + OCIO_CHECK_EQUAL(array2.getValues()[47], 0.99999f); + } } -OCIO_ADD_TEST(FileFormatCTF, error_checker_for_difficult_xml) +OCIO_ADD_TEST(FileFormatCTF, difficult_xml_unknown_elements) { OCIO::LocalCachedFileRcPtr cachedFile; @@ -1134,110 +1433,348 @@ OCIO_ADD_TEST(FileFormatCTF, error_checker_for_difficult_xml) OCIO_CHECK_EQUAL(array2.getValues()[47], 0.97109f); } -OCIO_ADD_TEST(FileFormatCTF, invalid_transform) +OCIO_ADD_TEST(FileFormatCTF, unknown_elements) { - const std::string ctfFile("transform_invalid.clf"); - OCIO_CHECK_THROW_WHAT(LoadCLFFile(ctfFile), OCIO::Exception, - "is not a CTF/CLF file."); -} + OCIO::LocalCachedFileRcPtr cachedFile; + { + constexpr static const char ErrorOutputs[3][1024] = + { + "(34): Unrecognized element 'B' where its parent is 'ProcessList' (2): Unknown element", + "(34): Unrecognized element 'C' where its parent is 'B' (34)", + "(36): Unrecognized element 'A' where its parent is 'Description' (36)" + }; -OCIO_ADD_TEST(FileFormatCTF, missing_element_end) -{ - const std::string ctfFile("transform_element_end_missing.clf"); - OCIO_CHECK_THROW_WHAT(LoadCLFFile(ctfFile), OCIO::Exception, "no element found"); -} + OCIO::LogGuard guard; + OCIO::SetLoggingLevel(OCIO::LOGGING_LEVEL_WARNING); + // NB: This file has some added unknown elements A, B, and C as a test. + const std::string ctfFile("clf/illegal/unknown_elements.clf"); + OCIO_CHECK_NO_THROW(cachedFile = LoadCLFFile(ctfFile)); + OCIO_REQUIRE_ASSERT((bool)cachedFile); -OCIO_ADD_TEST(FileFormatCTF, missing_transform_id) -{ - const std::string ctfFile("transform_missing_id.clf"); - OCIO_CHECK_THROW_WHAT(LoadCLFFile(ctfFile), - OCIO::Exception, - "Required attribute 'id'"); + const StringUtils::StringVec parts = StringUtils::SplitByLines(StringUtils::RightTrim(guard.output())); + OCIO_REQUIRE_EQUAL(parts.size(), 3); + + for (size_t i = 0; i < parts.size(); ++i) + { + OCIO_CHECK_NE(std::string::npos, StringUtils::Find(parts[i], ErrorOutputs[i])); + } + } + + const OCIO::ConstOpDataVec & opList = cachedFile->m_transform->getOps(); + OCIO_REQUIRE_EQUAL(opList.size(), 4); + + auto pMatrix = std::dynamic_pointer_cast(opList[0]); + OCIO_REQUIRE_ASSERT(pMatrix); + + const OCIO::ArrayDouble & a1 = pMatrix->getArray(); + OCIO_CHECK_EQUAL(a1.getLength(), 4); + OCIO_CHECK_EQUAL(a1.getNumColorComponents(), 4); + OCIO_CHECK_EQUAL(a1.getNumValues(), a1.getLength()*a1.getLength()); + + OCIO_REQUIRE_EQUAL(a1.getValues().size(), a1.getNumValues()); + OCIO_CHECK_EQUAL(a1.getValues()[0], 3.24); + OCIO_CHECK_EQUAL(a1.getValues()[4], -0.96930); + OCIO_CHECK_EQUAL(a1.getValues()[10], 1.0573); + + auto pLut1 = std::dynamic_pointer_cast(opList[1]); + OCIO_REQUIRE_ASSERT(pLut1); + + const OCIO::Array & a2 = pLut1->getArray(); + OCIO_CHECK_EQUAL(a2.getLength(), 17); + OCIO_CHECK_EQUAL(a2.getNumColorComponents(), 3); + OCIO_CHECK_EQUAL(a2.getNumValues(), + a2.getLength() + *pLut1->getArray().getMaxColorComponents()); + + OCIO_REQUIRE_EQUAL(a2.getValues().size(), a2.getNumValues()); + OCIO_CHECK_EQUAL(a2.getValues()[3], 0.28358f); + OCIO_CHECK_EQUAL(a2.getValues()[4], 0.28358f); + OCIO_CHECK_EQUAL(a2.getValues()[5], 100.0f); + OCIO_CHECK_EQUAL(a2.getValues()[50], 1.0f); + + auto pLut2 = std::dynamic_pointer_cast(opList[2]); + OCIO_REQUIRE_ASSERT(pLut2); + OCIO_CHECK_EQUAL(pLut2->getFileOutputBitDepth(), OCIO::BIT_DEPTH_UINT10); + + const OCIO::Array & array = pLut2->getArray(); + OCIO_CHECK_EQUAL(array.getLength(), 32); + OCIO_CHECK_EQUAL(array.getNumColorComponents(), 1); + OCIO_CHECK_EQUAL(array.getNumValues(), + array.getLength() + *pLut2->getArray().getMaxColorComponents()); + + OCIO_REQUIRE_EQUAL(array.getValues().size(), 96); + OCIO_CHECK_EQUAL(array.getValues()[0], 0.0f); + OCIO_CHECK_EQUAL(array.getValues()[1], 0.0f); + OCIO_CHECK_EQUAL(array.getValues()[2], 0.0f); + OCIO_CHECK_EQUAL(array.getValues()[3], 215.0f / 1023.0f); + OCIO_CHECK_EQUAL(array.getValues()[4], 215.0f / 1023.0f); + OCIO_CHECK_EQUAL(array.getValues()[5], 215.0f / 1023.0f); + OCIO_CHECK_EQUAL(array.getValues()[6], 294.0f / 1023.0f); + // and many more + OCIO_CHECK_EQUAL(array.getValues()[92], 1008.0f / 1023.0f); + OCIO_CHECK_EQUAL(array.getValues()[93], 1023.0f / 1023.0f); + OCIO_CHECK_EQUAL(array.getValues()[94], 1023.0f / 1023.0f); + OCIO_CHECK_EQUAL(array.getValues()[95], 1023.0f / 1023.0f); + + auto pLut3 = std::dynamic_pointer_cast(opList[3]); + OCIO_REQUIRE_ASSERT(pLut3); + OCIO_CHECK_EQUAL(pLut3->getFileOutputBitDepth(), OCIO::BIT_DEPTH_UINT10); + + const OCIO::Array & a3 = pLut3->getArray(); + OCIO_CHECK_EQUAL(a3.getLength(), 3); + OCIO_CHECK_EQUAL(a3.getNumColorComponents(), 3); + OCIO_CHECK_EQUAL(a3.getNumValues(), + a3.getLength()*a3.getLength()*a3.getLength() + *pLut3->getArray().getMaxColorComponents()); + + OCIO_REQUIRE_EQUAL(a3.getValues().size(), a3.getNumValues()); + OCIO_CHECK_EQUAL(a3.getValues()[0], 0.0f); + OCIO_CHECK_EQUAL(a3.getValues()[1], 30.0f / 1023.0f); + OCIO_CHECK_EQUAL(a3.getValues()[2], 33.0f / 1023.0f); + OCIO_CHECK_EQUAL(a3.getValues()[3], 0.0f); + OCIO_CHECK_EQUAL(a3.getValues()[4], 0.0f); + OCIO_CHECK_EQUAL(a3.getValues()[5], 133.0f / 1023.0f); + + OCIO_CHECK_EQUAL(a3.getValues()[78], 1023.0f / 1023.0f); + OCIO_CHECK_EQUAL(a3.getValues()[79], 1023.0f / 1023.0f); + OCIO_CHECK_EQUAL(a3.getValues()[80], 1023.0f / 1023.0f); } -OCIO_ADD_TEST(FileFormatCTF, missing_in_bitdepth) +OCIO_ADD_TEST(FileFormatCTF, wrong_format) { - const std::string ctfFile("transform_missing_inbitdepth.clf"); - OCIO_CHECK_THROW_WHAT(LoadCLFFile(ctfFile), - OCIO::Exception, - "inBitDepth is missing"); + OCIO::LocalCachedFileRcPtr cachedFile; + { + const std::string ctfFile("logtolin_8to8.lut"); + OCIO_CHECK_THROW_WHAT(cachedFile = LoadCLFFile(ctfFile), + OCIO::Exception, + "not a CTF/CLF file."); + OCIO_CHECK_ASSERT(!(bool)cachedFile); + } } -OCIO_ADD_TEST(FileFormatCTF, missing_out_bitdepth) +OCIO_ADD_TEST(FileFormatCTF, binary_file) { - const std::string ctfFile("transform_missing_outbitdepth.clf"); - OCIO_CHECK_THROW_WHAT(LoadCLFFile(ctfFile), - OCIO::Exception, - "outBitDepth is missing"); + const std::string ctfFile("clf/illegal/image_png.clf"); + OCIO_CHECK_THROW_WHAT(LoadCLFFile(ctfFile), OCIO::Exception, "is not a CTF/CLF file."); } -OCIO_ADD_TEST(FileFormatCTF, array_missing_values) +OCIO_ADD_TEST(FileFormatCTF, process_list_invalid_version) { - const std::string ctfFile("array_missing_values.clf"); + const std::string ctfFile("process_list_invalid_version.ctf"); OCIO_CHECK_THROW_WHAT(LoadCLFFile(ctfFile), OCIO::Exception, - "Expected 3x3 Array values"); + "is not a valid version"); } -OCIO_ADD_TEST(FileFormatCTF, array_illegal_values) +OCIO_ADD_TEST(FileFormatCTF, clf_process_list_bad_version) { - const std::string ctfFile("array_illegal_values.clf"); - OCIO_CHECK_THROW_WHAT(LoadCLFFile(ctfFile), OCIO::Exception, - "Illegal values"); + std::string fileName("clf/illegal/process_list_bad_version.clf"); + OCIO_CHECK_THROW_WHAT(LoadCLFFile(fileName), + OCIO::Exception, + "is not a valid version"); } -OCIO_ADD_TEST(FileFormatCTF, unknown_value) +OCIO_ADD_TEST(FileFormatCTF, process_list_valid_version) { - const std::string ctfFile("unknown_outdepth.clf"); - OCIO_CHECK_THROW_WHAT(LoadCLFFile(ctfFile), - OCIO::Exception, - "outBitDepth unknown value"); + OCIO::LocalCachedFileRcPtr cachedFile; + const std::string ctfFile("process_list_valid_version.ctf"); + OCIO_CHECK_NO_THROW(cachedFile = LoadCLFFile(ctfFile)); + + const OCIO::CTFVersion ctfVersion = + cachedFile->m_transform->getCTFVersion(); + OCIO_CHECK_EQUAL(ctfVersion, OCIO::CTF_PROCESS_LIST_VERSION_1_4); } -OCIO_ADD_TEST(FileFormatCTF, array_corrupted_dimension) +OCIO_ADD_TEST(FileFormatCTF, process_list_higher_version) { - const std::string ctfFile("array_illegal_dimension.clf"); + const std::string ctfFile("process_list_higher_version.ctf"); OCIO_CHECK_THROW_WHAT(LoadCLFFile(ctfFile), OCIO::Exception, - "Illegal array dimensions"); + "Unsupported transform file version"); } -OCIO_ADD_TEST(FileFormatCTF, array_too_many_values) +OCIO_ADD_TEST(FileFormatCTF, clf_process_list_higher_version) { - const std::string ctfFile("array_too_many_values.clf"); + const std::string ctfFile("clf/illegal/process_list_higher_version.clf"); OCIO_CHECK_THROW_WHAT(LoadCLFFile(ctfFile), OCIO::Exception, - "Expected 3x3 Array, found too many values"); + "Unsupported transform file version"); } -OCIO_ADD_TEST(FileFormatCTF, matrix_bitdepth_illegal) +OCIO_ADD_TEST(FileFormatCTF, process_list_version_revision) { - const std::string ctfFile("matrix_bitdepth_illegal.clf"); + OCIO::LocalCachedFileRcPtr cachedFile; + const std::string ctfFile("process_list_version_revision.ctf"); + OCIO_CHECK_NO_THROW(cachedFile = LoadCLFFile(ctfFile)); + + const OCIO::CTFVersion ctfVersion = + cachedFile->m_transform->getCTFVersion(); + const OCIO::CTFVersion ver(1, 3, 10); + OCIO_CHECK_EQUAL(ctfVersion, ver); + OCIO_CHECK_ASSERT(OCIO::CTF_PROCESS_LIST_VERSION_1_3 < ctfVersion); + OCIO_CHECK_ASSERT(ctfVersion < OCIO::CTF_PROCESS_LIST_VERSION_1_4); +} + +OCIO_ADD_TEST(FileFormatCTF, process_list_no_version) +{ + OCIO::LocalCachedFileRcPtr cachedFile; + const std::string ctfFile("process_list_no_version.ctf"); + OCIO_CHECK_NO_THROW(cachedFile = LoadCLFFile(ctfFile)); + + const OCIO::CTFVersion ctfVersion = + cachedFile->m_transform->getCTFVersion(); + OCIO_CHECK_EQUAL(ctfVersion, OCIO::CTF_PROCESS_LIST_VERSION_1_2); +} + +OCIO_ADD_TEST(FileFormatCTF, info_element_version_test) +{ + // VALID - No Version. + { + const std::string ctfFile("info_version_without.ctf"); + OCIO_CHECK_NO_THROW(LoadCLFFile(ctfFile)); + } + // VALID - Minor Version. + { + const std::string ctfFile("info_version_valid_minor.ctf"); + OCIO_CHECK_NO_THROW(LoadCLFFile(ctfFile)); + } + // INVALID - Invalid Version. + { + const std::string ctfFile("info_version_invalid.ctf"); + OCIO_CHECK_THROW_WHAT( + LoadCLFFile(ctfFile), OCIO::Exception, + "Invalid Info element version attribute"); + } + // INVALID - Unsupported Version. + { + const std::string ctfFile("info_version_unsupported.ctf"); + OCIO_CHECK_THROW_WHAT( + LoadCLFFile(ctfFile), OCIO::Exception, + "Unsupported Info element version attribute"); + } + // INVALID - Empty Version. + { + const std::string ctfFile("info_version_empty.ctf"); + OCIO_CHECK_THROW_WHAT( + LoadCLFFile(ctfFile), OCIO::Exception, + "Invalid Info element version attribute"); + } +} + +OCIO_ADD_TEST(FileFormatCTF, process_list_missing) +{ + const std::string ctfFile("clf/illegal/process_list_missing.clf"); + OCIO_CHECK_THROW_WHAT(LoadCLFFile(ctfFile), OCIO::Exception, + "is not a CTF/CLF file."); +} + +OCIO_ADD_TEST(FileFormatCTF, transform_missing) +{ + const std::string ctfFile("clf/illegal/transform_missing.clf"); + OCIO_CHECK_THROW_WHAT(LoadCLFFile(ctfFile), OCIO::Exception, + "is not a CTF/CLF file."); +} + +OCIO_ADD_TEST(FileFormatCTF, transform_element_end_missing) +{ + const std::string ctfFile("clf/illegal/transform_element_end_missing.clf"); + OCIO_CHECK_THROW_WHAT(LoadCLFFile(ctfFile), OCIO::Exception, "no element found"); +} + +OCIO_ADD_TEST(FileFormatCTF, transform_missing_id) +{ + const std::string ctfFile("clf/illegal/transform_missing_id.clf"); + OCIO_CHECK_THROW_WHAT(LoadCLFFile(ctfFile), + OCIO::Exception, + "Required attribute 'id'"); +} + +OCIO_ADD_TEST(FileFormatCTF, transform_missing_inbitdepth) +{ + const std::string ctfFile("clf/illegal/transform_missing_inbitdepth.clf"); OCIO_CHECK_THROW_WHAT(LoadCLFFile(ctfFile), OCIO::Exception, - "inBitDepth unknown value"); + "inBitDepth is missing"); +} + +OCIO_ADD_TEST(FileFormatCTF, transform_missing_outbitdepth) +{ + const std::string ctfFile("clf/illegal/transform_missing_outbitdepth.clf"); + OCIO_CHECK_THROW_WHAT(LoadCLFFile(ctfFile), + OCIO::Exception, + "outBitDepth is missing"); +} + +OCIO_ADD_TEST(FileFormatCTF, array_missing_values) +{ + const std::string ctfFile("clf/illegal/array_missing_values.clf"); + OCIO_CHECK_THROW_WHAT(LoadCLFFile(ctfFile), + OCIO::Exception, + "Expected 3x3 Array values"); +} + +OCIO_ADD_TEST(FileFormatCTF, array_bad_value) +{ + const std::string ctfFile("clf/illegal/array_bad_value.clf"); + OCIO_CHECK_THROW_WHAT(LoadCLFFile(ctfFile), + OCIO::Exception, + "Illegal values"); +} + +OCIO_ADD_TEST(FileFormatCTF, array_bad_dimension) +{ + const std::string ctfFile("clf/illegal/array_bad_dimension.clf"); + OCIO_CHECK_THROW_WHAT(LoadCLFFile(ctfFile), + OCIO::Exception, + "Illegal array dimensions"); +} + +OCIO_ADD_TEST(FileFormatCTF, array_too_many_values) +{ + const std::string ctfFile("clf/illegal/array_too_many_values.clf"); + OCIO_CHECK_THROW_WHAT(LoadCLFFile(ctfFile), + OCIO::Exception, + "Expected 3x3 Array, found too many values"); } OCIO_ADD_TEST(FileFormatCTF, matrix_end_missing) { - const std::string ctfFile("matrix_end_missing.clf"); + const std::string ctfFile("clf/illegal/matrix_end_missing.clf"); OCIO_CHECK_THROW_WHAT(LoadCLFFile(ctfFile), OCIO::Exception, "no closing tag for 'Matrix'"); } +OCIO_ADD_TEST(FileFormatCTF, transform_bad_outdepth) +{ + const std::string ctfFile("clf/illegal/transform_bad_outdepth.clf"); + OCIO_CHECK_THROW_WHAT(LoadCLFFile(ctfFile), + OCIO::Exception, + "outBitDepth unknown value"); +} + +OCIO_ADD_TEST(FileFormatCTF, transform_end_missing) +{ + const std::string ctfFile("clf/illegal/transform_element_end_missing.clf"); + OCIO_CHECK_THROW_WHAT(LoadCLFFile(ctfFile), + OCIO::Exception, + "no element found"); +} + OCIO_ADD_TEST(FileFormatCTF, transform_corrupted_tag) { - const std::string ctfFile("transform_corrupted_tag.clf"); - OCIO_CHECK_THROW_WHAT(LoadCLFFile(ctfFile), OCIO::Exception, + const std::string ctfFile("clf/illegal/transform_corrupted_tag.clf"); + OCIO_CHECK_THROW_WHAT(LoadCLFFile(ctfFile), + OCIO::Exception, "no closing tag"); } OCIO_ADD_TEST(FileFormatCTF, transform_empty) { - const std::string ctfFile("transform_empty.clf"); + const std::string ctfFile("clf/illegal/transform_empty.clf"); OCIO_CHECK_THROW_WHAT(LoadCLFFile(ctfFile), OCIO::Exception, "No color operator"); @@ -1245,7 +1782,7 @@ OCIO_ADD_TEST(FileFormatCTF, transform_empty) OCIO_ADD_TEST(FileFormatCTF, transform_id_empty) { - const std::string ctfFile("transform_id_empty.clf"); + const std::string ctfFile("clf/illegal/transform_id_empty.clf"); OCIO_CHECK_THROW_WHAT(LoadCLFFile(ctfFile), OCIO::Exception, "Required attribute 'id' does not have a value"); @@ -1256,233 +1793,255 @@ OCIO_ADD_TEST(FileFormatCTF, transform_with_bitdepth_mismatch) // Even though we normalize the bit-depths after reading, any mismatches in // the file are an indication of improper/unreliable formatting and an // exception should be thrown. - const std::string ctfFile("transform_bitdepth_mismatch.clf"); + const std::string ctfFile("clf/illegal/transform_bitdepth_mismatch.clf"); OCIO_CHECK_THROW_WHAT(LoadCLFFile(ctfFile), OCIO::Exception, "Bit-depth mismatch"); } -OCIO_ADD_TEST(FileFormatCTF, check_index_map) +OCIO_ADD_TEST(FileFormatCTF, inverse_of_id_test) { - const std::string ctfFile("indexMap_test.ctf"); - OCIO_CHECK_THROW_WHAT(LoadCLFFile(ctfFile), - OCIO::Exception, - "Only two entry IndexMaps are supported"); + OCIO::LocalCachedFileRcPtr cachedFile; + const std::string ctfFile("clf/inverseOf_id_test.clf"); + OCIO_CHECK_NO_THROW(cachedFile = LoadCLFFile(ctfFile)); + OCIO_REQUIRE_ASSERT((bool)cachedFile); + + OCIO_CHECK_ASSERT(cachedFile->m_transform->getInverseOfId() == + "inverseOfIdTest"); } -OCIO_ADD_TEST(FileFormatCTF, matrix_with_offset) +OCIO_ADD_TEST(FileFormatCTF, range_default) { + // If style is not present, it defaults to clamp. OCIO::LocalCachedFileRcPtr cachedFile; - const std::string ctfFile("matrix_offsets_example.ctf"); + const std::string ctfFile("clf/range.clf"); OCIO_CHECK_NO_THROW(cachedFile = LoadCLFFile(ctfFile)); OCIO_REQUIRE_ASSERT((bool)cachedFile); - // Note that the ProcessList does not have a version attribute and - // therefore defaults to 1.2. - // The "4x4x3" Array syntax is only allowed in versions 1.2 or earlier. - const OCIO::CTFVersion ctfVersion = - cachedFile->m_transform->getCTFVersion(); - OCIO_CHECK_ASSERT(OCIO::CTF_PROCESS_LIST_VERSION_1_2 == ctfVersion); const OCIO::ConstOpDataVec & opList = cachedFile->m_transform->getOps(); OCIO_REQUIRE_EQUAL(opList.size(), 1); - auto pMatrix = std::dynamic_pointer_cast(opList[0]); - OCIO_REQUIRE_ASSERT(pMatrix); + auto pR = std::dynamic_pointer_cast(opList[0]); + OCIO_REQUIRE_ASSERT(pR); - const OCIO::ArrayDouble & array = pMatrix->getArray(); - OCIO_CHECK_EQUAL(array.getLength(), 4); - OCIO_CHECK_EQUAL(array.getNumColorComponents(), 4); - OCIO_CHECK_EQUAL(array.getNumValues(), - array.getLength()*array.getLength()); + OCIO_CHECK_EQUAL(pR->getFileInputBitDepth(), OCIO::BIT_DEPTH_UINT16); + OCIO_CHECK_EQUAL(pR->getFileOutputBitDepth(), OCIO::BIT_DEPTH_UINT16); + // NB: All exactly representable as float. + OCIO_CHECK_EQUAL(pR->getMinInValue(), 16320. / 65535.); + OCIO_CHECK_EQUAL(pR->getMaxInValue(), 32640. / 65535.); + OCIO_CHECK_EQUAL(pR->getMinOutValue(), 16320. / 65535.); + OCIO_CHECK_EQUAL(pR->getMaxOutValue(), 32640. / 65535.); - OCIO_REQUIRE_EQUAL(array.getValues().size(), array.getNumValues()); - OCIO_CHECK_EQUAL(array.getValues()[0], 3.24); - OCIO_CHECK_EQUAL(array.getValues()[1], -1.537); - OCIO_CHECK_EQUAL(array.getValues()[2], -0.49850); - OCIO_CHECK_EQUAL(array.getValues()[3], 0.0); - - OCIO_CHECK_EQUAL(array.getValues()[4], -0.96930); - OCIO_CHECK_EQUAL(array.getValues()[5], 1.876); - OCIO_CHECK_EQUAL(array.getValues()[6], 0.04156); - OCIO_CHECK_EQUAL(array.getValues()[7], 0.0); - - OCIO_CHECK_EQUAL(array.getValues()[8], 0.05560); - OCIO_CHECK_EQUAL(array.getValues()[9], -0.204); - OCIO_CHECK_EQUAL(array.getValues()[10], 1.0573); - OCIO_CHECK_EQUAL(array.getValues()[11], 0.0); - - OCIO_CHECK_EQUAL(array.getValues()[12], 0.0); - OCIO_CHECK_EQUAL(array.getValues()[13], 0.0); - OCIO_CHECK_EQUAL(array.getValues()[14], 0.0); - OCIO_CHECK_EQUAL(array.getValues()[15], 1.0); - - OCIO_CHECK_EQUAL(pMatrix->getOffsets()[0], 1.0); - OCIO_CHECK_EQUAL(pMatrix->getOffsets()[1], 2.0); - OCIO_CHECK_EQUAL(pMatrix->getOffsets()[2], 3.0); + OCIO_CHECK_ASSERT(!pR->minIsEmpty()); + OCIO_CHECK_ASSERT(!pR->maxIsEmpty()); } -OCIO_ADD_TEST(FileFormatCTF, matrix_with_offset_1_3) +OCIO_ADD_TEST(FileFormatCTF, range_test1_clamp) { - // Matrix 4 4 3 only valid up to version 1.2. - const std::string ctfFile("matrix_offsets_example_1_3.ctf"); - OCIO_CHECK_THROW_WHAT(LoadCLFFile(ctfFile), - OCIO::Exception, - "Illegal array dimensions 4 4 3"); + // Style == clamp. + OCIO::LocalCachedFileRcPtr cachedFile; + const std::string ctfFile("clf/range_test1_clamp.clf"); + OCIO_CHECK_NO_THROW(cachedFile = LoadCLFFile(ctfFile)); + OCIO_REQUIRE_ASSERT((bool)cachedFile); + + const OCIO::ConstOpDataVec & opList = cachedFile->m_transform->getOps(); + OCIO_REQUIRE_EQUAL(opList.size(), 1); + auto pR = std::dynamic_pointer_cast(opList[0]); + OCIO_REQUIRE_ASSERT(pR); + + OCIO_CHECK_EQUAL(pR->getFileInputBitDepth(), OCIO::BIT_DEPTH_UINT8); + OCIO_CHECK_EQUAL(pR->getFileOutputBitDepth(), OCIO::BIT_DEPTH_F32); + // NB: All exactly representable as float. + OCIO_CHECK_EQUAL(pR->getMinInValue(), 16. / 255.); + OCIO_CHECK_EQUAL(pR->getMaxInValue(), 240. / 255.); + OCIO_CHECK_EQUAL(pR->getMinOutValue(), -0.5); + OCIO_CHECK_EQUAL(pR->getMaxOutValue(), 2.); + + OCIO_CHECK_ASSERT(!pR->minIsEmpty()); + OCIO_CHECK_ASSERT(!pR->maxIsEmpty()); } -OCIO_ADD_TEST(FileFormatCTF, lut_3by1d_with_nan_infinity) +OCIO_ADD_TEST(FileFormatCTF, range_test1_noclamp) { + // Style == noClamp. OCIO::LocalCachedFileRcPtr cachedFile; - const std::string ctfFile("lut3by1d_nan_infinity_example.clf"); + const std::string ctfFile("clf/range_test1_noclamp.clf"); OCIO_CHECK_NO_THROW(cachedFile = LoadCLFFile(ctfFile)); OCIO_REQUIRE_ASSERT((bool)cachedFile); const OCIO::ConstOpDataVec & opList = cachedFile->m_transform->getOps(); OCIO_REQUIRE_EQUAL(opList.size(), 1); - auto pLut1d = std::dynamic_pointer_cast(opList[0]); - OCIO_REQUIRE_ASSERT(pLut1d); - const OCIO::Array & array = pLut1d->getArray(); + // Check that the noClamp style Range became a Matrix. + auto matOpData = std::dynamic_pointer_cast(opList[0]); + OCIO_REQUIRE_ASSERT(matOpData); + OCIO_CHECK_EQUAL(matOpData->getFileInputBitDepth(), OCIO::BIT_DEPTH_UINT8); + OCIO_CHECK_EQUAL(matOpData->getFileOutputBitDepth(), OCIO::BIT_DEPTH_F32); - OCIO_REQUIRE_EQUAL(array.getValues().size(), array.getNumValues()); - OCIO_CHECK_ASSERT(OCIO::IsNan(array.getValues()[0])); - OCIO_CHECK_ASSERT(OCIO::IsNan(array.getValues()[1])); - OCIO_CHECK_ASSERT(OCIO::IsNan(array.getValues()[2])); - OCIO_CHECK_ASSERT(OCIO::IsNan(array.getValues()[3])); - OCIO_CHECK_ASSERT(OCIO::IsNan(array.getValues()[4])); - OCIO_CHECK_EQUAL(array.getValues()[5], - std::numeric_limits::infinity()); - OCIO_CHECK_EQUAL(array.getValues()[6], - std::numeric_limits::infinity()); - OCIO_CHECK_EQUAL(array.getValues()[7], - std::numeric_limits::infinity()); - OCIO_CHECK_EQUAL(array.getValues()[8], - -std::numeric_limits::infinity()); - OCIO_CHECK_EQUAL(array.getValues()[9], - -std::numeric_limits::infinity()); -} + const double outScale = OCIO::GetBitDepthMaxValue(OCIO::BIT_DEPTH_F32); + const double matScale = outScale / OCIO::GetBitDepthMaxValue(OCIO::BIT_DEPTH_UINT8); + const OCIO::ArrayDouble & array = matOpData->getArray(); + OCIO_CHECK_EQUAL(array.getLength(), 4u); + OCIO_CHECK_EQUAL(array.getNumColorComponents(), 4u); + OCIO_CHECK_EQUAL(array.getNumValues(), + array.getLength()*array.getLength()); -OCIO_ADD_TEST(FileFormatCTF, lut1d_half_domain_set_false) -{ - // Should throw an exception because the 'half_domain' tag - // was found but set to something other than 'true'. - const std::string ctfFile("lut1d_half_domain_set_false.clf"); - OCIO_CHECK_THROW_WHAT(LoadCLFFile(ctfFile), - OCIO::Exception, - "Illegal 'halfDomain' attribute"); -} + const float scalef = (2.f - -0.5f) / (240.f - 16.f); + const float offsetf = -0.5f - scalef * 16.f; + const float prec = 10000.f; + const int scale = (int)(prec * scalef); + const int offset = (int)(prec * offsetf); -OCIO_ADD_TEST(FileFormatCTF, lut1d_raw_half_set_false) -{ - // Should throw an exception because the 'raw_halfs' tag - // was found but set to something other than 'true'. - const std::string ctfFile("lut1d_raw_half_set_false.clf"); - OCIO_CHECK_THROW_WHAT(LoadCLFFile(ctfFile), - OCIO::Exception, - "Illegal 'rawHalfs' attribute"); + OCIO_CHECK_ASSERT(matOpData->isDiagonal()); + + // Check values on the diagonal. + OCIO_REQUIRE_EQUAL(array.getValues().size(), array.getNumValues()); + OCIO_CHECK_EQUAL((int)(prec * array.getValues()[0] * matScale), scale); + OCIO_CHECK_EQUAL((int)(prec * array.getValues()[5] * matScale), scale); + OCIO_CHECK_EQUAL((int)(prec * array.getValues()[10] * matScale), scale); + OCIO_CHECK_EQUAL(array.getValues()[15], 1.0); + + // Check the offsets. + const OCIO::MatrixOpData::Offsets & offsets = matOpData->getOffsets(); + OCIO_CHECK_EQUAL((int)(prec * offsets[0] * outScale), offset); + OCIO_CHECK_EQUAL((int)(prec * offsets[1] * outScale), offset); + OCIO_CHECK_EQUAL((int)(prec * offsets[2] * outScale), offset); + OCIO_CHECK_EQUAL(offsets[3], 0.f); } -OCIO_ADD_TEST(FileFormatCTF, lut1d_half_domain_raw_half_set) +OCIO_ADD_TEST(FileFormatCTF, range_test2) { + // Style == clamp. OCIO::LocalCachedFileRcPtr cachedFile; - const std::string ctfFile("lut1d_half_domain_raw_half_set.clf"); + const std::string ctfFile("clf/range_test2.clf"); OCIO_CHECK_NO_THROW(cachedFile = LoadCLFFile(ctfFile)); OCIO_REQUIRE_ASSERT((bool)cachedFile); const OCIO::ConstOpDataVec & opList = cachedFile->m_transform->getOps(); OCIO_REQUIRE_EQUAL(opList.size(), 1); - auto pLut1d = std::dynamic_pointer_cast(opList[0]); - OCIO_REQUIRE_ASSERT(pLut1d); + auto pR = std::dynamic_pointer_cast(opList[0]); + OCIO_REQUIRE_ASSERT(pR); - OCIO_CHECK_ASSERT(pLut1d->isInputHalfDomain()); - OCIO_CHECK_ASSERT(pLut1d->isOutputRawHalfs()); - - OCIO_CHECK_EQUAL(pLut1d->getArray().getValues()[0] * 1023.0f, - OCIO::ConvertHalfBitsToFloat(0)); - OCIO_CHECK_EQUAL(pLut1d->getArray().getValues()[3] * 1023.0f, - OCIO::ConvertHalfBitsToFloat(215)); - OCIO_CHECK_EQUAL(pLut1d->getArray().getValues()[6] * 1023.0f, - OCIO::ConvertHalfBitsToFloat(294)); - OCIO_CHECK_EQUAL(pLut1d->getArray().getValues()[9] * 1023.0f, - OCIO::ConvertHalfBitsToFloat(354)); - OCIO_CHECK_EQUAL(pLut1d->getArray().getValues()[12] * 1023.0f, - OCIO::ConvertHalfBitsToFloat(403)); + OCIO_CHECK_EQUAL(pR->getFileInputBitDepth(), OCIO::BIT_DEPTH_F32); + OCIO_CHECK_EQUAL(pR->getFileOutputBitDepth(), OCIO::BIT_DEPTH_F16); + OCIO_CHECK_EQUAL(pR->getMinInValue(), 0.1); + OCIO_CHECK_EQUAL(pR->getMinOutValue(), 0.1); + OCIO_CHECK_ASSERT(pR->maxIsEmpty()); } -OCIO_ADD_TEST(FileFormatCTF, lut1d_half_domain_invalid_entries) +OCIO_ADD_TEST(FileFormatCTF, range_nonmatching_clamp) { - const std::string ctfFile("lut1d_half_domain_invalid_entries.clf"); - // This should fail with invalid entries exception because the number - // of entries in the op is not 65536 (required when using half domain). + const std::string ctfFile("clf/illegal/range_nonmatching_clamp.clf"); + OCIO_CHECK_THROW_WHAT(LoadCLFFile(ctfFile), OCIO::Exception, + "In and out minimum limits must be equal"); +} + +OCIO_ADD_TEST(FileFormatCTF, range_empty) +{ + const std::string ctfFile("clf/illegal/range_empty.clf"); + OCIO_CHECK_THROW_WHAT(LoadCLFFile(ctfFile), OCIO::Exception, + "At least minimum or maximum limits must be set"); +} + +OCIO_ADD_TEST(FileFormatCTF, range_bad_noclamp) +{ + const std::string ctfFile("clf/illegal/range_bad_noclamp.clf"); + OCIO_CHECK_THROW_WHAT(LoadCLFFile(ctfFile), OCIO::Exception, + "Non-clamping Range min & max values have to be set"); +} + +OCIO_ADD_TEST(FileFormatCTF, indexMap_test) +{ + const std::string ctfFile("indexMap_test.ctf"); OCIO_CHECK_THROW_WHAT(LoadCLFFile(ctfFile), OCIO::Exception, - "65536 required for halfDomain"); + "Only two entry IndexMaps are supported"); } -OCIO_ADD_TEST(FileFormatCTF, inverse_of_id_test) +OCIO_ADD_TEST(FileFormatCTF, indexMap_test1_clfv2) { + // IndexMaps were allowed in CLF v2 (were removed in v3). OCIO::LocalCachedFileRcPtr cachedFile; - const std::string ctfFile("inverseOfId_test.clf"); + const std::string ctfFile("indexMap_test1_clfv2.clf"); OCIO_CHECK_NO_THROW(cachedFile = LoadCLFFile(ctfFile)); OCIO_REQUIRE_ASSERT((bool)cachedFile); - OCIO_CHECK_ASSERT(cachedFile->m_transform->getInverseOfId() == - "inverseOfIdTest"); + const OCIO::ConstOpDataVec & opList = cachedFile->m_transform->getOps(); + OCIO_REQUIRE_EQUAL(opList.size(), 2); + auto pR = std::dynamic_pointer_cast(opList[0]); + OCIO_REQUIRE_ASSERT(pR); + + // Check that the indexMap caused a Range to be inserted. + OCIO_CHECK_EQUAL(pR->getMinInValue() * 1023., 64.5); + OCIO_CHECK_EQUAL(pR->getMaxInValue() * 1023., 940.); + OCIO_CHECK_EQUAL(pR->getMinOutValue() * 1023.0, 132.0); // 4*1023/31 + OCIO_CHECK_EQUAL(pR->getMaxOutValue() * 1023.0, 1089.0); // 33*1023/31 + OCIO_CHECK_EQUAL(pR->getFileInputBitDepth(), OCIO::BIT_DEPTH_UINT10); + OCIO_CHECK_EQUAL(pR->getFileOutputBitDepth(), OCIO::BIT_DEPTH_UINT10); + + // Check the LUT is ok. + auto pL = std::dynamic_pointer_cast(opList[1]); + OCIO_REQUIRE_ASSERT(pL); + OCIO_CHECK_EQUAL(pL->getArray().getLength(), 32u); + OCIO_CHECK_EQUAL(pL->getFileOutputBitDepth(), OCIO::BIT_DEPTH_UINT12); } -OCIO_ADD_TEST(FileFormatCTF, range1) +OCIO_ADD_TEST(FileFormatCTF, indexMap_test2_clfv2) { OCIO::LocalCachedFileRcPtr cachedFile; - const std::string ctfFile("range_test1.clf"); + const std::string ctfFile("indexMap_test2_clfv2.clf"); OCIO_CHECK_NO_THROW(cachedFile = LoadCLFFile(ctfFile)); OCIO_REQUIRE_ASSERT((bool)cachedFile); const OCIO::ConstOpDataVec & opList = cachedFile->m_transform->getOps(); - OCIO_REQUIRE_EQUAL(opList.size(), 1); + OCIO_REQUIRE_EQUAL(opList.size(), 2); auto pR = std::dynamic_pointer_cast(opList[0]); OCIO_REQUIRE_ASSERT(pR); - - OCIO_CHECK_EQUAL(pR->getFileInputBitDepth(), OCIO::BIT_DEPTH_UINT8); + OCIO_CHECK_EQUAL(pR->getMinInValue(), -0.1f); + OCIO_CHECK_EQUAL(pR->getMaxInValue(), 19.f); + OCIO_CHECK_EQUAL(pR->getMinOutValue(), 0.f); + OCIO_CHECK_EQUAL(pR->getMaxOutValue(), 1.f); + OCIO_CHECK_EQUAL(pR->getFileInputBitDepth(), OCIO::BIT_DEPTH_F32); OCIO_CHECK_EQUAL(pR->getFileOutputBitDepth(), OCIO::BIT_DEPTH_F32); - // NB: All exactly representable as flt - OCIO_CHECK_EQUAL(pR->getMinInValue(), 16. / 255.); - OCIO_CHECK_EQUAL(pR->getMaxInValue(), 235. / 255.); - OCIO_CHECK_EQUAL(pR->getMinOutValue(), -0.5); - OCIO_CHECK_EQUAL(pR->getMaxOutValue(), 2.); - OCIO_CHECK_ASSERT(!pR->minIsEmpty()); - OCIO_CHECK_ASSERT(!pR->maxIsEmpty()); + // Check the LUT is ok. + auto pL = std::dynamic_pointer_cast(opList[1]); + OCIO_REQUIRE_ASSERT(pL); + OCIO_CHECK_EQUAL(pL->getArray().getLength(), 2u); + OCIO_CHECK_EQUAL(pL->getFileOutputBitDepth(), OCIO::BIT_DEPTH_UINT10); } -OCIO_ADD_TEST(FileFormatCTF, range2) +OCIO_ADD_TEST(FileFormatCTF, clf3_index_map) { - const std::string ctfFile("range_test2.clf"); - OCIO_CHECK_THROW_WHAT(LoadCLFFile(ctfFile), OCIO::Exception, - "In and out minimum limits must be equal"); + // Same as previous, but setting compCLFversion=3.0. + const std::string ctfFile("clf/illegal/indexMap_test2.clf"); + static constexpr char Warning[1024] = + "Element 'IndexMap' is not valid since CLF 3 (or CTF 2)"; + + OCIO::LogGuard guard; + OCIO::SetLoggingLevel(OCIO::LOGGING_LEVEL_WARNING); + + OCIO::LocalCachedFileRcPtr cachedFile; + OCIO_CHECK_NO_THROW(cachedFile = LoadCLFFile(ctfFile)); + OCIO_REQUIRE_ASSERT((bool)cachedFile); + OCIO_CHECK_NE(std::string::npos, + StringUtils::Find( StringUtils::RightTrim(guard.output()), Warning )); } -OCIO_ADD_TEST(FileFormatCTF, range3) +OCIO_ADD_TEST(FileFormatCTF, indexMap_test3) { - const std::string ctfFile("range_test3.clf"); - OCIO_CHECK_THROW_WHAT(LoadCLFFile(ctfFile), OCIO::Exception, - "At least minimum or maximum limits must be set"); + const std::string ctfFile("indexMap_test3.ctf"); + OCIO_CHECK_THROW_WHAT(LoadCLFFile(ctfFile), OCIO::Exception, + "Only one IndexMap allowed per LUT"); } -OCIO_ADD_TEST(FileFormatCTF, range4) +OCIO_ADD_TEST(FileFormatCTF, indexMap_test4_clfv2) { - const std::string clf{ R"( - - - 0.1 - 0.1 - - -)" }; - - OCIO_CHECK_THROW_WHAT(ParseString(clf), OCIO::Exception, - "Non-clamping Range min & max values have to be set"); + const std::string ctfFile("indexMap_test4_clfv2.clf"); + OCIO_CHECK_THROW_WHAT(LoadCLFFile(ctfFile), OCIO::Exception, + "Only two entry IndexMaps are supported"); } -OCIO_ADD_TEST(FileFormatCTF, gamma1) +OCIO_ADD_TEST(FileFormatCTF, gamma_test1) { OCIO::LocalCachedFileRcPtr cachedFile; const std::string ctfFile("gamma_test1.ctf"); @@ -1516,7 +2075,7 @@ OCIO_ADD_TEST(FileFormatCTF, gamma1) OCIO_CHECK_ASSERT(pG->isNonChannelDependent()); // RGB are equal, A is an identity } -OCIO_ADD_TEST(FileFormatCTF, gamma2) +OCIO_ADD_TEST(FileFormatCTF, gamma_test2) { OCIO::LocalCachedFileRcPtr cachedFile; const std::string ctfFile("gamma_test2.ctf"); @@ -1547,7 +2106,7 @@ OCIO_ADD_TEST(FileFormatCTF, gamma2) OCIO_CHECK_ASSERT(!pG->isNonChannelDependent()); } -OCIO_ADD_TEST(FileFormatCTF, gamma3) +OCIO_ADD_TEST(FileFormatCTF, gamma_test3) { OCIO::LocalCachedFileRcPtr cachedFile; const std::string ctfFile("gamma_test3.ctf"); @@ -1577,7 +2136,7 @@ OCIO_ADD_TEST(FileFormatCTF, gamma3) OCIO_CHECK_ASSERT(pG->isNonChannelDependent()); } -OCIO_ADD_TEST(FileFormatCTF, gamma4) +OCIO_ADD_TEST(FileFormatCTF, gamma_test4) { OCIO::LocalCachedFileRcPtr cachedFile; const std::string ctfFile("gamma_test4.ctf"); @@ -1611,7 +2170,7 @@ OCIO_ADD_TEST(FileFormatCTF, gamma4) OCIO_CHECK_ASSERT(!pG->isNonChannelDependent()); } -OCIO_ADD_TEST(FileFormatCTF, gamma5) +OCIO_ADD_TEST(FileFormatCTF, gamma_test5) { // This test is for an old (< 1.5) transform file that contains // an invalid GammaParams for the A channel. @@ -1620,7 +2179,7 @@ OCIO_ADD_TEST(FileFormatCTF, gamma5) "Invalid channel"); } -OCIO_ADD_TEST(FileFormatCTF, gamma6) +OCIO_ADD_TEST(FileFormatCTF, gamma_test6) { // This test is for an old (< 1.5) transform file that contains // a single GammaParams with identity values: @@ -1642,15 +2201,7 @@ OCIO_ADD_TEST(FileFormatCTF, gamma6) OCIO_CHECK_ASSERT(pG->isIdentity()); } -OCIO_ADD_TEST(FileFormatCTF, gamma_wrong_power) -{ - // The moncurve style requires a gamma value >= 1. - const std::string ctfFile("gamma_wrong_power.ctf"); - OCIO_CHECK_THROW_WHAT(LoadCLFFile(ctfFile), OCIO::Exception, - "is less than lower bound"); -} - -OCIO_ADD_TEST(FileFormatCTF, gamma_alpha1) +OCIO_ADD_TEST(FileFormatCTF, gamma_alpha_test1) { // This test is for a new (>= 1.5) transform file that contains // a single GammaParams: @@ -1682,7 +2233,7 @@ OCIO_ADD_TEST(FileFormatCTF, gamma_alpha1) OCIO_CHECK_ASSERT(pG->isNonChannelDependent()); } -OCIO_ADD_TEST(FileFormatCTF, gamma_alpha2) +OCIO_ADD_TEST(FileFormatCTF, gamma_alpha_test2) { // This test is for a new (>= 1.5) transform file that contains // a different GammaParams for every channel: @@ -1717,7 +2268,7 @@ OCIO_ADD_TEST(FileFormatCTF, gamma_alpha2) OCIO_CHECK_ASSERT(!pG->isNonChannelDependent()); } -OCIO_ADD_TEST(FileFormatCTF, gamma_alpha3) +OCIO_ADD_TEST(FileFormatCTF, gamma_alpha_test3) { // This test is for a new (>= 1.5) transform file that contains // a single GammaParams: @@ -1750,7 +2301,7 @@ OCIO_ADD_TEST(FileFormatCTF, gamma_alpha3) OCIO_CHECK_ASSERT(pG->isNonChannelDependent()); } -OCIO_ADD_TEST(FileFormatCTF, gamma_alpha4) +OCIO_ADD_TEST(FileFormatCTF, gamma_alpha_test4) { // This test is for a new (>= 1.5) transform file that contains // a different GammaParams for every channel: @@ -1789,7 +2340,7 @@ OCIO_ADD_TEST(FileFormatCTF, gamma_alpha4) OCIO_CHECK_ASSERT(!pG->isNonChannelDependent()); } -OCIO_ADD_TEST(FileFormatCTF, gamma_alpha5) +OCIO_ADD_TEST(FileFormatCTF, gamma_alpha_test5) { // This test is for a new (>= 1.5) transform file that contains // a GammaParams with no channel specified: @@ -1824,7 +2375,7 @@ OCIO_ADD_TEST(FileFormatCTF, gamma_alpha5) OCIO_CHECK_ASSERT(!pG->isNonChannelDependent()); } -OCIO_ADD_TEST(FileFormatCTF, gamma_alpha6) +OCIO_ADD_TEST(FileFormatCTF, gamma_alpha_test6) { // This test is for an new (>= 1.5) transform file that contains // an invalid GammaParams for the A channel (missing offset attribute). @@ -1833,7 +2384,169 @@ OCIO_ADD_TEST(FileFormatCTF, gamma_alpha6) "Missing required offset parameter"); } -OCIO_ADD_TEST(FileFormatCTF, gamma_parse) +OCIO_ADD_TEST(FileFormatCTF, exponent_bad_value) +{ + // The moncurve style requires a gamma value >= 1. + const std::string ctfFile("clf/illegal/exponent_bad_value.clf"); + OCIO_CHECK_THROW_WHAT(LoadCLFFile(ctfFile), OCIO::Exception, + "is less than lower bound"); +} + +OCIO_ADD_TEST(FileFormatCTF, exponent_bad_param) +{ + // The basic style cannot use offset. + const std::string ctfFile("clf/illegal/exponent_bad_param.clf"); + OCIO_CHECK_THROW_WHAT(LoadCLFFile(ctfFile), OCIO::Exception, + "Illegal offset parameter"); +} + +OCIO_ADD_TEST(FileFormatCTF, exponent_all_styles) +{ + // Note: This is somewhat repetitive of the CTF Gamma tests above, but it is worth + // having both due to changes in the format over time (e.g. moncurveFwd->monCurveFwd, + // and gamma->exponent), and the fact that CLF and early CTF does not support alpha. + OCIO::LocalCachedFileRcPtr cachedFile; + const std::string fileName("clf/exponent_all_styles.clf"); + OCIO_CHECK_NO_THROW(cachedFile = LoadCLFFile(fileName)); + const OCIO::ConstOpDataVec & opList = cachedFile->m_transform->getOps(); + OCIO_REQUIRE_EQUAL(opList.size(), 11); + + { // Op 0 == basicFwd. + auto opData = std::dynamic_pointer_cast(opList[0]); + OCIO_REQUIRE_ASSERT(opData); + StringUtils::StringVec desc; + GetElementsValues(opData->getFormatMetadata().getChildrenElements(), + OCIO::TAG_DESCRIPTION, desc); + OCIO_REQUIRE_EQUAL(desc.size(), 1); + OCIO_CHECK_EQUAL(desc[0], "If there is only one Params, use it for R, G, and B."); + OCIO_CHECK_EQUAL(opData->getDirection(), OCIO::TRANSFORM_DIR_FORWARD); + OCIO_CHECK_EQUAL(opData->getStyle(), OCIO::GammaOpData::BASIC_FWD); + OCIO_CHECK_ASSERT(opData->isNonChannelDependent()); // RGB are equal, A is an identity + OCIO_CHECK_ASSERT(opData->isAlphaComponentIdentity()); + OCIO::GammaOpData::Params params; + params.push_back(2.4); + OCIO_CHECK_ASSERT(opData->getRedParams() == params); + } + { // Op 1 == basicRev. + auto opData = std::dynamic_pointer_cast(opList[1]); + OCIO_REQUIRE_ASSERT(opData); + OCIO_CHECK_EQUAL(opData->getID(), "a1"); + OCIO_CHECK_EQUAL(opData->getName(), "gamma"); + OCIO_CHECK_EQUAL(opData->getDirection(), OCIO::TRANSFORM_DIR_INVERSE); + OCIO_CHECK_EQUAL(opData->getStyle(), OCIO::GammaOpData::BASIC_REV); + OCIO_CHECK_ASSERT(!opData->isNonChannelDependent()); + OCIO_CHECK_ASSERT(opData->isAlphaComponentIdentity()); + OCIO::GammaOpData::Params paramsR; + paramsR.push_back(2.4); + OCIO::GammaOpData::Params paramsG; + paramsG.push_back(2.35); + OCIO::GammaOpData::Params paramsB; + paramsB.push_back(2.2); + OCIO_CHECK_ASSERT(opData->getRedParams() == paramsR); + OCIO_CHECK_ASSERT(opData->getGreenParams() == paramsG); + OCIO_CHECK_ASSERT(opData->getBlueParams() == paramsB); + } + { // Op 2 == monCurveFwd. + auto opData = std::dynamic_pointer_cast(opList[2]); + OCIO_REQUIRE_ASSERT(opData); + OCIO_CHECK_EQUAL(opData->getDirection(), OCIO::TRANSFORM_DIR_FORWARD); + OCIO_CHECK_EQUAL(opData->getStyle(), OCIO::GammaOpData::MONCURVE_FWD); + OCIO_CHECK_ASSERT(opData->isNonChannelDependent()); // RGB are equal, A is an identity + OCIO_CHECK_ASSERT(opData->isAlphaComponentIdentity()); + OCIO::GammaOpData::Params params; + params.push_back(1./0.45); + params.push_back(0.099); + OCIO_CHECK_ASSERT(opData->getRedParams() == params); + } + { // Op 3 == monCurveRev. + auto opData = std::dynamic_pointer_cast(opList[3]); + OCIO_REQUIRE_ASSERT(opData); + OCIO_CHECK_EQUAL(opData->getDirection(), OCIO::TRANSFORM_DIR_INVERSE); + OCIO_CHECK_EQUAL(opData->getStyle(), OCIO::GammaOpData::MONCURVE_REV); + OCIO_CHECK_ASSERT(!opData->isNonChannelDependent()); + OCIO_CHECK_ASSERT(opData->isAlphaComponentIdentity()); + OCIO::GammaOpData::Params paramsR; + paramsR.push_back(2.2); + paramsR.push_back(0.001); + OCIO::GammaOpData::Params paramsG; + paramsG.push_back(2.4); + paramsG.push_back(0.01); + OCIO::GammaOpData::Params paramsB; + paramsB.push_back(2.6); + paramsB.push_back(0.1); + OCIO_CHECK_ASSERT(opData->getRedParams() == paramsR); + OCIO_CHECK_ASSERT(opData->getGreenParams() == paramsG); + OCIO_CHECK_ASSERT(opData->getBlueParams() == paramsB); + } + { // Op 4 == monCurveFwd. + auto opData = std::dynamic_pointer_cast(opList[4]); + OCIO_REQUIRE_ASSERT(opData); + OCIO_CHECK_EQUAL(opData->getDirection(), OCIO::TRANSFORM_DIR_FORWARD); + OCIO_CHECK_EQUAL(opData->getStyle(), OCIO::GammaOpData::MONCURVE_FWD); + OCIO_CHECK_ASSERT(opData->areAllComponentsEqual()); + OCIO_CHECK_ASSERT(opData->isNonChannelDependent()); // RGB are equal, A is an identity + OCIO_CHECK_ASSERT(opData->isAlphaComponentIdentity()); + OCIO_CHECK_ASSERT(OCIO::GammaOpData::isIdentityParameters( + opData->getRedParams(), + opData->getStyle())); + } + { // Op 5 == basicMirrorFwd. + auto opData = std::dynamic_pointer_cast(opList[5]); + OCIO_REQUIRE_ASSERT(opData); + OCIO_CHECK_EQUAL(opData->getDirection(), OCIO::TRANSFORM_DIR_FORWARD); + OCIO_CHECK_EQUAL(opData->getStyle(), OCIO::GammaOpData::BASIC_MIRROR_FWD); + OCIO_CHECK_ASSERT(!opData->areAllComponentsEqual()); + OCIO_CHECK_ASSERT(opData->isNonChannelDependent()); // RGB are equal, A is an identity + OCIO_CHECK_ASSERT(opData->isAlphaComponentIdentity()); + } + { // Op 6 == basicMirrorRev. + auto opData = std::dynamic_pointer_cast(opList[6]); + OCIO_REQUIRE_ASSERT(opData); + OCIO_CHECK_EQUAL(opData->getDirection(), OCIO::TRANSFORM_DIR_INVERSE); + OCIO_CHECK_EQUAL(opData->getStyle(), OCIO::GammaOpData::BASIC_MIRROR_REV); + OCIO_CHECK_ASSERT(opData->isNonChannelDependent()); // RGB are equal, A is an identity + } + { // Op 7 == basicPassThruFwd. + auto opData = std::dynamic_pointer_cast(opList[7]); + OCIO_REQUIRE_ASSERT(opData); + OCIO_CHECK_EQUAL(opData->getDirection(), OCIO::TRANSFORM_DIR_FORWARD); + OCIO_CHECK_EQUAL(opData->getStyle(), OCIO::GammaOpData::BASIC_PASS_THRU_FWD); + OCIO_CHECK_ASSERT(opData->isNonChannelDependent()); // RGB are equal, A is an identity + } + { // Op 8 == basicPassThruRev. + auto opData = std::dynamic_pointer_cast(opList[8]); + OCIO_REQUIRE_ASSERT(opData); + OCIO_CHECK_EQUAL(opData->getDirection(), OCIO::TRANSFORM_DIR_INVERSE); + OCIO_CHECK_EQUAL(opData->getStyle(), OCIO::GammaOpData::BASIC_PASS_THRU_REV); + OCIO_CHECK_ASSERT(opData->isNonChannelDependent()); // RGB are equal, A is an identity + } + { // Op 9 == monCurveMirrorFwd. + auto opData = std::dynamic_pointer_cast(opList[9]); + OCIO_REQUIRE_ASSERT(opData); + OCIO_CHECK_EQUAL(opData->getDirection(), OCIO::TRANSFORM_DIR_FORWARD); + OCIO_CHECK_EQUAL(opData->getStyle(), OCIO::GammaOpData::MONCURVE_MIRROR_FWD); + OCIO_CHECK_ASSERT(opData->isNonChannelDependent()); // RGB are equal, A is an identity + } + { // Op 10 == monCurveMirrorRev. + auto opData = std::dynamic_pointer_cast(opList[10]); + OCIO_REQUIRE_ASSERT(opData); + OCIO_CHECK_EQUAL(opData->getDirection(), OCIO::TRANSFORM_DIR_INVERSE); + OCIO_CHECK_EQUAL(opData->getStyle(), OCIO::GammaOpData::MONCURVE_MIRROR_REV); + OCIO_CHECK_ASSERT(!opData->isNonChannelDependent()); + OCIO::GammaOpData::Params paramsR; + paramsR.push_back(3.0); + paramsR.push_back(0.16); + OCIO_CHECK_ASSERT(opData->getRedParams() == paramsR); + OCIO_CHECK_ASSERT(OCIO::GammaOpData::isIdentityParameters( + opData->getGreenParams(), + opData->getStyle())); + OCIO_CHECK_ASSERT(OCIO::GammaOpData::isIdentityParameters( + opData->getBlueParams(), + opData->getStyle())); + } +} + +OCIO_ADD_TEST(FileFormatCTF, clf2_exponent_parse) { const std::string gammaCLF2{ R"( @@ -1858,74 +2571,22 @@ OCIO_ADD_TEST(FileFormatCTF, gamma_parse) OCIO_CHECK_THROW_WHAT(ParseString(gammaCLFAlpha), OCIO::Exception, "Invalid channel: A"); - const std::string gammaCTFMirror1_7{ R"( - - - - - -)" }; - - OCIO_CHECK_THROW_WHAT(ParseString(gammaCTFMirror1_7), OCIO::Exception, - "Style not handled: 'basicMirrorRev'"); -} - -OCIO_ADD_TEST(FileFormatCTF, invalid_version) -{ - const std::string ctfFile("process_list_invalid_version.ctf"); - OCIO_CHECK_THROW_WHAT(LoadCLFFile(ctfFile), - OCIO::Exception, - "is not a valid version"); -} - -OCIO_ADD_TEST(FileFormatCTF, valid_version) -{ - OCIO::LocalCachedFileRcPtr cachedFile; - const std::string ctfFile("process_list_valid_version.ctf"); - OCIO_CHECK_NO_THROW(cachedFile = LoadCLFFile(ctfFile)); - - const OCIO::CTFVersion ctfVersion = - cachedFile->m_transform->getCTFVersion(); - OCIO_CHECK_EQUAL(ctfVersion, OCIO::CTF_PROCESS_LIST_VERSION_1_4); -} - -OCIO_ADD_TEST(FileFormatCTF, higher_version) -{ - const std::string ctfFile("process_list_higher_version.ctf"); - OCIO_CHECK_THROW_WHAT(LoadCLFFile(ctfFile), - OCIO::Exception, - "Unsupported transform file version"); -} - -OCIO_ADD_TEST(FileFormatCTF, version_revision) -{ - OCIO::LocalCachedFileRcPtr cachedFile; - const std::string ctfFile("process_list_version_revision.ctf"); - OCIO_CHECK_NO_THROW(cachedFile = LoadCLFFile(ctfFile)); - - const OCIO::CTFVersion ctfVersion = - cachedFile->m_transform->getCTFVersion(); - const OCIO::CTFVersion ver(1, 3, 10); - OCIO_CHECK_EQUAL(ctfVersion, ver); - OCIO_CHECK_ASSERT(OCIO::CTF_PROCESS_LIST_VERSION_1_3 < ctfVersion); - OCIO_CHECK_ASSERT(ctfVersion < OCIO::CTF_PROCESS_LIST_VERSION_1_4); -} - -OCIO_ADD_TEST(FileFormatCTF, no_version) -{ - OCIO::LocalCachedFileRcPtr cachedFile; - const std::string ctfFile("process_list_no_version.ctf"); - OCIO_CHECK_NO_THROW(cachedFile = LoadCLFFile(ctfFile)); + const std::string gammaCTFMirror1_7{ R"( + + + + + +)" }; - const OCIO::CTFVersion ctfVersion = - cachedFile->m_transform->getCTFVersion(); - OCIO_CHECK_EQUAL(ctfVersion, OCIO::CTF_PROCESS_LIST_VERSION_1_2); + OCIO_CHECK_THROW_WHAT(ParseString(gammaCTFMirror1_7), OCIO::Exception, + "Style not handled: 'basicMirrorRev'"); } -OCIO_ADD_TEST(FileFormatCTF, cdl) +OCIO_ADD_TEST(FileFormatCTF, cdl_clamp_fwd) { OCIO::LocalCachedFileRcPtr cachedFile; - const std::string ctfFile("cdl_clamp_fwd.clf"); + const std::string ctfFile("clf/cdl_clamp_fwd.clf"); OCIO_CHECK_NO_THROW(cachedFile = LoadCLFFile(ctfFile)); OCIO_REQUIRE_ASSERT((bool)cachedFile); @@ -1961,59 +2622,10 @@ OCIO_ADD_TEST(FileFormatCTF, cdl) OCIO_CHECK_EQUAL(pCDL->getSaturation(), 1.239); } -OCIO_ADD_TEST(FileFormatCTF, cdl_invalid_sop_node) -{ - const std::string ctfFile("cdl_invalidSOP.clf"); - OCIO_CHECK_THROW_WHAT(LoadCLFFile(ctfFile), OCIO::Exception, - "SOPNode: 3 values required"); -} - -OCIO_ADD_TEST(FileFormatCTF, cdl_invalid_sat_node) -{ - const std::string ctfFile("cdl_invalidSat.clf"); - OCIO_CHECK_THROW_WHAT(LoadCLFFile(ctfFile), OCIO::Exception, - "SatNode: non-single value"); -} - -OCIO_ADD_TEST(FileFormatCTF, cdl_missing_slope) -{ - const std::string ctfFile("cdl_missing_slope.clf"); - OCIO_CHECK_THROW_WHAT(LoadCLFFile(ctfFile), OCIO::Exception, - "Required node 'Slope' is missing"); -} - -OCIO_ADD_TEST(FileFormatCTF, cdl_missing_offset) -{ - const std::string ctfFile("cdl_missing_offset.clf"); - OCIO_CHECK_THROW_WHAT(LoadCLFFile(ctfFile), OCIO::Exception, - "Required node 'Offset' is missing"); -} - -OCIO_ADD_TEST(FileFormatCTF, cdl_missing_power) -{ - const std::string ctfFile("cdl_missing_power.clf"); - OCIO_CHECK_THROW_WHAT(LoadCLFFile(ctfFile), OCIO::Exception, - "Required node 'Power' is missing"); -} - OCIO_ADD_TEST(FileFormatCTF, cdl_missing_style) -{ - const std::string ctfFile("cdl_missing_style.clf"); - OCIO_CHECK_THROW_WHAT(LoadCLFFile(ctfFile), OCIO::Exception, - "Required attribute 'style' is missing"); -} - -OCIO_ADD_TEST(FileFormatCTF, cdl_invalid_style) -{ - const std::string ctfFile("cdl_invalid_style.clf"); - OCIO_CHECK_THROW_WHAT(LoadCLFFile(ctfFile), OCIO::Exception, - "Unknown style for CDL"); -} - -OCIO_ADD_TEST(FileFormatCTF, cdl_no_sop_node) { OCIO::LocalCachedFileRcPtr cachedFile; - const std::string ctfFile("cdl_noSOP.clf"); + const std::string ctfFile("clf/cdl_missing_style.clf"); OCIO_CHECK_NO_THROW(cachedFile = LoadCLFFile(ctfFile)); OCIO_REQUIRE_ASSERT((bool)cachedFile); @@ -2022,513 +2634,352 @@ OCIO_ADD_TEST(FileFormatCTF, cdl_no_sop_node) auto pCDL = std::dynamic_pointer_cast(opList[0]); OCIO_REQUIRE_ASSERT(pCDL); - OCIO_CHECK_ASSERT(pCDL->getSlopeParams() - == OCIO::CDLOpData::ChannelParams(1.0)); - OCIO_CHECK_ASSERT(pCDL->getOffsetParams() - == OCIO::CDLOpData::ChannelParams(0.0)); - OCIO_CHECK_ASSERT(pCDL->getPowerParams() - == OCIO::CDLOpData::ChannelParams(1.0)); - OCIO_CHECK_EQUAL(pCDL->getSaturation(), 1.239); -} - -OCIO_ADD_TEST(FileFormatCTF, cdl_no_sat_node) -{ - OCIO::LocalCachedFileRcPtr cachedFile; - const std::string ctfFile("cdl_noSat.clf"); - OCIO_CHECK_NO_THROW(cachedFile = LoadCLFFile(ctfFile)); - OCIO_REQUIRE_ASSERT((bool)cachedFile); - - const OCIO::ConstOpDataVec & opList = cachedFile->m_transform->getOps(); - OCIO_REQUIRE_EQUAL(opList.size(), 1); - auto pCDL = std::dynamic_pointer_cast(opList[0]); - OCIO_REQUIRE_ASSERT(pCDL); + // Note: Default for CLF is different from OCIO default. + OCIO_CHECK_EQUAL(pCDL->getStyle(), OCIO::CDLOpData::CDL_V1_2_FWD); - OCIO_CHECK_ASSERT(pCDL->getSlopeParams() + OCIO_CHECK_ASSERT(pCDL->getSlopeParams() == OCIO::CDLOpData::ChannelParams(1.35, 1.1, 0.71)); OCIO_CHECK_ASSERT(pCDL->getOffsetParams() == OCIO::CDLOpData::ChannelParams(0.05, -0.23, 0.11)); OCIO_CHECK_ASSERT(pCDL->getPowerParams() == OCIO::CDLOpData::ChannelParams(0.93, 0.81, 1.27)); - OCIO_CHECK_EQUAL(pCDL->getSaturation(), 1.0); + OCIO_CHECK_EQUAL(pCDL->getSaturation(), 1.239); } -OCIO_ADD_TEST(FileFormatCTF, cdl_various_in_ctf) +OCIO_ADD_TEST(FileFormatCTF, cdl_all_styles) { OCIO::LocalCachedFileRcPtr cachedFile; - const std::string ctfFile("cdl_various.ctf"); + const std::string ctfFile("clf/cdl_all_styles.clf"); OCIO_CHECK_NO_THROW(cachedFile = LoadCLFFile(ctfFile)); OCIO_REQUIRE_ASSERT((bool)cachedFile); const OCIO::ConstOpDataVec & opList = cachedFile->m_transform->getOps(); - OCIO_REQUIRE_EQUAL(opList.size(), 8); + OCIO_REQUIRE_EQUAL(opList.size(), 4); + auto pCDL = std::dynamic_pointer_cast(opList[0]); OCIO_REQUIRE_ASSERT(pCDL); OCIO_CHECK_EQUAL(pCDL->getStyle(), OCIO::CDLOpData::CDL_V1_2_FWD); pCDL = std::dynamic_pointer_cast(opList[1]); OCIO_REQUIRE_ASSERT(pCDL); - OCIO_CHECK_EQUAL(pCDL->getStyle(), OCIO::CDLOpData::CDL_V1_2_FWD); - - pCDL = std::dynamic_pointer_cast(opList[2]); - OCIO_REQUIRE_ASSERT(pCDL); - OCIO_CHECK_EQUAL(pCDL->getStyle(), OCIO::CDLOpData::CDL_V1_2_REV); - - pCDL = std::dynamic_pointer_cast(opList[3]); - OCIO_REQUIRE_ASSERT(pCDL); OCIO_CHECK_EQUAL(pCDL->getStyle(), OCIO::CDLOpData::CDL_V1_2_REV); - pCDL = std::dynamic_pointer_cast(opList[4]); - OCIO_REQUIRE_ASSERT(pCDL); - OCIO_CHECK_EQUAL(pCDL->getStyle(), OCIO::CDLOpData::CDL_NO_CLAMP_FWD); - - pCDL = std::dynamic_pointer_cast(opList[5]); + pCDL = std::dynamic_pointer_cast(opList[2]); OCIO_REQUIRE_ASSERT(pCDL); OCIO_CHECK_EQUAL(pCDL->getStyle(), OCIO::CDLOpData::CDL_NO_CLAMP_FWD); - pCDL = std::dynamic_pointer_cast(opList[6]); - OCIO_REQUIRE_ASSERT(pCDL); - OCIO_CHECK_EQUAL(pCDL->getStyle(), OCIO::CDLOpData::CDL_NO_CLAMP_REV); - - pCDL = std::dynamic_pointer_cast(opList[7]); + pCDL = std::dynamic_pointer_cast(opList[3]); OCIO_REQUIRE_ASSERT(pCDL); OCIO_CHECK_EQUAL(pCDL->getStyle(), OCIO::CDLOpData::CDL_NO_CLAMP_REV); } -OCIO_ADD_TEST(FileFormatCTF, lut1d_hue_adjust_invalid_style) -{ - const std::string ctfFile("lut1d_hue_adjust_invalid_style.clf"); - OCIO_CHECK_THROW_WHAT(LoadCLFFile(ctfFile), OCIO::Exception, - "Illegal 'hueAdjust' attribute"); -} - -OCIO_ADD_TEST(FileFormatCTF, metadata) -{ - OCIO::LocalCachedFileRcPtr cachedFile; - const std::string ctfFile("metadata.clf"); - OCIO_CHECK_NO_THROW(cachedFile = LoadCLFFile(ctfFile)); - OCIO_REQUIRE_ASSERT((bool)cachedFile); - - OCIO_CHECK_EQUAL(cachedFile->m_transform->getInputDescriptor(), - "inputDesc"); - OCIO_CHECK_EQUAL(cachedFile->m_transform->getOutputDescriptor(), - "outputDesc"); - - // Ensure ops were not affected by metadata parsing. - const OCIO::ConstOpDataVec & opList = cachedFile->m_transform->getOps(); - OCIO_REQUIRE_EQUAL(opList.size(), 1); - - auto pMatrix = - std::dynamic_pointer_cast(opList[0]); - OCIO_REQUIRE_ASSERT(pMatrix); - OCIO_CHECK_EQUAL(pMatrix->getName(), "identity"); - - OCIO_CHECK_EQUAL(pMatrix->getFileInputBitDepth(), OCIO::BIT_DEPTH_F32); - OCIO_CHECK_EQUAL(pMatrix->getFileOutputBitDepth(), OCIO::BIT_DEPTH_UINT12); - - const OCIO::FormatMetadataImpl & info = cachedFile->m_transform->getInfoMetadata(); - - // Check element values. - // - OCIO_CHECK_EQUAL(std::string(info.getName()), OCIO::METADATA_INFO); - auto items = info.getChildrenElements(); - OCIO_REQUIRE_EQUAL(items.size(), 5); - OCIO_CHECK_EQUAL(std::string(items[0].getName()), "Copyright"); - OCIO_CHECK_EQUAL(std::string(items[0].getValue()), "Copyright Contributors to the OpenColorIO Project."); - OCIO_CHECK_EQUAL(std::string(items[1].getName()), "Release"); - OCIO_CHECK_EQUAL(std::string(items[1].getValue()), "2015"); - OCIO_CHECK_EQUAL(std::string(items[2].getName()), "InputColorSpace"); - OCIO_CHECK_EQUAL(std::string(items[2].getValue()), ""); - auto icItems = items[2].getChildrenElements(); - OCIO_REQUIRE_EQUAL(icItems.size(), 3); - OCIO_CHECK_EQUAL(std::string(icItems[0].getName()), OCIO::METADATA_DESCRIPTION); - OCIO_CHECK_EQUAL(std::string(icItems[0].getValue()), "Input color space description"); - OCIO_CHECK_EQUAL(std::string(icItems[1].getName()), "Profile"); - OCIO_CHECK_EQUAL(std::string(icItems[1].getValue()), "Input color space profile"); - OCIO_CHECK_EQUAL(std::string(icItems[2].getName()), "Empty"); - OCIO_CHECK_EQUAL(std::string(icItems[2].getValue()), ""); - - OCIO_CHECK_EQUAL(std::string(items[3].getName()), "OutputColorSpace"); - OCIO_CHECK_EQUAL(std::string(items[3].getValue()), ""); - auto ocItems = items[3].getChildrenElements(); - OCIO_REQUIRE_EQUAL(ocItems.size(), 2); - OCIO_CHECK_EQUAL(std::string(ocItems[0].getName()), OCIO::METADATA_DESCRIPTION); - OCIO_CHECK_EQUAL(std::string(ocItems[0].getValue()), "Output color space description"); - OCIO_CHECK_EQUAL(std::string(ocItems[1].getName()), "Profile"); - OCIO_CHECK_EQUAL(std::string(ocItems[1].getValue()), "Output color space profile"); - - OCIO_CHECK_EQUAL(std::string(items[4].getName()), "Category"); - OCIO_CHECK_EQUAL(std::string(items[4].getValue()), ""); - auto catItems = items[4].getChildrenElements(); - OCIO_REQUIRE_EQUAL(catItems.size(), 1); - OCIO_CHECK_EQUAL(std::string(catItems[0].getName()), "Name"); - OCIO_CHECK_EQUAL(std::string(catItems[0].getValue()), "Category name"); - auto attribs = catItems[0].getAttributes(); - OCIO_REQUIRE_EQUAL(attribs.size(), 2); - OCIO_CHECK_EQUAL(attribs[0].first, "att1"); - OCIO_CHECK_EQUAL(attribs[0].second, "test1"); - OCIO_CHECK_EQUAL(attribs[1].first, "att2"); - OCIO_CHECK_EQUAL(attribs[1].second, "test2"); -} - -OCIO_ADD_TEST(FileFormatCTF, index_map_1) -{ - OCIO::LocalCachedFileRcPtr cachedFile; - const std::string ctfFile("indexMap_test1.clf"); - OCIO_CHECK_NO_THROW(cachedFile = LoadCLFFile(ctfFile)); - OCIO_REQUIRE_ASSERT((bool)cachedFile); - - const OCIO::ConstOpDataVec & opList = cachedFile->m_transform->getOps(); - OCIO_REQUIRE_EQUAL(opList.size(), 2); - auto pR = std::dynamic_pointer_cast(opList[0]); - OCIO_REQUIRE_ASSERT(pR); - - // Check that the indexMap caused a Range to be inserted. - OCIO_CHECK_EQUAL(pR->getMinInValue() * 1023., 64.5); - OCIO_CHECK_EQUAL(pR->getMaxInValue() * 1023., 940.); - OCIO_CHECK_EQUAL(pR->getMinOutValue() * 1023.0, 132.0); // 4*1023/31 - OCIO_CHECK_EQUAL(pR->getMaxOutValue() * 1023.0, 1089.0); // 33*1023/31 - OCIO_CHECK_EQUAL(pR->getFileInputBitDepth(), OCIO::BIT_DEPTH_UINT10); - OCIO_CHECK_EQUAL(pR->getFileOutputBitDepth(), OCIO::BIT_DEPTH_UINT10); - - // Check the LUT is ok. - auto pL = std::dynamic_pointer_cast(opList[1]); - OCIO_REQUIRE_ASSERT(pL); - OCIO_CHECK_EQUAL(pL->getArray().getLength(), 32u); - OCIO_CHECK_EQUAL(pL->getFileOutputBitDepth(), OCIO::BIT_DEPTH_UINT12); -} - -OCIO_ADD_TEST(FileFormatCTF, index_map_2) +OCIO_ADD_TEST(FileFormatCTF, cdl_bad_slope) { - OCIO::LocalCachedFileRcPtr cachedFile; - const std::string ctfFile("indexMap_test2.clf"); - OCIO_CHECK_NO_THROW(cachedFile = LoadCLFFile(ctfFile)); - OCIO_REQUIRE_ASSERT((bool)cachedFile); - - const OCIO::ConstOpDataVec & opList = cachedFile->m_transform->getOps(); - OCIO_REQUIRE_EQUAL(opList.size(), 2); - auto pR = std::dynamic_pointer_cast(opList[0]); - OCIO_REQUIRE_ASSERT(pR); - // Range is from an IndexMap that manages floats. - OCIO_CHECK_EQUAL(pR->getMinInValue(), -0.1f); - OCIO_CHECK_EQUAL(pR->getMaxInValue(), 19.f); - OCIO_CHECK_EQUAL(pR->getMinOutValue(), 0.f); - OCIO_CHECK_EQUAL(pR->getMaxOutValue(), 1.f); - OCIO_CHECK_EQUAL(pR->getFileInputBitDepth(), OCIO::BIT_DEPTH_F32); - OCIO_CHECK_EQUAL(pR->getFileOutputBitDepth(), OCIO::BIT_DEPTH_F32); - - // Check the LUT is ok. - auto pL = std::dynamic_pointer_cast(opList[1]); - OCIO_REQUIRE_ASSERT(pL); - OCIO_CHECK_EQUAL(pL->getArray().getLength(), 2u); - OCIO_CHECK_EQUAL(pL->getFileOutputBitDepth(), OCIO::BIT_DEPTH_UINT10); + const std::string ctfFile("clf/illegal/cdl_bad_slope.clf"); + OCIO_CHECK_THROW_WHAT(LoadCLFFile(ctfFile), OCIO::Exception, + "SOPNode: 3 values required"); } - -OCIO_ADD_TEST(FileFormatCTF, index_map_3) + +OCIO_ADD_TEST(FileFormatCTF, cdl_bad_sat) { - const std::string ctfFile("indexMap_test3.clf"); + const std::string ctfFile("clf/illegal/cdl_bad_sat.clf"); OCIO_CHECK_THROW_WHAT(LoadCLFFile(ctfFile), OCIO::Exception, - "Only one IndexMap allowed per LUT"); + "SatNode: non-single value"); } -OCIO_ADD_TEST(FileFormatCTF, index_map_4) +OCIO_ADD_TEST(FileFormatCTF, cdl_bad_power) { - const std::string ctfFile("indexMap_test4.clf"); + const std::string ctfFile("clf/illegal/cdl_bad_power.clf"); OCIO_CHECK_THROW_WHAT(LoadCLFFile(ctfFile), OCIO::Exception, - "Only two entry IndexMaps are supported"); + "CDLOpData: Invalid 'power' 0 should be greater than 0."); } -OCIO_ADD_TEST(FileFormatCTF, clf_future_version) +OCIO_ADD_TEST(FileFormatCTF, cdl_missing_slope) { - const std::string ctfFile("clf_version_future.clf"); - OCIO_CHECK_THROW_WHAT(LoadCLFFile(ctfFile), OCIO::Exception, - "Unsupported transform file version"); + const std::string ctfFile("clf/illegal/cdl_missing_slope.clf"); + OCIO_CHECK_THROW_WHAT(LoadCLFFile(ctfFile), OCIO::Exception, + "Required node 'Slope' is missing"); } -OCIO_ADD_TEST(FileFormatCTF, clf_1) +OCIO_ADD_TEST(FileFormatCTF, cdl_missing_offset) { - OCIO::LocalCachedFileRcPtr cachedFile; - const std::string ctfFile("multiple_ops.clf"); - OCIO_CHECK_NO_THROW(cachedFile = LoadCLFFile(ctfFile)); - const OCIO::ConstOpDataVec & opList = cachedFile->m_transform->getOps(); - OCIO_REQUIRE_EQUAL(opList.size(), 6); - // First one is a CDL - auto cdlOpData = std::dynamic_pointer_cast(opList[0]); - OCIO_REQUIRE_ASSERT(cdlOpData); - StringUtils::StringVec desc; - GetElementsValues(cdlOpData->getFormatMetadata().getChildrenElements(), - OCIO::TAG_DESCRIPTION, desc); - - OCIO_REQUIRE_EQUAL(desc.size(), 1); - OCIO_CHECK_EQUAL(desc[0], "scene 1 exterior look"); - OCIO_CHECK_EQUAL(cdlOpData->getStyle(), OCIO::CDLOpData::CDL_V1_2_REV); - OCIO_CHECK_ASSERT(cdlOpData->getSlopeParams() - == OCIO::CDLOpData::ChannelParams(1., 1., 0.8)); - OCIO_CHECK_ASSERT(cdlOpData->getOffsetParams() - == OCIO::CDLOpData::ChannelParams(-0.02, 0., 0.15)); - OCIO_CHECK_ASSERT(cdlOpData->getPowerParams() - == OCIO::CDLOpData::ChannelParams(1.05, 1.15, 1.4)); - OCIO_CHECK_EQUAL(cdlOpData->getSaturation(), 0.75); - - // Next one in file is a lut1d, but it has an index map, - // thus a range was inserted before the LUT. - auto rangeOpData = std::dynamic_pointer_cast(opList[1]); - OCIO_REQUIRE_ASSERT(rangeOpData); - OCIO_CHECK_EQUAL(rangeOpData->getFileInputBitDepth(), OCIO::BIT_DEPTH_UINT10); - OCIO_CHECK_EQUAL(rangeOpData->getFileOutputBitDepth(), OCIO::BIT_DEPTH_UINT10); - OCIO_CHECK_EQUAL(rangeOpData->getMinInValue() * 1023., 64.5); - OCIO_CHECK_EQUAL(rangeOpData->getMaxInValue() * 1023., 940.); - OCIO_CHECK_EQUAL(rangeOpData->getMinOutValue() * 1023., 132.); // 4*1023/31 - OCIO_CHECK_EQUAL(rangeOpData->getMaxOutValue() * 1023., 957.); // 29*1023/31 - - // Lut1D. - auto l1OpData = std::dynamic_pointer_cast(opList[2]); - OCIO_REQUIRE_ASSERT(l1OpData); - OCIO_CHECK_EQUAL(l1OpData->getFileOutputBitDepth(), OCIO::BIT_DEPTH_UINT12); - desc.clear(); - GetElementsValues(l1OpData->getFormatMetadata().getChildrenElements(), - OCIO::TAG_DESCRIPTION, desc); - OCIO_CHECK_EQUAL(desc.size(), 0); - OCIO_CHECK_EQUAL(l1OpData->getArray().getLength(), 32u); - - // Check that the noClamp style Range became a Matrix. - auto matOpData = std::dynamic_pointer_cast(opList[3]); - OCIO_REQUIRE_ASSERT(matOpData); - OCIO_CHECK_EQUAL(matOpData->getFileInputBitDepth(), OCIO::BIT_DEPTH_UINT12); - OCIO_CHECK_EQUAL(matOpData->getFileOutputBitDepth(), OCIO::BIT_DEPTH_UINT10); - - const double outScale = OCIO::GetBitDepthMaxValue(OCIO::BIT_DEPTH_UINT10); - const double matScale = OCIO::GetBitDepthMaxValue(OCIO::BIT_DEPTH_UINT12) / outScale; - const OCIO::ArrayDouble & array = matOpData->getArray(); - OCIO_CHECK_EQUAL(array.getLength(), 4u); - OCIO_CHECK_EQUAL(array.getNumColorComponents(), 4u); - OCIO_CHECK_EQUAL(array.getNumValues(), - array.getLength()*array.getLength()); - - const float scalef = (900.f - 20.f) / (3760.f - 256.f); - const float offsetf = 20.f - scalef * 256.f; - const float prec = 10000.f; - const int scale = (int)(prec * scalef); - const int offset = (int)(prec * offsetf); - - OCIO_REQUIRE_EQUAL(array.getValues().size(), array.getNumValues()); - OCIO_CHECK_EQUAL((int)(prec * array.getValues()[0] / matScale), scale); - OCIO_CHECK_EQUAL(array.getValues()[1], 0.); - OCIO_CHECK_EQUAL(array.getValues()[2], 0.); - OCIO_CHECK_EQUAL(array.getValues()[3], 0.); - - OCIO_CHECK_EQUAL(array.getValues()[4], 0.); - OCIO_CHECK_EQUAL((int)(prec * array.getValues()[5] / matScale), scale); - OCIO_CHECK_EQUAL(array.getValues()[6], 0.); - OCIO_CHECK_EQUAL(array.getValues()[7], 0.); - - OCIO_CHECK_EQUAL(array.getValues()[8], 0.); - OCIO_CHECK_EQUAL(array.getValues()[9], 0.); - OCIO_CHECK_EQUAL((int)(prec * array.getValues()[10] / matScale), scale); - OCIO_CHECK_EQUAL(array.getValues()[11], 0.); - - OCIO_CHECK_EQUAL(array.getValues()[12], 0.); - OCIO_CHECK_EQUAL(array.getValues()[13], 0.); - OCIO_CHECK_EQUAL(array.getValues()[14], 0.); - OCIO_CHECK_EQUAL((int)(prec * array.getValues()[15] / matScale), - (int)(prec * 1023. / 4095.)); - - const OCIO::MatrixOpData::Offsets & offsets = matOpData->getOffsets(); - OCIO_CHECK_EQUAL((int)(prec * offsets[0] * outScale), offset); - OCIO_CHECK_EQUAL((int)(prec * offsets[1] * outScale), offset); - OCIO_CHECK_EQUAL((int)(prec * offsets[2] * outScale), offset); - OCIO_CHECK_EQUAL(offsets[3], 0.); - - // A range with Clamp. - rangeOpData = std::dynamic_pointer_cast(opList[4]); - OCIO_REQUIRE_ASSERT(rangeOpData); - OCIO_CHECK_EQUAL(rangeOpData->getFileInputBitDepth(), OCIO::BIT_DEPTH_UINT10); - OCIO_CHECK_EQUAL(rangeOpData->getFileOutputBitDepth(), OCIO::BIT_DEPTH_UINT10); - - // A range without style defaults to clamp. - rangeOpData = std::dynamic_pointer_cast(opList[5]); - OCIO_REQUIRE_ASSERT(rangeOpData); - OCIO_CHECK_EQUAL(rangeOpData->getFileInputBitDepth(), OCIO::BIT_DEPTH_UINT10); - OCIO_CHECK_EQUAL(rangeOpData->getFileOutputBitDepth(), OCIO::BIT_DEPTH_UINT10); + const std::string ctfFile("clf/illegal/cdl_missing_offset.clf"); + OCIO_CHECK_THROW_WHAT(LoadCLFFile(ctfFile), OCIO::Exception, + "Required node 'Offset' is missing"); } -OCIO_ADD_TEST(FileFormatCTF, tabluation_support) -{ - OCIO::LocalCachedFileRcPtr cachedFile; - // This clf file contains tabulations used as delimiters for a - // series of numbers. - const std::string ctfFile("tabulation_support.clf"); - OCIO_CHECK_NO_THROW(cachedFile = LoadCLFFile(ctfFile)); - const OCIO::ConstOpDataVec & opList = cachedFile->m_transform->getOps(); - OCIO_CHECK_EQUAL(cachedFile->m_transform->getID(), "none"); - OCIO_REQUIRE_EQUAL(opList.size(), 1); - - auto pL = std::dynamic_pointer_cast(opList[0]); - OCIO_REQUIRE_ASSERT(pL); - - OCIO_CHECK_EQUAL(pL->getFileOutputBitDepth(), OCIO::BIT_DEPTH_UINT12); - - const OCIO::Array & array = pL->getArray(); - OCIO_CHECK_EQUAL(array.getLength(), 33U); - OCIO_CHECK_EQUAL(array.getNumColorComponents(), 3U); - OCIO_CHECK_EQUAL(array.getNumValues(), 107811U); - OCIO_REQUIRE_EQUAL(array.getValues().size(), 107811U); - - OCIO_CHECK_EQUAL(array.getValues()[0], 0.0f); - OCIO_CHECK_EQUAL(array.getValues()[1], 0.0f); - OCIO_CHECK_EQUAL(array.getValues()[2], 0.0f); - - OCIO_CHECK_EQUAL(array.getValues()[3], 0.0f); - OCIO_CHECK_EQUAL(array.getValues()[4], 0.0f); - OCIO_CHECK_CLOSE(array.getValues()[5] * 4095.0f, 13.0f, 1e-6f); +OCIO_ADD_TEST(FileFormatCTF, cdl_missing_power) +{ + const std::string ctfFile("clf/illegal/cdl_missing_power.clf"); + OCIO_CHECK_THROW_WHAT(LoadCLFFile(ctfFile), OCIO::Exception, + "Required node 'Power' is missing"); +} - OCIO_CHECK_EQUAL(array.getValues()[6] * 4095.0f, 1.0f); - OCIO_CHECK_EQUAL(array.getValues()[7] * 4095.0f, 0.0f); - OCIO_CHECK_EQUAL(array.getValues()[8] * 4095.0f, 44.0f); +OCIO_ADD_TEST(FileFormatCTF, cdl_bad_style) +{ + const std::string ctfFile("clf/illegal/cdl_bad_style.clf"); + OCIO_CHECK_THROW_WHAT(LoadCLFFile(ctfFile), OCIO::Exception, + "Unknown style for CDL"); +} - OCIO_CHECK_EQUAL(array.getValues()[9], 0.0f); - OCIO_CHECK_EQUAL(array.getValues()[10] * 4095.0f, 1.0f); - OCIO_CHECK_EQUAL(array.getValues()[11] * 4095.0f, 94.0f); +OCIO_ADD_TEST(FileFormatCTF, cdl_missing_sop) +{ + OCIO::LocalCachedFileRcPtr cachedFile; + const std::string ctfFile("clf/cdl_missing_sop.clf"); + OCIO_CHECK_NO_THROW(cachedFile = LoadCLFFile(ctfFile)); + OCIO_REQUIRE_ASSERT((bool)cachedFile); - OCIO_CHECK_EQUAL(array.getValues()[3 * 33 + 0] * 4095.0f, 1.0f); - OCIO_CHECK_EQUAL(array.getValues()[3 * 33 + 1] * 4095.0f, 32.0f); - OCIO_CHECK_EQUAL(array.getValues()[3 * 33 + 2], 0.0f); + const OCIO::ConstOpDataVec & opList = cachedFile->m_transform->getOps(); + OCIO_REQUIRE_EQUAL(opList.size(), 1); + auto pCDL = std::dynamic_pointer_cast(opList[0]); + OCIO_REQUIRE_ASSERT(pCDL); - OCIO_CHECK_EQUAL(array.getValues()[3 * 35936 + 0] * 4095.0f, 4095.0f); - OCIO_CHECK_EQUAL(array.getValues()[3 * 35936 + 1] * 4095.0f, 4095.0f); - OCIO_CHECK_EQUAL(array.getValues()[3 * 35936 + 2] * 4095.0f, 4095.0f); + OCIO_CHECK_ASSERT(pCDL->getSlopeParams() + == OCIO::CDLOpData::ChannelParams(1.0)); + OCIO_CHECK_ASSERT(pCDL->getOffsetParams() + == OCIO::CDLOpData::ChannelParams(0.0)); + OCIO_CHECK_ASSERT(pCDL->getPowerParams() + == OCIO::CDLOpData::ChannelParams(1.0)); + OCIO_CHECK_EQUAL(pCDL->getSaturation(), 1.239); } -OCIO_ADD_TEST(FileFormatCTF, matrix_windows_eol) +OCIO_ADD_TEST(FileFormatCTF, cdl_missing_sat) { OCIO::LocalCachedFileRcPtr cachedFile; - // This file uses windows end of line character and does not start - // with the ?xml header. - const std::string ctfFile("matrix_windows.clf"); + const std::string ctfFile("clf/cdl_missing_sat.clf"); OCIO_CHECK_NO_THROW(cachedFile = LoadCLFFile(ctfFile)); + OCIO_REQUIRE_ASSERT((bool)cachedFile); + const OCIO::ConstOpDataVec & opList = cachedFile->m_transform->getOps(); - OCIO_CHECK_EQUAL(cachedFile->m_transform->getID(), "42"); OCIO_REQUIRE_EQUAL(opList.size(), 1); - OCIO_CHECK_EQUAL(opList[0]->getType(), OCIO::OpData::MatrixType); - OCIO_CHECK_EQUAL(opList[0]->getID(), "mat42"); -} + auto pCDL = std::dynamic_pointer_cast(opList[0]); + OCIO_REQUIRE_ASSERT(pCDL); -OCIO_ADD_TEST(FileFormatCTF, lut_3d_file_with_xml_extension) -{ - const std::string ctfFile("not_a_ctf.xml"); - OCIO_CHECK_THROW_WHAT(LoadCLFFile(ctfFile), OCIO::Exception, - "is not a CTF/CLF file."); + OCIO_CHECK_ASSERT(pCDL->getSlopeParams() + == OCIO::CDLOpData::ChannelParams(1.35, 1.1, 0.71)); + OCIO_CHECK_ASSERT(pCDL->getOffsetParams() + == OCIO::CDLOpData::ChannelParams(0.05, -0.23, 0.11)); + OCIO_CHECK_ASSERT(pCDL->getPowerParams() + == OCIO::CDLOpData::ChannelParams(0.93, 0.81, 1.27)); + OCIO_CHECK_EQUAL(pCDL->getSaturation(), 1.0); } - -OCIO_ADD_TEST(FileFormatCTF, info_element_version_test) +OCIO_ADD_TEST(FileFormatCTF, cdl_various_in_ctf) { - // VALID - No Version. - // - { - const std::string ctfFile("info_version_without.ctf"); - OCIO_CHECK_NO_THROW(LoadCLFFile(ctfFile)); - } + // When CDL was added to the CLF spec in v2, the style names were changed. + // Test that both the new and old style names work. + OCIO::LocalCachedFileRcPtr cachedFile; + const std::string ctfFile("cdl_various.ctf"); + OCIO_CHECK_NO_THROW(cachedFile = LoadCLFFile(ctfFile)); + OCIO_REQUIRE_ASSERT((bool)cachedFile); - // VALID - Minor Version. - // - { - const std::string ctfFile("info_version_valid_minor.ctf"); - OCIO_CHECK_NO_THROW(LoadCLFFile(ctfFile)); - } + const OCIO::ConstOpDataVec & opList = cachedFile->m_transform->getOps(); + OCIO_REQUIRE_EQUAL(opList.size(), 8); - // INVALID - Invalid Version. - // - { - const std::string ctfFile("info_version_invalid.ctf"); - OCIO_CHECK_THROW_WHAT( - LoadCLFFile(ctfFile), OCIO::Exception, - "Invalid Info element version attribute"); - } + auto pCDL = std::dynamic_pointer_cast(opList[0]); + OCIO_REQUIRE_ASSERT(pCDL); + OCIO_CHECK_EQUAL(pCDL->getStyle(), OCIO::CDLOpData::CDL_V1_2_FWD); - // INVALID - Unsupported Version. - // - { - const std::string ctfFile("info_version_unsupported.ctf"); - OCIO_CHECK_THROW_WHAT( - LoadCLFFile(ctfFile), OCIO::Exception, - "Unsupported Info element version attribute"); - } + pCDL = std::dynamic_pointer_cast(opList[1]); + OCIO_REQUIRE_ASSERT(pCDL); + OCIO_CHECK_EQUAL(pCDL->getStyle(), OCIO::CDLOpData::CDL_V1_2_FWD); - // INVALID - Empty Version. - // - { - const std::string ctfFile("info_version_empty.ctf"); - OCIO_CHECK_THROW_WHAT( - LoadCLFFile(ctfFile), OCIO::Exception, - "Invalid Info element version attribute"); - } - -} + pCDL = std::dynamic_pointer_cast(opList[2]); + OCIO_REQUIRE_ASSERT(pCDL); + OCIO_CHECK_EQUAL(pCDL->getStyle(), OCIO::CDLOpData::CDL_V1_2_REV); -OCIO_ADD_TEST(Log, load_log10) -{ - OCIO::LocalCachedFileRcPtr cachedFile; - std::string fileName("log_log10.ctf"); - OCIO_CHECK_NO_THROW(cachedFile = LoadCLFFile(fileName)); - const OCIO::ConstOpDataVec & fileOps = cachedFile->m_transform->getOps(); - - OCIO_CHECK_EQUAL(cachedFile->m_transform->getName(), "log example"); - OCIO_CHECK_EQUAL(cachedFile->m_transform->getID(), - "b5cc7aed-d405-4d8b-b64b-382b2341a378"); - OCIO_CHECK_EQUAL(cachedFile->m_transform->getInputDescriptor(), "inputDesc"); - OCIO_CHECK_EQUAL(cachedFile->m_transform->getOutputDescriptor(), "outputDesc"); - OCIO_CHECK_EQUAL(cachedFile->m_transform->getDescriptions().size(), 1); - OCIO_CHECK_EQUAL(cachedFile->m_transform->getDescriptions()[0], - "Example of Log10 logarithm operation."); + pCDL = std::dynamic_pointer_cast(opList[3]); + OCIO_REQUIRE_ASSERT(pCDL); + OCIO_CHECK_EQUAL(pCDL->getStyle(), OCIO::CDLOpData::CDL_V1_2_REV); - OCIO_REQUIRE_EQUAL(fileOps.size(), 1); - OCIO::ConstOpDataRcPtr op = fileOps[0]; - OCIO::ConstLogOpDataRcPtr log = std::dynamic_pointer_cast(op); - OCIO_REQUIRE_ASSERT(log); - StringUtils::StringVec desc; - GetElementsValues(log->getFormatMetadata().getChildrenElements(), - OCIO::TAG_DESCRIPTION, desc); - OCIO_REQUIRE_EQUAL(desc.size(), 1); - OCIO_CHECK_EQUAL(desc[0], "Log10 logarithm operation"); + pCDL = std::dynamic_pointer_cast(opList[4]); + OCIO_REQUIRE_ASSERT(pCDL); + OCIO_CHECK_EQUAL(pCDL->getStyle(), OCIO::CDLOpData::CDL_NO_CLAMP_FWD); - OCIO_CHECK_ASSERT(log->isLog10()); - OCIO_CHECK_EQUAL(log->getDirection(), OCIO::TRANSFORM_DIR_FORWARD); -} + pCDL = std::dynamic_pointer_cast(opList[5]); + OCIO_REQUIRE_ASSERT(pCDL); + OCIO_CHECK_EQUAL(pCDL->getStyle(), OCIO::CDLOpData::CDL_NO_CLAMP_FWD); -OCIO_ADD_TEST(Log, load_log2) -{ - OCIO::LocalCachedFileRcPtr cachedFile; - std::string fileName("log_log2.ctf"); - OCIO_CHECK_NO_THROW(cachedFile = LoadCLFFile(fileName)); - const OCIO::ConstOpDataVec & fileOps = cachedFile->m_transform->getOps(); - OCIO_REQUIRE_EQUAL(fileOps.size(), 1); - auto op = fileOps[0]; - auto log = std::dynamic_pointer_cast(op); - OCIO_REQUIRE_ASSERT(log); + pCDL = std::dynamic_pointer_cast(opList[6]); + OCIO_REQUIRE_ASSERT(pCDL); + OCIO_CHECK_EQUAL(pCDL->getStyle(), OCIO::CDLOpData::CDL_NO_CLAMP_REV); - OCIO_CHECK_ASSERT(log->isLog2()); - OCIO_CHECK_EQUAL(log->getDirection(), OCIO::TRANSFORM_DIR_FORWARD); + pCDL = std::dynamic_pointer_cast(opList[7]); + OCIO_REQUIRE_ASSERT(pCDL); + OCIO_CHECK_EQUAL(pCDL->getStyle(), OCIO::CDLOpData::CDL_NO_CLAMP_REV); } -OCIO_ADD_TEST(Log, load_antilog10) +OCIO_ADD_TEST(FileFormatCTF, log_all_styles) { OCIO::LocalCachedFileRcPtr cachedFile; - std::string fileName("log_antilog10.ctf"); + const std::string fileName("clf/log_all_styles.clf"); OCIO_CHECK_NO_THROW(cachedFile = LoadCLFFile(fileName)); - const OCIO::ConstOpDataVec & fileOps = cachedFile->m_transform->getOps(); - OCIO_REQUIRE_EQUAL(fileOps.size(), 1); - auto op = fileOps[0]; - auto log = std::dynamic_pointer_cast(op); - OCIO_REQUIRE_ASSERT(log); + const OCIO::ConstOpDataVec & opList = cachedFile->m_transform->getOps(); + OCIO_REQUIRE_EQUAL(opList.size(), 10); + double error = 1e-9; - OCIO_CHECK_ASSERT(log->isLog10()); - OCIO_CHECK_EQUAL(log->getDirection(), OCIO::TRANSFORM_DIR_INVERSE); + { // Op 0 == antiLog2. + auto opData = std::dynamic_pointer_cast(opList[0]); + OCIO_REQUIRE_ASSERT(opData); + StringUtils::StringVec desc; + GetElementsValues(opData->getFormatMetadata().getChildrenElements(), + OCIO::TAG_DESCRIPTION, desc); + OCIO_REQUIRE_EQUAL(desc.size(), 1); + OCIO_CHECK_EQUAL(desc[0], "AntiLog2 logarithm operation"); + OCIO_CHECK_EQUAL(opData->getDirection(), OCIO::TRANSFORM_DIR_INVERSE); + OCIO_CHECK_ASSERT(opData->isLog2()); + } + { // Op 1 == log2. + auto opData = std::dynamic_pointer_cast(opList[1]); + OCIO_REQUIRE_ASSERT(opData); + OCIO_CHECK_EQUAL(opData->getID(), "a1"); + OCIO_CHECK_EQUAL(opData->getName(), "logarithm"); + OCIO_CHECK_EQUAL(opData->getDirection(), OCIO::TRANSFORM_DIR_FORWARD); + OCIO_CHECK_ASSERT(opData->isLog2()); + OCIO_CHECK_ASSERT(!opData->isLog10()); + OCIO_CHECK_ASSERT(!opData->isCamera()); + } + { // Op 2 == linToLog. + auto opData = std::dynamic_pointer_cast(opList[2]); + OCIO_REQUIRE_ASSERT(opData); + OCIO_CHECK_EQUAL(opData->getDirection(), OCIO::TRANSFORM_DIR_FORWARD); + OCIO_CHECK_ASSERT(!opData->isLog2()); + OCIO_CHECK_ASSERT(!opData->isLog10()); + OCIO_CHECK_ASSERT(!opData->isCamera()); + OCIO_CHECK_ASSERT(opData->allComponentsEqual()); + auto & param = opData->getRedParams(); + OCIO_REQUIRE_EQUAL(param.size(), 4); + OCIO_CHECK_CLOSE(param[OCIO::LOG_SIDE_SLOPE], 0.29325513196, error); + OCIO_CHECK_CLOSE(param[OCIO::LOG_SIDE_OFFSET], 0.66959921799, error); + OCIO_CHECK_CLOSE(param[OCIO::LIN_SIDE_SLOPE], 0.98920224838, error); + OCIO_CHECK_CLOSE(param[OCIO::LIN_SIDE_OFFSET], 0.01079775162, error); + OCIO_CHECK_EQUAL(opData->getBase(), 10.); + } + { // Op 3 == antiLog10. + auto opData = std::dynamic_pointer_cast(opList[3]); + OCIO_REQUIRE_ASSERT(opData); + OCIO_CHECK_EQUAL(opData->getDirection(), OCIO::TRANSFORM_DIR_INVERSE); + OCIO_CHECK_ASSERT(!opData->isLog2()); + OCIO_CHECK_ASSERT(opData->isLog10()); + } + { // Op 4 == log10. + auto opData = std::dynamic_pointer_cast(opList[4]); + OCIO_REQUIRE_ASSERT(opData); + OCIO_CHECK_EQUAL(opData->getDirection(), OCIO::TRANSFORM_DIR_FORWARD); + OCIO_CHECK_ASSERT(!opData->isLog2()); + OCIO_CHECK_ASSERT(opData->isLog10()); + } + { // Op 5 == logToLin. + auto opData = std::dynamic_pointer_cast(opList[5]); + OCIO_REQUIRE_ASSERT(opData); + OCIO_CHECK_EQUAL(opData->getDirection(), OCIO::TRANSFORM_DIR_INVERSE); + OCIO_CHECK_ASSERT(!opData->isLog2()); + OCIO_CHECK_ASSERT(!opData->isLog10()); + OCIO_CHECK_ASSERT(!opData->isCamera()); + OCIO_CHECK_ASSERT(opData->allComponentsEqual()); + auto & param = opData->getRedParams(); + OCIO_REQUIRE_EQUAL(param.size(), 4); + OCIO_CHECK_CLOSE(param[OCIO::LOG_SIDE_SLOPE], 0.29325513196, error); + OCIO_CHECK_CLOSE(param[OCIO::LOG_SIDE_OFFSET], 0.66959921799, error); + OCIO_CHECK_CLOSE(param[OCIO::LIN_SIDE_SLOPE], 0.98920224838, error); + OCIO_CHECK_CLOSE(param[OCIO::LIN_SIDE_OFFSET], 0.01079775162, error); + OCIO_CHECK_EQUAL(opData->getBase(), 10.); + } + { // Op 6 == cameraLinToLog. + auto opData = std::dynamic_pointer_cast(opList[6]); + OCIO_REQUIRE_ASSERT(opData); + OCIO_CHECK_EQUAL(opData->getDirection(), OCIO::TRANSFORM_DIR_FORWARD); + OCIO_CHECK_ASSERT(!opData->isLog2()); + OCIO_CHECK_ASSERT(!opData->isLog10()); + OCIO_CHECK_ASSERT(opData->isCamera()); + OCIO_CHECK_ASSERT(opData->allComponentsEqual()); + auto & param = opData->getRedParams(); + OCIO_REQUIRE_EQUAL(param.size(), 5); + OCIO_CHECK_CLOSE(param[OCIO::LOG_SIDE_SLOPE], 0.05707762557, error); + OCIO_CHECK_CLOSE(param[OCIO::LOG_SIDE_OFFSET], 0.55479452050, error); + OCIO_CHECK_CLOSE(param[OCIO::LIN_SIDE_SLOPE], 1. , error); + OCIO_CHECK_CLOSE(param[OCIO::LIN_SIDE_OFFSET], 0. , error); + OCIO_CHECK_CLOSE(param[OCIO::LIN_SIDE_BREAK], 0.00781250000, error); + // Default base value is 2. + OCIO_CHECK_EQUAL(opData->getBase(), 2.); + } + { // Op 7 == cameraLogToLin. + auto opData = std::dynamic_pointer_cast(opList[7]); + OCIO_REQUIRE_ASSERT(opData); + OCIO_CHECK_EQUAL(opData->getDirection(), OCIO::TRANSFORM_DIR_INVERSE); + OCIO_CHECK_ASSERT(!opData->isLog2()); + OCIO_CHECK_ASSERT(!opData->isLog10()); + OCIO_CHECK_ASSERT(opData->isCamera()); + OCIO_CHECK_ASSERT(opData->allComponentsEqual()); + auto & param = opData->getRedParams(); + OCIO_REQUIRE_EQUAL(param.size(), 5); + OCIO_CHECK_CLOSE(param[OCIO::LOG_SIDE_SLOPE], 0.05707762557, error); + OCIO_CHECK_CLOSE(param[OCIO::LOG_SIDE_OFFSET], 0.55479452050, error); + OCIO_CHECK_CLOSE(param[OCIO::LIN_SIDE_SLOPE], 1. , error); + OCIO_CHECK_CLOSE(param[OCIO::LIN_SIDE_OFFSET], 0. , error); + OCIO_CHECK_CLOSE(param[OCIO::LIN_SIDE_BREAK], 0.00781250000, error); + OCIO_CHECK_EQUAL(opData->getBase(), 2.); + } + { // Op 8 == cameraLogToLin. + auto opData = std::dynamic_pointer_cast(opList[8]); + OCIO_REQUIRE_ASSERT(opData); + OCIO_CHECK_EQUAL(opData->getDirection(), OCIO::TRANSFORM_DIR_INVERSE); + OCIO_CHECK_ASSERT(!opData->isLog2()); + OCIO_CHECK_ASSERT(!opData->isLog10()); + OCIO_CHECK_ASSERT(opData->isCamera()); + OCIO_CHECK_ASSERT(opData->allComponentsEqual()); + auto & param = opData->getRedParams(); + OCIO_REQUIRE_EQUAL(param.size(), 6); + OCIO_CHECK_CLOSE(param[OCIO::LOG_SIDE_SLOPE], 0.25562072336, error); + OCIO_CHECK_CLOSE(param[OCIO::LOG_SIDE_OFFSET], 0.41055718475, error); + OCIO_CHECK_CLOSE(param[OCIO::LIN_SIDE_SLOPE], 5.26315789474, error); + OCIO_CHECK_CLOSE(param[OCIO::LIN_SIDE_OFFSET], 0.05263157895, error); + OCIO_CHECK_CLOSE(param[OCIO::LIN_SIDE_BREAK], 0.01125000000, error); + OCIO_CHECK_CLOSE(param[OCIO::LINEAR_SLOPE], 6.62194371178, error); + OCIO_CHECK_EQUAL(opData->getBase(), 10.); + } + { // Op 9 == linToLog. + auto opData = std::dynamic_pointer_cast(opList[9]); + OCIO_REQUIRE_ASSERT(opData); + OCIO_CHECK_EQUAL(opData->getDirection(), OCIO::TRANSFORM_DIR_FORWARD); + OCIO_CHECK_ASSERT(!opData->isLog2()); + OCIO_CHECK_ASSERT(!opData->isLog10()); + OCIO_CHECK_ASSERT(!opData->isCamera()); + OCIO_CHECK_ASSERT(!opData->allComponentsEqual()); + { + auto & param = opData->getRedParams(); + OCIO_REQUIRE_EQUAL(param.size(), 4); + OCIO_CHECK_EQUAL(param[OCIO::LOG_SIDE_SLOPE], 0.9); + OCIO_CHECK_EQUAL(param[OCIO::LOG_SIDE_OFFSET], 0.2); + OCIO_CHECK_EQUAL(param[OCIO::LIN_SIDE_SLOPE], 1.1); + OCIO_CHECK_EQUAL(param[OCIO::LIN_SIDE_OFFSET], 0.1); + OCIO_CHECK_EQUAL(opData->getBase(), 4.); + } + { + auto & param = opData->getGreenParams(); + OCIO_REQUIRE_EQUAL(param.size(), 4); + OCIO_CHECK_EQUAL(param[OCIO::LOG_SIDE_SLOPE], 1.1); + OCIO_CHECK_EQUAL(param[OCIO::LOG_SIDE_OFFSET], 0.1); + OCIO_CHECK_EQUAL(param[OCIO::LIN_SIDE_SLOPE], 1.0); + OCIO_CHECK_EQUAL(param[OCIO::LIN_SIDE_OFFSET],-0.1); + OCIO_CHECK_EQUAL(opData->getBase(), 4.); + } + { + auto & param = opData->getBlueParams(); + OCIO_REQUIRE_EQUAL(param.size(), 4); + OCIO_CHECK_EQUAL(param[OCIO::LOG_SIDE_SLOPE], 0.95); + OCIO_CHECK_EQUAL(param[OCIO::LOG_SIDE_OFFSET],-0.2); + OCIO_CHECK_EQUAL(param[OCIO::LIN_SIDE_SLOPE], 1.2); + OCIO_CHECK_EQUAL(param[OCIO::LIN_SIDE_OFFSET], 0.2); + OCIO_CHECK_EQUAL(opData->getBase(), 4.); + } + } } -OCIO_ADD_TEST(Log, load_antilog2) +OCIO_ADD_TEST(FileFormatCTF, log_logtolin) { OCIO::LocalCachedFileRcPtr cachedFile; - std::string fileName("log_antilog2.ctf"); + std::string fileName("log_logtolin.ctf"); OCIO_CHECK_NO_THROW(cachedFile = LoadCLFFile(fileName)); const OCIO::ConstOpDataVec & fileOps = cachedFile->m_transform->getOps(); OCIO_REQUIRE_EQUAL(fileOps.size(), 1); @@ -2536,14 +2987,26 @@ OCIO_ADD_TEST(Log, load_antilog2) auto log = std::dynamic_pointer_cast(op); OCIO_REQUIRE_ASSERT(log); - OCIO_CHECK_ASSERT(log->isLog2()); OCIO_CHECK_EQUAL(log->getDirection(), OCIO::TRANSFORM_DIR_INVERSE); + OCIO_CHECK_ASSERT(!log->isLog2()); + OCIO_CHECK_ASSERT(!log->isLog10()); + OCIO_CHECK_ASSERT(log->allComponentsEqual()); + auto & param = log->getRedParams(); + OCIO_REQUIRE_EQUAL(param.size(), 4); + double error = 1e-9; + // This file uses the original CTF/Cineon style params, verify they are converted properly + // to the new OCIO style params. + OCIO_CHECK_CLOSE(param[OCIO::LOG_SIDE_SLOPE], 0.29325513196, error); + OCIO_CHECK_CLOSE(param[OCIO::LOG_SIDE_OFFSET], 0.66959921799, error); + OCIO_CHECK_CLOSE(param[OCIO::LIN_SIDE_SLOPE], 0.98969709693, error); + OCIO_CHECK_CLOSE(param[OCIO::LIN_SIDE_OFFSET], 0.01030290307, error); } -OCIO_ADD_TEST(Log, load_log_to_lin) +OCIO_ADD_TEST(FileFormatCTF, log_logtolinv2) { + // Same as previous test, but CTF version set to 2. OCIO::LocalCachedFileRcPtr cachedFile; - std::string fileName("log_logtolin.ctf"); + std::string fileName("log_logtolinv2.ctf"); OCIO_CHECK_NO_THROW(cachedFile = LoadCLFFile(fileName)); const OCIO::ConstOpDataVec & fileOps = cachedFile->m_transform->getOps(); OCIO_REQUIRE_EQUAL(fileOps.size(), 1); @@ -2558,13 +3021,15 @@ OCIO_ADD_TEST(Log, load_log_to_lin) auto & param = log->getRedParams(); OCIO_REQUIRE_EQUAL(param.size(), 4); double error = 1e-9; + // This file uses the original CTF/Cineon style params, verify they are converted properly + // to the new OCIO style params. OCIO_CHECK_CLOSE(param[OCIO::LOG_SIDE_SLOPE], 0.29325513196, error); OCIO_CHECK_CLOSE(param[OCIO::LOG_SIDE_OFFSET], 0.66959921799, error); OCIO_CHECK_CLOSE(param[OCIO::LIN_SIDE_SLOPE], 0.98969709693, error); OCIO_CHECK_CLOSE(param[OCIO::LIN_SIDE_OFFSET], 0.01030290307, error); } -OCIO_ADD_TEST(Log, load_lin_to_log) +OCIO_ADD_TEST(FileFormatCTF, log_lintolog_3chan) { OCIO::LocalCachedFileRcPtr cachedFile; std::string fileName("log_lintolog_3chan.ctf"); @@ -2581,6 +3046,8 @@ OCIO_ADD_TEST(Log, load_lin_to_log) auto & rParam = log->getRedParams(); OCIO_REQUIRE_EQUAL(rParam.size(), 4); double error = 1e-9; + // This file uses the original CTF/Cineon style params, verify they are converted properly + // to the new OCIO style params. OCIO_CHECK_CLOSE(rParam[OCIO::LOG_SIDE_SLOPE], 0.244379276637, error); OCIO_CHECK_CLOSE(rParam[OCIO::LOG_SIDE_OFFSET], 0.665689149560, error); OCIO_CHECK_CLOSE(rParam[OCIO::LIN_SIDE_SLOPE], 1.111637101285, error); @@ -2601,47 +3068,35 @@ OCIO_ADD_TEST(Log, load_lin_to_log) OCIO_CHECK_CLOSE(bParam[OCIO::LIN_SIDE_OFFSET], 0.010970316295, error); } -OCIO_ADD_TEST(Log, load_invalid_style) +OCIO_ADD_TEST(FileFormatCTF, log_bad_style) { - std::string fileName("log_invalidstyle.ctf"); + std::string fileName("clf/illegal/log_bad_style.clf"); OCIO_CHECK_THROW_WHAT(LoadCLFFile(fileName), OCIO::Exception, "is invalid"); } -OCIO_ADD_TEST(Log, load_faulty_version) +OCIO_ADD_TEST(FileFormatCTF, log_bad_version) { - std::string fileName("log_log10_faulty_version.ctf"); + std::string fileName("clf/illegal/log_bad_version.clf"); OCIO_CHECK_THROW_WHAT(LoadCLFFile(fileName), OCIO::Exception, - "CTF file version '1.2' does not support operator 'Log'"); + "CLF file version '2' does not support operator 'Log'"); } -OCIO_ADD_TEST(Log, load_ocio_params_equals) +OCIO_ADD_TEST(FileFormatCTF, log_bad_param) { - std::ostringstream strebuf; - strebuf << "\n"; - strebuf << "\n"; - strebuf << "\n"; - strebuf << "\n"; - strebuf << "\n"; - strebuf << "\n"; - - OCIO::LocalCachedFileRcPtr cachedFile = ParseString(strebuf.str()); - OCIO::ConstOpDataVec & fileOps = cachedFile->m_transform->getOps(); + std::string fileName("clf/illegal/log_bad_param.clf"); + OCIO_CHECK_THROW_WHAT(LoadCLFFile(fileName), OCIO::Exception, + "Parameter 'linSideBreak' is only allowed for style"); +} - OCIO_REQUIRE_EQUAL(fileOps.size(), 1); - auto op = fileOps[0]; - auto log = std::dynamic_pointer_cast(op); - OCIO_REQUIRE_ASSERT(log); - OCIO_CHECK_EQUAL(log->getBase(), 9.0); - OCIO_CHECK_ASSERT(log->allComponentsEqual()); - const auto & redParams = log->getRedParams(); - OCIO_CHECK_EQUAL(redParams[OCIO::LIN_SIDE_SLOPE], 1.1); - OCIO_CHECK_EQUAL(redParams[OCIO::LIN_SIDE_OFFSET], 0.1); - OCIO_CHECK_EQUAL(redParams[OCIO::LOG_SIDE_SLOPE], 0.9); - OCIO_CHECK_EQUAL(redParams[OCIO::LOG_SIDE_OFFSET], 0.2); +OCIO_ADD_TEST(FileFormatCTF, log_missing_breakpnt) +{ + std::string fileName("clf/illegal/log_missing_breakpnt.clf"); + OCIO_CHECK_THROW_WHAT(LoadCLFFile(fileName), OCIO::Exception, + "Parameter 'linSideBreak' should be defined for style"); } -OCIO_ADD_TEST(Log, load_ocio_params_channels) +OCIO_ADD_TEST(FileFormatCTF, log_ocio_params_channels) { // NB: The blue channel is missing and will use default values. // Base can be specified in any channel but has to be specified. @@ -2680,29 +3135,7 @@ OCIO_ADD_TEST(Log, load_ocio_params_channels) OCIO_CHECK_EQUAL(bParams[OCIO::LOG_SIDE_OFFSET], 0.0); } -OCIO_ADD_TEST(Log, load_ocio_params_base_missing_2) -{ - std::ostringstream strebuf; - strebuf << "\n"; - strebuf << "\n"; - strebuf << "\n"; - strebuf << "\n"; - strebuf << "\n"; - strebuf << "\n"; - - OCIO::LocalCachedFileRcPtr cachedFile; - OCIO_CHECK_NO_THROW(cachedFile = ParseString(strebuf.str())); - OCIO::ConstOpDataVec & fileOps = cachedFile->m_transform->getOps(); - - OCIO_REQUIRE_EQUAL(fileOps.size(), 1); - auto op = fileOps[0]; - auto log = std::dynamic_pointer_cast(op); - OCIO_REQUIRE_ASSERT(log); - // Default value is 2. - OCIO_CHECK_EQUAL(log->getBase(), 2.0); -} - -OCIO_ADD_TEST(Log, load_ocio_params_base_missmatch) +OCIO_ADD_TEST(FileFormatCTF, log_ocio_params_base_missmatch) { std::ostringstream strebuf; strebuf << "\n"; @@ -2717,42 +3150,7 @@ OCIO_ADD_TEST(Log, load_ocio_params_base_missmatch) "base has to be the same"); } -OCIO_ADD_TEST(Log, load_lin_side_break) -{ - std::ostringstream strebuf; - strebuf << "\n"; - strebuf << "\n"; - strebuf << "\n"; - strebuf << "\n"; - strebuf << "\n"; - strebuf << "\n"; - - OCIO::LocalCachedFileRcPtr cachedFile = ParseString(strebuf.str()); - OCIO::ConstOpDataVec & fileOps = cachedFile->m_transform->getOps(); - - OCIO_REQUIRE_EQUAL(fileOps.size(), 1); - auto op = fileOps[0]; - auto log = std::dynamic_pointer_cast(op); - OCIO_REQUIRE_ASSERT(log); - OCIO_CHECK_EQUAL(log->getBase(), 9.0); - OCIO_CHECK_ASSERT(log->allComponentsEqual()); - const auto & redParams = log->getRedParams(); - OCIO_CHECK_EQUAL(redParams[OCIO::LIN_SIDE_SLOPE], 1.1); - OCIO_CHECK_EQUAL(redParams[OCIO::LIN_SIDE_OFFSET], 0.1); - OCIO_CHECK_EQUAL(redParams[OCIO::LOG_SIDE_SLOPE], 0.9); - OCIO_CHECK_EQUAL(redParams[OCIO::LOG_SIDE_OFFSET], 0.2); - OCIO_REQUIRE_EQUAL(redParams.size(), 5); - OCIO_CHECK_EQUAL(redParams[OCIO::LIN_SIDE_BREAK], 0.3); - - // Change version to clf 2. - auto strFail = strebuf.str(); - auto v = strFail.find_first_of('3'); - strFail[v] = '2'; - OCIO_CHECK_THROW_WHAT(ParseString(strFail), OCIO::Exception, - "CLF file version '2' does not support operator 'Log'"); -} - -OCIO_ADD_TEST(Log, load_default_params) +OCIO_ADD_TEST(FileFormatCTF, log_default_params) { std::ostringstream strebuf; strebuf << "\n"; @@ -2794,12 +3192,120 @@ OCIO_ADD_TEST(Log, load_default_params) OCIO_CHECK_EQUAL(greenParams[OCIO::LIN_SIDE_BREAK], 0.1); } +OCIO_ADD_TEST(FileFormatCTF, multiple_ops) +{ + OCIO::LocalCachedFileRcPtr cachedFile; + const std::string ctfFile("clf/multiple_ops.clf"); + OCIO_CHECK_NO_THROW(cachedFile = LoadCLFFile(ctfFile)); + const OCIO::ConstOpDataVec & opList = cachedFile->m_transform->getOps(); + OCIO_REQUIRE_EQUAL(opList.size(), 9); + + { // Op 0 == CDL. + auto cdlOpData = std::dynamic_pointer_cast(opList[0]); + OCIO_REQUIRE_ASSERT(cdlOpData); + StringUtils::StringVec desc; + GetElementsValues(cdlOpData->getFormatMetadata().getChildrenElements(), + OCIO::TAG_DESCRIPTION, desc); + OCIO_REQUIRE_EQUAL(desc.size(), 1); + OCIO_CHECK_EQUAL(desc[0], "scene 1 exterior look"); + OCIO_CHECK_EQUAL(cdlOpData->getStyle(), OCIO::CDLOpData::CDL_V1_2_REV); + OCIO_CHECK_ASSERT(cdlOpData->getSlopeParams() + == OCIO::CDLOpData::ChannelParams(1., 1., 0.8)); + OCIO_CHECK_ASSERT(cdlOpData->getOffsetParams() + == OCIO::CDLOpData::ChannelParams(-0.02, 0., 0.15)); + OCIO_CHECK_ASSERT(cdlOpData->getPowerParams() + == OCIO::CDLOpData::ChannelParams(1.05, 1.15, 1.4)); + OCIO_CHECK_EQUAL(cdlOpData->getSaturation(), 0.75); + } + { // Op 1 == Lut1D. + auto l1OpData = std::dynamic_pointer_cast(opList[1]); + OCIO_REQUIRE_ASSERT(l1OpData); + OCIO_CHECK_EQUAL(l1OpData->getFileOutputBitDepth(), OCIO::BIT_DEPTH_UINT12); + StringUtils::StringVec desc; + GetElementsValues(l1OpData->getFormatMetadata().getChildrenElements(), + OCIO::TAG_DESCRIPTION, desc); + OCIO_CHECK_EQUAL(desc.size(), 0); + OCIO_CHECK_EQUAL(l1OpData->getArray().getLength(), 32u); + } + { // Op 2 == Range. + // Check that the noClamp style Range became a Matrix. + auto matOpData = std::dynamic_pointer_cast(opList[2]); + OCIO_REQUIRE_ASSERT(matOpData); + OCIO_CHECK_EQUAL(matOpData->getFileInputBitDepth(), OCIO::BIT_DEPTH_UINT12); + OCIO_CHECK_EQUAL(matOpData->getFileOutputBitDepth(), OCIO::BIT_DEPTH_UINT10); + + const double outScale = OCIO::GetBitDepthMaxValue(OCIO::BIT_DEPTH_UINT10); + const double matScale = outScale / OCIO::GetBitDepthMaxValue(OCIO::BIT_DEPTH_UINT12); + const OCIO::ArrayDouble & array = matOpData->getArray(); + OCIO_CHECK_EQUAL(array.getLength(), 4u); + OCIO_CHECK_EQUAL(array.getNumColorComponents(), 4u); + OCIO_CHECK_EQUAL(array.getNumValues(), + array.getLength()*array.getLength()); + + const float scalef = (900.f - 20.f) / (3760.f - 256.f); + const float offsetf = 20.f - scalef * 256.f; + const float prec = 10000.f; + const int scale = (int)(prec * scalef); + const int offset = (int)(prec * offsetf); + + OCIO_CHECK_ASSERT(matOpData->isDiagonal()); + + // Check values on the diagonal. + OCIO_REQUIRE_EQUAL(array.getValues().size(), array.getNumValues()); + OCIO_CHECK_EQUAL((int)(prec * array.getValues()[0] * matScale), scale); + OCIO_CHECK_EQUAL((int)(prec * array.getValues()[5] * matScale), scale); + OCIO_CHECK_EQUAL((int)(prec * array.getValues()[10] * matScale), scale); + OCIO_CHECK_EQUAL(array.getValues()[15], 1.0); + + // Check the offsets. + const OCIO::MatrixOpData::Offsets & offsets = matOpData->getOffsets(); + OCIO_CHECK_EQUAL((int)(prec * offsets[0] * outScale), offset); + OCIO_CHECK_EQUAL((int)(prec * offsets[1] * outScale), offset); + OCIO_CHECK_EQUAL((int)(prec * offsets[2] * outScale), offset); + OCIO_CHECK_EQUAL(offsets[3], 0.f); + } + { // Op 3 == Range with Clamp. + auto rangeOpData = std::dynamic_pointer_cast(opList[3]); + OCIO_REQUIRE_ASSERT(rangeOpData); + OCIO_CHECK_EQUAL(rangeOpData->getFileInputBitDepth(), OCIO::BIT_DEPTH_UINT10); + OCIO_CHECK_EQUAL(rangeOpData->getFileOutputBitDepth(), OCIO::BIT_DEPTH_UINT10); + } + { // Op 4 == Range with Clamp. + // A range without style defaults to clamp. + auto rangeOpData = std::dynamic_pointer_cast(opList[4]); + OCIO_REQUIRE_ASSERT(rangeOpData); + OCIO_CHECK_EQUAL(rangeOpData->getFileInputBitDepth(), OCIO::BIT_DEPTH_UINT10); + OCIO_CHECK_EQUAL(rangeOpData->getFileOutputBitDepth(), OCIO::BIT_DEPTH_UINT10); + } + { // Op 5 == Log. + auto logOpData = std::dynamic_pointer_cast(opList[5]); + OCIO_REQUIRE_ASSERT(logOpData); + } + { // Op 6 == Matrix with offset. + auto matOpData2 = std::dynamic_pointer_cast(opList[6]); + OCIO_REQUIRE_ASSERT(matOpData2); + const OCIO::ArrayDouble & array2 = matOpData2->getArray(); + OCIO_CHECK_EQUAL(array2.getLength(), 4u); + OCIO_CHECK_EQUAL(array2.getValues()[2], 0.2); + const OCIO::MatrixOpData::Offsets & offsets2 = matOpData2->getOffsets(); + OCIO_CHECK_EQUAL(offsets2[1], -0.005); + } + { // Op 7 == Exponent. + auto expOpData = std::dynamic_pointer_cast(opList[7]); + OCIO_REQUIRE_ASSERT(expOpData); + } + { // Op 8 == Lut3D. + auto lut3OpData = std::dynamic_pointer_cast(opList[8]); + OCIO_REQUIRE_ASSERT(lut3OpData); + } +} + // // NOTE: These tests are on the ReferenceOpData itself, before it gets replaced // with the ops from the file it is referencing. Please see RefereceOpData.cpp // for tests involving the resolved ops. // -OCIO_ADD_TEST(Reference, load_alias) +OCIO_ADD_TEST(FileFormatCTF, reference_load_alias) { OCIO::LocalCachedFileRcPtr cachedFile; std::string fileName("reference_alias.ctf"); @@ -2818,7 +3324,7 @@ OCIO_ADD_TEST(Reference, load_alias) OCIO_CHECK_EQUAL(ref->getDirection(), OCIO::TRANSFORM_DIR_FORWARD); } -OCIO_ADD_TEST(Reference, load_path) +OCIO_ADD_TEST(FileFormatCTF, reference_load_path) { OCIO::LocalCachedFileRcPtr cachedFile; std::string fileName("reference_path_missing_file.ctf"); @@ -2835,7 +3341,7 @@ OCIO_ADD_TEST(Reference, load_path) OCIO_CHECK_EQUAL(ref->getDirection(), OCIO::TRANSFORM_DIR_INVERSE); } -OCIO_ADD_TEST(Reference, load_multiple) +OCIO_ADD_TEST(FileFormatCTF, reference_load_multiple) { OCIO::LocalCachedFileRcPtr cachedFile; // File contains 2 references, 1 range and 1 reference. @@ -2848,14 +3354,14 @@ OCIO_ADD_TEST(Reference, load_multiple) OCIO::ConstReferenceOpDataRcPtr ref0 = std::dynamic_pointer_cast(op0); OCIO_REQUIRE_ASSERT(ref0); OCIO_CHECK_EQUAL(ref0->getReferenceStyle(), OCIO::REF_PATH); - OCIO_CHECK_EQUAL(ref0->getPath(), "matrix_example.clf"); + OCIO_CHECK_EQUAL(ref0->getPath(), "matrix_example_1_3_offsets.ctf"); OCIO_CHECK_EQUAL(ref0->getDirection(), OCIO::TRANSFORM_DIR_FORWARD); OCIO::ConstOpDataRcPtr op1 = fileOps[1]; OCIO::ConstReferenceOpDataRcPtr ref1 = std::dynamic_pointer_cast(op1); OCIO_REQUIRE_ASSERT(ref1); OCIO_CHECK_EQUAL(ref1->getReferenceStyle(), OCIO::REF_PATH); - OCIO_CHECK_EQUAL(ref1->getPath(), "xyz_to_rgb.clf"); + OCIO_CHECK_EQUAL(ref1->getPath(), "clf/xyz_to_rgb.clf"); OCIO_CHECK_EQUAL(ref1->getDirection(), OCIO::TRANSFORM_DIR_INVERSE); OCIO::ConstOpDataRcPtr op2 = fileOps[2]; @@ -2866,13 +3372,13 @@ OCIO_ADD_TEST(Reference, load_multiple) OCIO::ConstReferenceOpDataRcPtr ref3 = std::dynamic_pointer_cast(op3); OCIO_REQUIRE_ASSERT(ref3); OCIO_CHECK_EQUAL(ref3->getReferenceStyle(), OCIO::REF_PATH); - OCIO_CHECK_EQUAL(ref3->getPath(), "cdl_clamp_fwd.clf"); + OCIO_CHECK_EQUAL(ref3->getPath(), "clf/cdl_clamp_fwd.clf"); // Note: This tests that the "inverted" attribute set to anything other than // true does not result in an inverted transform. OCIO_CHECK_EQUAL(ref3->getDirection(), OCIO::TRANSFORM_DIR_FORWARD); } -OCIO_ADD_TEST(Reference, load_path_utf8) +OCIO_ADD_TEST(FileFormatCTF, reference_load_path_utf8) { OCIO::LocalCachedFileRcPtr cachedFile; std::string fileName("reference_utf8.ctf"); @@ -2887,7 +3393,7 @@ OCIO_ADD_TEST(Reference, load_path_utf8) OCIO_CHECK_EQUAL(ref->getAlias(), ""); } -OCIO_ADD_TEST(Reference, load_alias_path) +OCIO_ADD_TEST(FileFormatCTF, reference_load_alias_path) { std::string fileName("reference_alias_path.ctf"); // Can't have alias and path at the same time. @@ -3133,7 +3639,7 @@ OCIO_ADD_TEST(FileFormatCTF, load_deprecated_ops_file) } } -OCIO_ADD_TEST(FixedFunction, load_fixed_function_file) +OCIO_ADD_TEST(FileFormatCTF, load_fixed_function_file) { OCIO::LocalCachedFileRcPtr cachedFile; std::string fileName("fixed_function.ctf"); @@ -3224,7 +3730,7 @@ void ValidateFixedFunctionStyleNoParam(OCIO::FixedFunctionOpData::Style style, i } } -OCIO_ADD_TEST(FixedFunction, load_save_ctf) +OCIO_ADD_TEST(FileFormatCTF, ff_load_save_ctf) { ValidateFixedFunctionStyleNoParam(OCIO::FixedFunctionOpData::ACES_RED_MOD_03_FWD, __LINE__); ValidateFixedFunctionStyleNoParam(OCIO::FixedFunctionOpData::ACES_RED_MOD_03_INV, __LINE__); @@ -3246,7 +3752,7 @@ OCIO_ADD_TEST(FixedFunction, load_save_ctf) ValidateFixedFunctionStyleNoParam(OCIO::FixedFunctionOpData::LUV_TO_XYZ , __LINE__); } -OCIO_ADD_TEST(FixedFunction, load_ff_fail_version) +OCIO_ADD_TEST(FileFormatCTF, load_ff_fail_version) { std::ostringstream strebuf; strebuf << "\n"; @@ -3260,7 +3766,7 @@ OCIO_ADD_TEST(FixedFunction, load_ff_fail_version) "CTF file version '1.5' does not support operator 'FixedFunction'"); } -OCIO_ADD_TEST(FixedFunction, load_ff_fail_params) +OCIO_ADD_TEST(FileFormatCTF, load_ff_fail_params) { std::ostringstream strebuf; strebuf << "\n"; @@ -3274,7 +3780,7 @@ OCIO_ADD_TEST(FixedFunction, load_ff_fail_params) "must have one parameter but 2 found"); } -OCIO_ADD_TEST(FixedFunction, load_ff_fail_style) +OCIO_ADD_TEST(FileFormatCTF, load_ff_fail_style) { std::ostringstream strebuf; strebuf << "\n"; @@ -3286,7 +3792,7 @@ OCIO_ADD_TEST(FixedFunction, load_ff_fail_style) "Unknown FixedFunction style"); } -OCIO_ADD_TEST(FixedFunction, load_ff_aces_fail_gamma_param) +OCIO_ADD_TEST(FileFormatCTF, load_ff_aces_fail_gamma_param) { std::ostringstream strebuf; strebuf << "\n"; @@ -3301,7 +3807,7 @@ OCIO_ADD_TEST(FixedFunction, load_ff_aces_fail_gamma_param) "Missing required parameter"); } -OCIO_ADD_TEST(FixedFunction, load_ff_aces_fail_gamma_twice) +OCIO_ADD_TEST(FileFormatCTF, load_ff_aces_fail_gamma_twice) { std::ostringstream strebuf; strebuf << "\n"; @@ -3316,7 +3822,7 @@ OCIO_ADD_TEST(FixedFunction, load_ff_aces_fail_gamma_twice) "only 1 gamma parameter"); } -OCIO_ADD_TEST(FixedFunction, load_ff_aces_fail_missing_param) +OCIO_ADD_TEST(FileFormatCTF, load_ff_aces_fail_missing_param) { std::ostringstream strebuf; strebuf << "\n"; @@ -3337,7 +3843,7 @@ OCIO_ADD_TEST(FixedFunction, load_ff_aces_fail_missing_param) OCIO_ADD_TEST(CTFTransform, load_edit_save_matrix) { - const std::string ctfFile("matrix_example.clf"); + const std::string ctfFile("clf/matrix_example.clf"); OCIO::ConstProcessorRcPtr processor; OCIO_CHECK_NO_THROW(processor = OCIO::GetFileTransformProcessor(ctfFile)); OCIO_REQUIRE_ASSERT(processor); @@ -3383,7 +3889,7 @@ OCIO_ADD_TEST(CTFTransform, load_edit_save_matrix) // Output matrix array as '3 4 3'. const std::string expectedCTF{ R"( - Convert output-referred XYZ values to linear RGB. + Basic matrix example using CLF v2 dim syntax XYZ RGB @@ -3391,7 +3897,8 @@ OCIO_ADD_TEST(CTFTransform, load_edit_save_matrix) Preserved - XYZ to sRGB matrix + Legacy matrix + Note that dim="3 3 3" should be supported for CLF v2 compatibility A " short " description with a ' inside <test"'&> @@ -3425,14 +3932,14 @@ OCIO_ADD_TEST(CTFTransform, load_edit_save_matrix) OCIO_CHECK_EQUAL(std::string(OCIO::METADATA_ID), md.getAttributeName(0)); OCIO_CHECK_EQUAL(std::string(OCIO::METADATA_NAME), md.getAttributeName(1)); OCIO_CHECK_EQUAL(shortName, md.getAttributeValue(1)); - OCIO_REQUIRE_EQUAL(md.getNumChildrenElements(), 3); + OCIO_REQUIRE_EQUAL(md.getNumChildrenElements(), 4); const auto & desc0 = md.getChildElement(0); OCIO_CHECK_EQUAL(std::string(OCIO::METADATA_DESCRIPTION), desc0.getName()); - OCIO_CHECK_EQUAL(std::string(R"(XYZ to sRGB matrix)"), desc0.getValue()); - const auto & desc1 = md.getChildElement(1); + OCIO_CHECK_EQUAL(std::string(R"(Legacy matrix)"), desc0.getValue()); + const auto & desc1 = md.getChildElement(2); OCIO_CHECK_EQUAL(std::string(OCIO::METADATA_DESCRIPTION), desc1.getName()); OCIO_CHECK_EQUAL(description1, desc1.getValue()); - const auto & desc2 = md.getChildElement(2); + const auto & desc2 = md.getChildElement(3); OCIO_CHECK_EQUAL(std::string(OCIO::METADATA_DESCRIPTION), desc2.getName()); OCIO_CHECK_EQUAL(description2, desc2.getValue()); } @@ -3611,7 +4118,7 @@ OCIO_ADD_TEST(CTFTransform, save_log_camera) OCIO_ADD_TEST(CTFTransform, save_lut_1d_1component) { - const std::string ctfFile("lut1d_32f_example.clf"); + const std::string ctfFile("clf/lut1d_32f_example.clf"); OCIO::ConstProcessorRcPtr proc = OCIO::GetFileTransformProcessor(ctfFile); std::ostringstream outputTransform; @@ -3793,7 +4300,7 @@ OCIO_ADD_TEST(CTFTransform, save_invalid_lut_1d) OCIO_ADD_TEST(CTFTransform, save_lut_3d) { - const std::string ctfFile("lut3d_2x2x2_32f_32f.clf"); + const std::string ctfFile("clf/lut3d_identity_12i_16f.clf"); OCIO::ConstProcessorRcPtr proc = OCIO::GetFileTransformProcessor(ctfFile); std::ostringstream outputTransform; @@ -3857,7 +4364,7 @@ OCIO_ADD_TEST(CTFTransform, save_group) OCIO_ADD_TEST(CTFTransform, load_save_matrix) { - const std::string ctfFile("matrix_example.clf"); + const std::string ctfFile("clf/matrix_example.clf"); OCIO::ConstProcessorRcPtr processor; OCIO_CHECK_NO_THROW(processor = OCIO::GetFileTransformProcessor(ctfFile)); OCIO_REQUIRE_ASSERT(processor); @@ -3871,11 +4378,12 @@ OCIO_ADD_TEST(CTFTransform, load_save_matrix) // Output matrix array as '3 3 3'. const std::string expected{ R"( - Convert output-referred XYZ values to linear RGB. + Basic matrix example using CLF v2 dim syntax XYZ RGB - XYZ to sRGB matrix + Legacy matrix + Note that dim="3 3 3" should be supported for CLF v2 compatibility 3.24 -1.537 -0.4985 -0.9693 1.876 0.04156 @@ -3917,7 +4425,7 @@ OCIO_ADD_TEST(CTFTransform, save_matrix_444) OCIO_ADD_TEST(CTFTransform, load_edit_save_matrix_clf) { - const std::string ctfFile("matrix_example.clf"); + const std::string ctfFile("clf/matrix_example.clf"); OCIO::ConstProcessorRcPtr processor; OCIO_CHECK_NO_THROW(processor = OCIO::GetFileTransformProcessor(ctfFile)); OCIO_REQUIRE_ASSERT(processor); @@ -3945,11 +4453,12 @@ OCIO_ADD_TEST(CTFTransform, load_edit_save_matrix_clf) const std::string expectedCLF{ R"( - Convert output-referred XYZ values to linear RGB. + Basic matrix example using CLF v2 dim syntax XYZ RGB - XYZ to sRGB matrix + Legacy matrix + Note that dim="3 3 3" should be supported for CLF v2 compatibility Added description 3.24 -1.537 -0.4985 0.1 @@ -3974,11 +4483,12 @@ R"( const std::string expectedCTF{ R"( - Convert output-referred XYZ values to linear RGB. + Basic matrix example using CLF v2 dim syntax XYZ RGB - XYZ to sRGB matrix + Legacy matrix + Note that dim="3 3 3" should be supported for CLF v2 compatibility Added description 3.24 -1.537 -0.4985 0 0.1 diff --git a/tests/cpu/ops/lut1d/Lut1DOp_tests.cpp b/tests/cpu/ops/lut1d/Lut1DOp_tests.cpp index 990078633e..20b4c683ed 100644 --- a/tests/cpu/ops/lut1d/Lut1DOp_tests.cpp +++ b/tests/cpu/ops/lut1d/Lut1DOp_tests.cpp @@ -284,7 +284,7 @@ OCIO_ADD_TEST(Lut1DRenderer, finite_value_hue_adjust) OCIO_ADD_TEST(Lut1D, lut_1d_compose_with_bit_depth) { - const std::string ctfFile("lut1d_comp.clf"); + const std::string ctfFile("clf/lut1d_comp.clf"); OCIO::OpRcPtrVec ops; OCIO::ContextRcPtr context = OCIO::Context::Create(); diff --git a/tests/cpu/ops/lut3d/Lut3DOpData_tests.cpp b/tests/cpu/ops/lut3d/Lut3DOpData_tests.cpp index 57a8ece3e6..3cc4970341 100644 --- a/tests/cpu/ops/lut3d/Lut3DOpData_tests.cpp +++ b/tests/cpu/ops/lut3d/Lut3DOpData_tests.cpp @@ -242,7 +242,7 @@ OCIO_ADD_TEST(Lut3DOpData, compose) OCIO_ADD_TEST(Lut3DOpData, compose_2) { - const std::string clfFile("lut3d_bizarre.clf"); + const std::string clfFile("clf/lut3d_bizarre.clf"); OCIO::OpRcPtrVec ops; OCIO::ContextRcPtr context = OCIO::Context::Create(); @@ -251,7 +251,7 @@ OCIO_ADD_TEST(Lut3DOpData, compose_2) OCIO_REQUIRE_EQUAL(2, ops.size()); - const std::string clfFile1("lut3d_17x17x17_10i_12i.clf"); + const std::string clfFile1("clf/lut3d_17x17x17_10i_12i.clf"); OCIO::OpRcPtrVec ops1; OCIO_CHECK_NO_THROW(BuildOpsTest(ops1, clfFile1, context, OCIO::TRANSFORM_DIR_FORWARD)); @@ -290,7 +290,7 @@ OCIO_ADD_TEST(Lut3DOpData, compose_2) OCIO_ADD_TEST(Lut3DOpData, inv_lut3d_lut_size) { - const std::string fileName("lut3d_17x17x17_10i_12i.clf"); + const std::string fileName("clf/lut3d_17x17x17_10i_12i.clf"); OCIO::OpRcPtrVec ops; OCIO::ContextRcPtr context = OCIO::Context::Create(); OCIO_CHECK_NO_THROW(BuildOpsTest(ops, fileName, context, diff --git a/tests/cpu/ops/lut3d/Lut3DOp_tests.cpp b/tests/cpu/ops/lut3d/Lut3DOp_tests.cpp index 88d9a7686d..99e8233f87 100644 --- a/tests/cpu/ops/lut3d/Lut3DOp_tests.cpp +++ b/tests/cpu/ops/lut3d/Lut3DOp_tests.cpp @@ -379,7 +379,7 @@ OCIO_ADD_TEST(Lut3DOp, cpu_renderer_cloned) { // The unit test validates the processing of cloned ops. - const std::string fileName("lut3d_17x17x17_10i_12i.clf"); + const std::string fileName("clf/lut3d_17x17x17_10i_12i.clf"); OCIO::OpRcPtrVec ops; OCIO::ContextRcPtr context = OCIO::Context::Create(); OCIO_CHECK_NO_THROW(BuildOpsTest(ops, fileName, context, OCIO::TRANSFORM_DIR_FORWARD)); @@ -444,7 +444,7 @@ OCIO_ADD_TEST(Lut3DOp, cpu_renderer_inverse) { // The unit test validates the processing of inversed ops. - const std::string fileName("lut3d_17x17x17_10i_12i.clf"); + const std::string fileName("clf/lut3d_17x17x17_10i_12i.clf"); OCIO::OpRcPtrVec ops; OCIO::ContextRcPtr context = OCIO::Context::Create(); OCIO_CHECK_NO_THROW(BuildOpsTest(ops, fileName, context, @@ -553,7 +553,7 @@ OCIO_ADD_TEST(Lut3DOp, cpu_renderer_inverse) OCIO_ADD_TEST(Lut3DOp, cpu_renderer_lut3d_with_nan) { - const std::string fileName("lut3d_2x2x2_32f_32f.clf"); + const std::string fileName("clf/lut3d_identity_12i_16f.clf"); OCIO::OpRcPtrVec ops; OCIO::ContextRcPtr context = OCIO::Context::Create(); diff --git a/tests/cpu/ops/reference/ReferenceOpData_tests.cpp b/tests/cpu/ops/reference/ReferenceOpData_tests.cpp index acce967ed9..66af5fed69 100644 --- a/tests/cpu/ops/reference/ReferenceOpData_tests.cpp +++ b/tests/cpu/ops/reference/ReferenceOpData_tests.cpp @@ -169,7 +169,7 @@ OCIO_ADD_TEST(Reference, load_multiple_resolve_internal) OCIO_REQUIRE_ASSERT(ops[1]); op = ops[1]; OCIO_REQUIRE_ASSERT(GetFilePath(path, op)); - OCIO_CHECK_NE(path.find("matrix_example.clf"), std::string::npos); + OCIO_CHECK_NE(path.find("matrix_example_1_3_offsets.ctf"), std::string::npos); OCIO_REQUIRE_ASSERT(ops[2]); op = ops[2]; diff --git a/tests/cpu/transforms/FileTransform_tests.cpp b/tests/cpu/transforms/FileTransform_tests.cpp index 50c8df3ca6..d60b44c5b7 100644 --- a/tests/cpu/transforms/FileTransform_tests.cpp +++ b/tests/cpu/transforms/FileTransform_tests.cpp @@ -73,25 +73,25 @@ OCIO_ADD_TEST(FileTransform, load_file_ok) OCIO_CHECK_ASSERT(!proc->isNoOp()); // Academy/ASC common LUT format. - const std::string clfRangeTransform("range.clf"); + const std::string clfRangeTransform("clf/range.clf"); OCIO_CHECK_NO_THROW(proc = OCIO::GetFileTransformProcessor(clfRangeTransform)); OCIO_CHECK_ASSERT(!proc->isNoOp()); // Academy/ASC common LUT format. - const std::string clfMatTransform("matrix_example.clf"); + const std::string clfMatTransform("clf/matrix_example.clf"); OCIO_CHECK_NO_THROW(proc = OCIO::GetFileTransformProcessor(clfMatTransform)); OCIO_CHECK_ASSERT(!proc->isNoOp()); // Test other types of CLF/CTF elements. - const std::string clfCdlTransform("cdl_clamp_fwd.clf"); + const std::string clfCdlTransform("clf/cdl_clamp_fwd.clf"); OCIO_CHECK_NO_THROW(proc = OCIO::GetFileTransformProcessor(clfCdlTransform)); OCIO_CHECK_ASSERT(!proc->isNoOp()); - const std::string clfLut1Transform("lut1d_example.clf"); + const std::string clfLut1Transform("clf/lut1d_example.clf"); OCIO_CHECK_NO_THROW(proc = OCIO::GetFileTransformProcessor(clfLut1Transform)); OCIO_CHECK_ASSERT(!proc->isNoOp()); - const std::string clfLut3Transform("lut3d_2x2x2_32f_32f.clf"); + const std::string clfLut3Transform("clf/lut3d_identity_12i_16f.clf"); OCIO_CHECK_NO_THROW(proc = OCIO::GetFileTransformProcessor(clfLut3Transform)); OCIO_CHECK_ASSERT(!proc->isNoOp()); @@ -146,7 +146,7 @@ OCIO_ADD_TEST(FileTransform, load_file_fail) // Supported file extension with a wrong content. // It's in fact a binary png file i.e. all readers must fail. - const std::string faultyCLFFile("image_png.clf"); + const std::string faultyCLFFile("clf/illegal/image_png.clf"); OCIO_CHECK_THROW_WHAT(OCIO::GetFileTransformProcessor(faultyCLFFile), OCIO::Exception, "image_png.clf' could not be loaded"); diff --git a/tests/data/files/cdl_invalidSOP.clf b/tests/data/files/cdl_invalidSOP.clf deleted file mode 100644 index f3858a6d54..0000000000 --- a/tests/data/files/cdl_invalidSOP.clf +++ /dev/null @@ -1,17 +0,0 @@ - - - Example of ASC CDL operation - inputDesc - outputDesc - - ASC CDL operation - - 1.35 1.1 - 0.05 -0.23 0.11 - 0.93 0.81 1.27 - - - 1.239 - - - diff --git a/tests/data/files/cdl_invalidSat.clf b/tests/data/files/cdl_invalidSat.clf deleted file mode 100644 index bfce6f22ac..0000000000 --- a/tests/data/files/cdl_invalidSat.clf +++ /dev/null @@ -1,17 +0,0 @@ - - - Example of ASC CDL operation - inputDesc - outputDesc - - ASC CDL operation - - 1.35 1.1 0.71 - 0.05 -0.23 0.11 - 0.93 0.81 1.27 - - - 1.239 0.9 - - - diff --git a/tests/data/files/clf/cdl_all_styles.clf b/tests/data/files/clf/cdl_all_styles.clf new file mode 100644 index 0000000000..681acaa752 --- /dev/null +++ b/tests/data/files/clf/cdl_all_styles.clf @@ -0,0 +1,44 @@ + + + Test all CDL style values + + + 1.000000 1.000000 0.800000 + -0.020000 0.00000 0.150000 + 1.0500000 1.150000 1.40000 + + + 0.750000 + + + + + 1.000000 1.000000 0.800000 + -0.020000 0.00000 0.150000 + 1.0500000 1.150000 1.40000 + + + 0.750000 + + + + + 1.000000 1.000000 0.800000 + -0.020000 0.00000 0.150000 + 1.0500000 1.150000 1.40000 + + + 0.750000 + + + + + 1.000000 1.000000 0.800000 + -0.020000 0.00000 0.150000 + 1.0500000 1.150000 1.40000 + + + 1.750000 + + + diff --git a/tests/data/files/cdl_clamp_fwd.clf b/tests/data/files/clf/cdl_clamp_fwd.clf similarity index 91% rename from tests/data/files/cdl_clamp_fwd.clf rename to tests/data/files/clf/cdl_clamp_fwd.clf index 71ae47340e..3a298fa13e 100644 --- a/tests/data/files/cdl_clamp_fwd.clf +++ b/tests/data/files/clf/cdl_clamp_fwd.clf @@ -1,5 +1,5 @@ - + Example of ASC CDL operation inputDesc outputDesc diff --git a/tests/data/files/cdl_noSat.clf b/tests/data/files/clf/cdl_missing_sat.clf similarity index 59% rename from tests/data/files/cdl_noSat.clf rename to tests/data/files/clf/cdl_missing_sat.clf index 1e75833add..40fa7f8851 100644 --- a/tests/data/files/cdl_noSat.clf +++ b/tests/data/files/clf/cdl_missing_sat.clf @@ -1,8 +1,6 @@ - - Example of ASC CDL operation - inputDesc - outputDesc + + Missing Sat defaults to 1 ASC CDL operation diff --git a/tests/data/files/cdl_noSOP.clf b/tests/data/files/clf/cdl_missing_sop.clf similarity index 73% rename from tests/data/files/cdl_noSOP.clf rename to tests/data/files/clf/cdl_missing_sop.clf index f70ddf4166..99ab40eb4c 100644 --- a/tests/data/files/cdl_noSOP.clf +++ b/tests/data/files/clf/cdl_missing_sop.clf @@ -1,6 +1,6 @@ - - Example of ASC CDL operation + + Missing SOP defaults to identity params inputDesc outputDesc diff --git a/tests/data/files/cdl_missing_style.clf b/tests/data/files/clf/cdl_missing_style.clf similarity index 57% rename from tests/data/files/cdl_missing_style.clf rename to tests/data/files/clf/cdl_missing_style.clf index 9dcafbe695..2c407b929d 100644 --- a/tests/data/files/cdl_missing_style.clf +++ b/tests/data/files/clf/cdl_missing_style.clf @@ -1,10 +1,7 @@ - - Example of ASC CDL operation - inputDesc - outputDesc + + Missing style defaults to "Fwd" - ASC CDL operation 1.35 1.1 0.71 0.05 -0.23 0.11 diff --git a/tests/data/files/clf/difficult_syntax.clf b/tests/data/files/clf/difficult_syntax.clf new file mode 100644 index 0000000000..a64a08247c --- /dev/null +++ b/tests/data/files/clf/difficult_syntax.clf @@ -0,0 +1,71 @@ + + + + + + + + + + +This is a "difficult" but 'legal' color transform file. + + + + + + +third array dim value is ignored + + + + + + 3.24000 -1.53700 -0.49850 +-0.96930 1.87600 0.04156 + 0.05560 -0.20400 0.105730e+1 + + + + + + This is the ProcessList description. + + + the n–dash description + + 0.00000 0.00000 0.00000 + 0.28358 2.8358E-1 0.28358 + 0.38860 0.38860 0.38860 + 0.46725 0.46725 0.46725 + + 0.53252 0.53252 0.53252 + 0.58937 0.58937 0.58937 + 0.64029 0.64029 0.64029 + 0.68677 0.68677 0.68677 +0.72974 0.72974 0.72974 + 0.76987 0.76987 0.76987 +0.80764 0.80764 0.80764 + 0.84340 0.84340 0.84340 + 0.87742 0.87742 +0.87742 + 0.90994 0.90994 0.90994 0.94111 0.94111 0.94111 0.97109 0.97109 0.99999 1.00000 1.00000 1.00000 + + + another valid +description +element + + + + & another <valid> desc + + + yet 'another' "valid" desc + + + diff --git a/tests/data/files/clf/exponent_all_styles.clf b/tests/data/files/clf/exponent_all_styles.clf new file mode 100644 index 0000000000..8478a6e143 --- /dev/null +++ b/tests/data/files/clf/exponent_all_styles.clf @@ -0,0 +1,47 @@ + + + Test all Exponent style values + + If there is only one Params, use it for R, G, and B. + + + + + + + + + Rec 709 OETF + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/data/files/array_illegal_dimension.clf b/tests/data/files/clf/illegal/array_bad_dimension.clf similarity index 81% rename from tests/data/files/array_illegal_dimension.clf rename to tests/data/files/clf/illegal/array_bad_dimension.clf index c1b763578a..918b1720c4 100644 --- a/tests/data/files/array_illegal_dimension.clf +++ b/tests/data/files/clf/illegal/array_bad_dimension.clf @@ -1,7 +1,7 @@ - + - XYZ to sRGB matrix + Array dim attribute is not legal. 3.24000 -1.53700 -0.49850 -0.96930 1.87600 0.04156 diff --git a/tests/data/files/array_illegal_values.clf b/tests/data/files/clf/illegal/array_bad_value.clf similarity index 74% rename from tests/data/files/array_illegal_values.clf rename to tests/data/files/clf/illegal/array_bad_value.clf index 168aef75b4..28f607b9d2 100644 --- a/tests/data/files/array_illegal_values.clf +++ b/tests/data/files/clf/illegal/array_bad_value.clf @@ -1,8 +1,8 @@ - + - XYZ to sRGB matrix - + Array has a non-numeric character + 3.24000 -1.53700 -0.49850 -0.96930 P 0.04156 0.05560 -0.20400 1.05730 diff --git a/tests/data/files/array_missing_values.clf b/tests/data/files/clf/illegal/array_missing_values.clf similarity index 52% rename from tests/data/files/array_missing_values.clf rename to tests/data/files/clf/illegal/array_missing_values.clf index 7b762ec279..fafd66361e 100644 --- a/tests/data/files/array_missing_values.clf +++ b/tests/data/files/clf/illegal/array_missing_values.clf @@ -1,7 +1,8 @@ - + - + Matrix has too few values. + 1 2 3 diff --git a/tests/data/files/array_too_many_values.clf b/tests/data/files/clf/illegal/array_too_many_values.clf similarity index 79% rename from tests/data/files/array_too_many_values.clf rename to tests/data/files/clf/illegal/array_too_many_values.clf index bcaaccc82b..49957befdc 100644 --- a/tests/data/files/array_too_many_values.clf +++ b/tests/data/files/clf/illegal/array_too_many_values.clf @@ -1,8 +1,8 @@ - + - XYZ to sRGB matrix - + Matrix has too many values. + 3.24000 -1.53700 -0.49850 -0.96930 1.87600 0.04156 0.05560 -0.20400 1.05730 diff --git a/tests/data/files/cdl_missing_power.clf b/tests/data/files/clf/illegal/cdl_bad_power.clf similarity index 55% rename from tests/data/files/cdl_missing_power.clf rename to tests/data/files/clf/illegal/cdl_bad_power.clf index eb8936862f..e39c8a611f 100644 --- a/tests/data/files/cdl_missing_power.clf +++ b/tests/data/files/clf/illegal/cdl_bad_power.clf @@ -1,13 +1,11 @@ - - Example of ASC CDL operation - inputDesc - outputDesc + + CDL power must be > 0 - ASC CDL operation 1.35 1.1 0.71 0.05 -0.23 0.11 + 0.93 0.81 0 1.239 diff --git a/tests/data/files/clf/illegal/cdl_bad_sat.clf b/tests/data/files/clf/illegal/cdl_bad_sat.clf new file mode 100644 index 0000000000..bca68a6813 --- /dev/null +++ b/tests/data/files/clf/illegal/cdl_bad_sat.clf @@ -0,0 +1,14 @@ + + + Sat may only have 1 value. + + + 1.35 1.1 0.71 + 0.05 -0.23 0.11 + 0.93 0.81 1.27 + + + 1.239 0.9 + + + diff --git a/tests/data/files/clf/illegal/cdl_bad_slope.clf b/tests/data/files/clf/illegal/cdl_bad_slope.clf new file mode 100644 index 0000000000..b267e9cf45 --- /dev/null +++ b/tests/data/files/clf/illegal/cdl_bad_slope.clf @@ -0,0 +1,14 @@ + + + Slope must have 3 values. + + + 1.35 1.1 + 0.05 -0.23 0.11 + 0.93 0.81 1.27 + + + 1.239 + + + diff --git a/tests/data/files/cdl_invalid_style.clf b/tests/data/files/clf/illegal/cdl_bad_style.clf similarity index 59% rename from tests/data/files/cdl_invalid_style.clf rename to tests/data/files/clf/illegal/cdl_bad_style.clf index 51cfcb9005..40dc6420b9 100644 --- a/tests/data/files/cdl_invalid_style.clf +++ b/tests/data/files/clf/illegal/cdl_bad_style.clf @@ -1,10 +1,7 @@ - - Example of ASC CDL operation - inputDesc - outputDesc + + CDL style is not a legal value - ASC CDL operation 1.35 1.1 0.71 0.05 -0.23 0.11 diff --git a/tests/data/files/cdl_missing_offset.clf b/tests/data/files/clf/illegal/cdl_missing_offset.clf similarity index 51% rename from tests/data/files/cdl_missing_offset.clf rename to tests/data/files/clf/illegal/cdl_missing_offset.clf index 874e0b847e..0ee0dbf2f8 100644 --- a/tests/data/files/cdl_missing_offset.clf +++ b/tests/data/files/clf/illegal/cdl_missing_offset.clf @@ -1,12 +1,10 @@ - - Example of ASC CDL operation - inputDesc - outputDesc - - ASC CDL operation + + The SOPNode is optional, but if present, must contain Slope, Offset, and Power + 1.35 1.1 0.71 + 0.93 0.81 1.27 diff --git a/tests/data/files/clf/illegal/cdl_missing_power.clf b/tests/data/files/clf/illegal/cdl_missing_power.clf new file mode 100644 index 0000000000..a759f90576 --- /dev/null +++ b/tests/data/files/clf/illegal/cdl_missing_power.clf @@ -0,0 +1,14 @@ + + + The SOPNode is optional, but if present, must contain Slope, Offset, and Power + + + 1.35 1.1 0.71 + 0.05 -0.23 0.11 + + + + 1.239 + + + diff --git a/tests/data/files/cdl_missing_slope.clf b/tests/data/files/clf/illegal/cdl_missing_slope.clf similarity index 54% rename from tests/data/files/cdl_missing_slope.clf rename to tests/data/files/clf/illegal/cdl_missing_slope.clf index dfa6fc46ea..efd3e9d274 100644 --- a/tests/data/files/cdl_missing_slope.clf +++ b/tests/data/files/clf/illegal/cdl_missing_slope.clf @@ -1,10 +1,7 @@ - - Example of ASC CDL operation - inputDesc - outputDesc - - ASC CDL operation + + The SOPNode is optional, but if present, must contain Slope, Offset, and Power + 0.05 -0.23 0.11 diff --git a/tests/data/files/clf/illegal/exponent_bad_param.clf b/tests/data/files/clf/illegal/exponent_bad_param.clf new file mode 100644 index 0000000000..5e3094f70c --- /dev/null +++ b/tests/data/files/clf/illegal/exponent_bad_param.clf @@ -0,0 +1,7 @@ + + + The basic styles may not use the offset param + + + + diff --git a/tests/data/files/clf/illegal/exponent_bad_value.clf b/tests/data/files/clf/illegal/exponent_bad_value.clf new file mode 100644 index 0000000000..2a358d5313 --- /dev/null +++ b/tests/data/files/clf/illegal/exponent_bad_value.clf @@ -0,0 +1,7 @@ + + + The moncurve style requires an exponent >= 1. + + + + diff --git a/tests/data/files/image_png.clf b/tests/data/files/clf/illegal/image_png.clf similarity index 100% rename from tests/data/files/image_png.clf rename to tests/data/files/clf/illegal/image_png.clf diff --git a/tests/data/files/clf/illegal/indexMap_test2.clf b/tests/data/files/clf/illegal/indexMap_test2.clf new file mode 100644 index 0000000000..498ac6454e --- /dev/null +++ b/tests/data/files/clf/illegal/indexMap_test2.clf @@ -0,0 +1,19 @@ + + + Index map was only allowed up to CLF v2 + + + 0 30 33 + 0 0 133 + 0 0 223 + 0 0 324 + 0 192 335 + 0 241 448 + 26 308 580 + 87 384 743 + + + -1e-1@0 1.9e1@ 1 + + + diff --git a/tests/data/files/clf/illegal/log_bad_param.clf b/tests/data/files/clf/illegal/log_bad_param.clf new file mode 100644 index 0000000000..db03820476 --- /dev/null +++ b/tests/data/files/clf/illegal/log_bad_param.clf @@ -0,0 +1,7 @@ + + + The linToLog style may not contain the linSideBreak param. + + + + diff --git a/tests/data/files/clf/illegal/log_bad_style.clf b/tests/data/files/clf/illegal/log_bad_style.clf new file mode 100644 index 0000000000..dbc1ac9319 --- /dev/null +++ b/tests/data/files/clf/illegal/log_bad_style.clf @@ -0,0 +1,6 @@ + + + Illegal log style value. + + + diff --git a/tests/data/files/log_log10_faulty_version.ctf b/tests/data/files/clf/illegal/log_bad_version.clf similarity index 76% rename from tests/data/files/log_log10_faulty_version.ctf rename to tests/data/files/clf/illegal/log_bad_version.clf index dddf9a575e..6aea455cd7 100644 --- a/tests/data/files/log_log10_faulty_version.ctf +++ b/tests/data/files/clf/illegal/log_bad_version.clf @@ -1,5 +1,5 @@ - + Version is too low to support Log. inputDesc outputDesc diff --git a/tests/data/files/clf/illegal/log_missing_breakpnt.clf b/tests/data/files/clf/illegal/log_missing_breakpnt.clf new file mode 100644 index 0000000000..4282f23df7 --- /dev/null +++ b/tests/data/files/clf/illegal/log_missing_breakpnt.clf @@ -0,0 +1,8 @@ + + + The camera styles must have the linSideBreak param. + + + + diff --git a/tests/data/files/clf/illegal/lut1d_half_domain_missing_values.clf b/tests/data/files/clf/illegal/lut1d_half_domain_missing_values.clf new file mode 100644 index 0000000000..f50ec51898 --- /dev/null +++ b/tests/data/files/clf/illegal/lut1d_half_domain_missing_values.clf @@ -0,0 +1,42 @@ + + + Half-domain must have 65536 values. + RGB + RGB + + + 0 + 215 + 294 + 354 + 403 + 446 + 485 + 520 + 553 + 583 + 612 + 639 + 665 + 689 + 713 + 735 + 757 + 779 + 799 + 819 + 838 + 857 + 875 + 893 + 911 + 928 + 944 + 961 + 977 + 992 +1008 +1023 + + + \ No newline at end of file diff --git a/tests/data/files/clf/illegal/lut1d_half_domain_set_false.clf b/tests/data/files/clf/illegal/lut1d_half_domain_set_false.clf new file mode 100644 index 0000000000..fca07d882f --- /dev/null +++ b/tests/data/files/clf/illegal/lut1d_half_domain_set_false.clf @@ -0,0 +1,42 @@ + + + The only legal value for halfDomain is "true". + RGB + RGB + + + 0 + 215 + 294 + 354 + 403 + 446 + 485 + 520 + 553 + 583 + 612 + 639 + 665 + 689 + 713 + 735 + 757 + 779 + 799 + 819 + 838 + 857 + 875 + 893 + 911 + 928 + 944 + 961 + 977 + 992 +1008 +1023 + + + \ No newline at end of file diff --git a/tests/data/files/clf/illegal/lut1d_raw_half_set_false.clf b/tests/data/files/clf/illegal/lut1d_raw_half_set_false.clf new file mode 100644 index 0000000000..94daa1e6f9 --- /dev/null +++ b/tests/data/files/clf/illegal/lut1d_raw_half_set_false.clf @@ -0,0 +1,42 @@ + + + The only legal value for rawHhalfs is "true". + RGB + RGB + + + 0 + 215 + 294 + 354 + 403 + 446 + 485 + 520 + 553 + 583 + 612 + 639 + 665 + 689 + 713 + 735 + 757 + 779 + 799 + 819 + 838 + 857 + 875 + 893 + 911 + 928 + 944 + 961 + 977 + 992 +1008 +1023 + + + \ No newline at end of file diff --git a/tests/data/files/clf/illegal/lut3d_unequal_size.clf b/tests/data/files/clf/illegal/lut3d_unequal_size.clf new file mode 100644 index 0000000000..1be11cfab9 --- /dev/null +++ b/tests/data/files/clf/illegal/lut3d_unequal_size.clf @@ -0,0 +1,20 @@ + + + Lut3d must have equal grid dimensions + + +0 0 0 +0 0 1 +0 1 0 +0 1 1 +0 0 0 +0 0 1 +0 1 0 +0 1 1 +1 0 0 +1 0 1 +1 1 0 +1 1 1 + + + diff --git a/tests/data/files/matrix_end_missing.clf b/tests/data/files/clf/illegal/matrix_end_missing.clf similarity index 72% rename from tests/data/files/matrix_end_missing.clf rename to tests/data/files/clf/illegal/matrix_end_missing.clf index 7742a53cc3..b00cddd8cd 100644 --- a/tests/data/files/matrix_end_missing.clf +++ b/tests/data/files/clf/illegal/matrix_end_missing.clf @@ -1,4 +1,5 @@ - + + The Matrix element is not complete. diff --git a/tests/data/files/clf/illegal/process_list_bad_version.clf b/tests/data/files/clf/illegal/process_list_bad_version.clf new file mode 100644 index 0000000000..11408a1c28 --- /dev/null +++ b/tests/data/files/clf/illegal/process_list_bad_version.clf @@ -0,0 +1,11 @@ + + + Not a legal compCLFversion string + + + 3.24000 -1.53700 -0.49850 +-0.96930 1.87600 0.04156 + 0.05560 -0.20400 1.05730 + + + diff --git a/tests/data/files/clf/illegal/process_list_higher_version.clf b/tests/data/files/clf/illegal/process_list_higher_version.clf new file mode 100644 index 0000000000..8e1d97bff0 --- /dev/null +++ b/tests/data/files/clf/illegal/process_list_higher_version.clf @@ -0,0 +1,11 @@ + + + Versions higher than current version must be rejected + + + 3.24000 -1.53700 -0.49850 +-0.96930 1.87600 0.04156 + 0.05560 -0.20400 1.05730 + + + diff --git a/tests/data/files/not_a_ctf.xml b/tests/data/files/clf/illegal/process_list_missing.clf similarity index 64% rename from tests/data/files/not_a_ctf.xml rename to tests/data/files/clf/illegal/process_list_missing.clf index d33a590395..0dbe66c238 100644 --- a/tests/data/files/not_a_ctf.xml +++ b/tests/data/files/clf/illegal/process_list_missing.clf @@ -1,5 +1,6 @@ - + Missing ProcesssList element + 3.24000 -1.53700 -0.49850 -0.96930 1.87600 0.04156 0.05560 -0.20400 1.05730 diff --git a/tests/data/files/clf/illegal/range_bad_noclamp.clf b/tests/data/files/clf/illegal/range_bad_noclamp.clf new file mode 100644 index 0000000000..3751a6bfb6 --- /dev/null +++ b/tests/data/files/clf/illegal/range_bad_noclamp.clf @@ -0,0 +1,8 @@ + + + The noClamp style may not be used when there are only two values. + + 0.1 + 1e-1 + + diff --git a/tests/data/files/range_test3.clf b/tests/data/files/clf/illegal/range_empty.clf similarity index 59% rename from tests/data/files/range_test3.clf rename to tests/data/files/clf/illegal/range_empty.clf index 36ba07f0d3..f4bb850cfa 100644 --- a/tests/data/files/range_test3.clf +++ b/tests/data/files/clf/illegal/range_empty.clf @@ -1,5 +1,6 @@ - + + Starting in CLF v3, a Range may not be empty diff --git a/tests/data/files/clf/illegal/range_nonmatching_clamp.clf b/tests/data/files/clf/illegal/range_nonmatching_clamp.clf new file mode 100644 index 0000000000..b8fee78a67 --- /dev/null +++ b/tests/data/files/clf/illegal/range_nonmatching_clamp.clf @@ -0,0 +1,9 @@ + + + If there is only a min or only a max, the InValue must equal OutValue. + Since the bit-depths are different, they are not actually the same here. + + 256 + 256 + + \ No newline at end of file diff --git a/tests/data/files/unknown_outdepth.clf b/tests/data/files/clf/illegal/transform_bad_outdepth.clf similarity index 70% rename from tests/data/files/unknown_outdepth.clf rename to tests/data/files/clf/illegal/transform_bad_outdepth.clf index d4d4b1da74..8d65b6db95 100644 --- a/tests/data/files/unknown_outdepth.clf +++ b/tests/data/files/clf/illegal/transform_bad_outdepth.clf @@ -1,8 +1,8 @@ - - - XYZ to sRGB matrix - + + The outBitDepth is illegal + + 3.24000 -1.53700 -0.49850 -0.96930 1.87600 0.04156 0.05560 -0.20400 1.05730 diff --git a/tests/data/files/transform_bitdepth_mismatch.clf b/tests/data/files/clf/illegal/transform_bitdepth_mismatch.clf similarity index 72% rename from tests/data/files/transform_bitdepth_mismatch.clf rename to tests/data/files/clf/illegal/transform_bitdepth_mismatch.clf index 3abe367b9b..1153df6a4e 100644 --- a/tests/data/files/transform_bitdepth_mismatch.clf +++ b/tests/data/files/clf/illegal/transform_bitdepth_mismatch.clf @@ -1,12 +1,14 @@ - - + + All bit-depths in a file must match at adjacent ops + 3.24000 -1.53700 -0.49850 -0.96930 1.87600 0.04156 0.05560 -0.20400 1.05730 - + Note in-depth does not == out-depth of previous + 0.00000 0.00000 1e-2 0.28358 0.28358 1e+2 diff --git a/tests/data/files/clf/illegal/transform_corrupted_tag.clf b/tests/data/files/clf/illegal/transform_corrupted_tag.clf new file mode 100644 index 0000000000..1f82247b18 --- /dev/null +++ b/tests/data/files/clf/illegal/transform_corrupted_tag.clf @@ -0,0 +1,12 @@ + + + Note closing element is bad + + + 3.24000 -1.53700 -0.49850 +-0.96930 1.87600 0.04156 + 0.05560 -0.20400 1.05730 + + + ProcessList is not spelled correctly + diff --git a/tests/data/files/clf/illegal/transform_element_end_missing.clf b/tests/data/files/clf/illegal/transform_element_end_missing.clf new file mode 100644 index 0000000000..136c8453cb --- /dev/null +++ b/tests/data/files/clf/illegal/transform_element_end_missing.clf @@ -0,0 +1,11 @@ + + + ProcessList must have an end tag + + + 3.24000 -1.53700 -0.49850 +-0.96930 1.87600 0.04156 + 0.05560 -0.20400 1.05730 + + + Note closing element is missing diff --git a/tests/data/files/transform_empty.clf b/tests/data/files/clf/illegal/transform_empty.clf similarity index 58% rename from tests/data/files/transform_empty.clf rename to tests/data/files/clf/illegal/transform_empty.clf index 78b70e9a53..b07de5aa5b 100644 --- a/tests/data/files/transform_empty.clf +++ b/tests/data/files/clf/illegal/transform_empty.clf @@ -1,3 +1,4 @@ - + + There must be at least on process node diff --git a/tests/data/files/clf/illegal/transform_id_empty.clf b/tests/data/files/clf/illegal/transform_id_empty.clf new file mode 100644 index 0000000000..bda57d36ef --- /dev/null +++ b/tests/data/files/clf/illegal/transform_id_empty.clf @@ -0,0 +1,5 @@ + + + The id string must not be empty + + diff --git a/tests/data/files/transform_invalid.clf b/tests/data/files/clf/illegal/transform_missing.clf similarity index 100% rename from tests/data/files/transform_invalid.clf rename to tests/data/files/clf/illegal/transform_missing.clf diff --git a/tests/data/files/clf/illegal/transform_missing_id.clf b/tests/data/files/clf/illegal/transform_missing_id.clf new file mode 100644 index 0000000000..a72ed5577b --- /dev/null +++ b/tests/data/files/clf/illegal/transform_missing_id.clf @@ -0,0 +1,5 @@ + + + The ProcessList id attribute is missing + + diff --git a/tests/data/files/clf/illegal/transform_missing_inbitdepth.clf b/tests/data/files/clf/illegal/transform_missing_inbitdepth.clf new file mode 100644 index 0000000000..011ff246d7 --- /dev/null +++ b/tests/data/files/clf/illegal/transform_missing_inbitdepth.clf @@ -0,0 +1,10 @@ + + + The inBitDepth is missing + + +64 +196 + + + diff --git a/tests/data/files/clf/illegal/transform_missing_outbitdepth.clf b/tests/data/files/clf/illegal/transform_missing_outbitdepth.clf new file mode 100644 index 0000000000..26d7cd176d --- /dev/null +++ b/tests/data/files/clf/illegal/transform_missing_outbitdepth.clf @@ -0,0 +1,10 @@ + + + The outBitDepth is missing + + +64 +196 + + + diff --git a/tests/data/files/unknown_elements.clf b/tests/data/files/clf/illegal/unknown_elements.clf similarity index 85% rename from tests/data/files/unknown_elements.clf rename to tests/data/files/clf/illegal/unknown_elements.clf index f30944c967..adc9dd3886 100644 --- a/tests/data/files/unknown_elements.clf +++ b/tests/data/files/clf/illegal/unknown_elements.clf @@ -1,8 +1,9 @@ - - Convert output-referred XYZ values to gamma-corrected RGB. + + This example contains unknown elements + See section 5.4 of the spec: Unrecognized elements that are not children of the Info element + should either raise an error or at least provide a warning message - XYZ to sRGB matrix 3.24000 -1.53700 -0.49850 -0.96930 1.87600 0.04156 @@ -10,7 +11,6 @@ - linear to 1/2.2 gamma corrected code values 0.00000 0.00000 1e-2 0.28358 0.28358 1e+2 diff --git a/tests/data/files/clf/info_example.clf b/tests/data/files/clf/info_example.clf new file mode 100644 index 0000000000..c4cf5b602c --- /dev/null +++ b/tests/data/files/clf/info_example.clf @@ -0,0 +1,40 @@ + + + Example of using the Info element + input desc + output desc + A second description + + + + Copyright Contributors to the OpenColorIO Project. + 2020.0.63 + 1 + + + + + + + + + Input color space description + video + no_version + 387b23d1-f1ce-3f69-8544-e5601f45f78b + + + scene + ACES + 1 + + + + + +4095 0 0 +0 4095 0 +0 0 4095 + + + diff --git a/tests/data/files/inverseOfId_test.clf b/tests/data/files/clf/inverseOf_id_test.clf similarity index 61% rename from tests/data/files/inverseOfId_test.clf rename to tests/data/files/clf/inverseOf_id_test.clf index ec8c8ba07a..b04a3873ff 100644 --- a/tests/data/files/inverseOfId_test.clf +++ b/tests/data/files/clf/inverseOf_id_test.clf @@ -1,10 +1,10 @@ - - Apply a 1/2.2 gamma. + + The inverseOf attribute is used to identify inverse pairs RGB RGB - linear to 1/2.2 gamma corrected code values + linear to 1/2.2 approx. gamma corrected code values 0 215 diff --git a/tests/data/files/clf/log_all_styles.clf b/tests/data/files/clf/log_all_styles.clf new file mode 100644 index 0000000000..4d8435a829 --- /dev/null +++ b/tests/data/files/clf/log_all_styles.clf @@ -0,0 +1,47 @@ + + + Test all Logarithmic style values + + + AntiLog2 logarithm operation + + + Log base 2 + + + + Classic Cineon curve + + + + + + + + + + + + ACEScct curve + Note that the default base is 2 + + + + ACEScct curve + + + + + + + + + + + + + + diff --git a/tests/data/files/clf/lut1d_32f_example.clf b/tests/data/files/clf/lut1d_32f_example.clf new file mode 100644 index 0000000000..09a849d0e0 --- /dev/null +++ b/tests/data/files/clf/lut1d_32f_example.clf @@ -0,0 +1,8 @@ + + + Basic Lut1D example + + 1D LUT +1.0 0.8 0.6 0 + + \ No newline at end of file diff --git a/tests/data/files/lut1d_comp.clf b/tests/data/files/clf/lut1d_comp.clf similarity index 94% rename from tests/data/files/lut1d_comp.clf rename to tests/data/files/clf/lut1d_comp.clf index feaf7e7442..04d2833676 100644 --- a/tests/data/files/lut1d_comp.clf +++ b/tests/data/files/clf/lut1d_comp.clf @@ -1,6 +1,6 @@ - - Test LUT1D 1 + + Two Lut1D ops 64 diff --git a/tests/data/files/clf/lut1d_example.clf b/tests/data/files/clf/lut1d_example.clf new file mode 100644 index 0000000000..d57474bbf5 --- /dev/null +++ b/tests/data/files/clf/lut1d_example.clf @@ -0,0 +1,10 @@ + + + 1D LUT with legal out of range values + + Note that the bit-depth does not constrain the legal range of values. + +-100 400 800 2500 + + + \ No newline at end of file diff --git a/tests/data/files/lut1d_half_domain_raw_half_set.clf b/tests/data/files/clf/lut1d_half_domain_raw_half_set.clf similarity index 99% rename from tests/data/files/lut1d_half_domain_raw_half_set.clf rename to tests/data/files/clf/lut1d_half_domain_raw_half_set.clf index 784b5bc6ef..372d1223d7 100644 --- a/tests/data/files/lut1d_half_domain_raw_half_set.clf +++ b/tests/data/files/clf/lut1d_half_domain_raw_half_set.clf @@ -1,8 +1,9 @@ - + + Lut1D using halfDomain and rawHalfs features RGB RGB - + 0 215 diff --git a/tests/data/files/lut3by1d_nan_infinity_example.clf b/tests/data/files/clf/lut3by1d_nan_infinity_example.clf similarity index 59% rename from tests/data/files/lut3by1d_nan_infinity_example.clf rename to tests/data/files/clf/lut3by1d_nan_infinity_example.clf index a9833f6fe6..f70e7084a4 100644 --- a/tests/data/files/lut3by1d_nan_infinity_example.clf +++ b/tests/data/files/clf/lut3by1d_nan_infinity_example.clf @@ -1,5 +1,6 @@ - + + Test support for NaN and Inf in Array values NAN -NAN -NAN diff --git a/tests/data/files/lut3d_17x17x17_10i_12i.clf b/tests/data/files/clf/lut3d_17x17x17_10i_12i.clf similarity index 99% rename from tests/data/files/lut3d_17x17x17_10i_12i.clf rename to tests/data/files/clf/lut3d_17x17x17_10i_12i.clf index 013a72010f..3a94ab78fe 100644 --- a/tests/data/files/lut3d_17x17x17_10i_12i.clf +++ b/tests/data/files/clf/lut3d_17x17x17_10i_12i.clf @@ -1,6 +1,6 @@ - - example 3d-LUT. + + Basic 3d-LUT example. 0 12 13 diff --git a/tests/data/files/lut3d_bizarre.clf b/tests/data/files/clf/lut3d_bizarre.clf similarity index 66% rename from tests/data/files/lut3d_bizarre.clf rename to tests/data/files/clf/lut3d_bizarre.clf index 6ef4d8a6df..707e354c91 100644 --- a/tests/data/files/lut3d_bizarre.clf +++ b/tests/data/files/clf/lut3d_bizarre.clf @@ -1,8 +1,8 @@ - - - - Bizarre 3d-LUT with extended range values + + Unusual 3d-LUT useful for showing interpolation errors + + 3d-LUT with extended range values -60 5 75 -10 50 400 diff --git a/tests/data/files/clf/lut3d_identity_12i_16f.clf b/tests/data/files/clf/lut3d_identity_12i_16f.clf new file mode 100644 index 0000000000..463f31dcbd --- /dev/null +++ b/tests/data/files/clf/lut3d_identity_12i_16f.clf @@ -0,0 +1,17 @@ + + + 3D LUT example + + 3D LUT + +0.0 0.0 0.0 +0.0 0.0 1.0 +0.0 1.0 0.0 +0.0 1.0 1.0 +1.0 0.0 0.0 +1.0 0.0 1.0 +1.0 1.0 0.0 +1.0 1.0 1.0 + + + \ No newline at end of file diff --git a/tests/data/files/clf/matrix_3x4_example.clf b/tests/data/files/clf/matrix_3x4_example.clf new file mode 100644 index 0000000000..d88b3da62d --- /dev/null +++ b/tests/data/files/clf/matrix_3x4_example.clf @@ -0,0 +1,13 @@ + + + Matrix example + Used by unit tests + + 3x4 Matrix , 4th column is offset + +4.8 0.1 -0.2 0.3 +0.4 3.5 0.1 -0.05 +0.6 -0.7 4.2 -4e-1 + + + \ No newline at end of file diff --git a/tests/data/files/matrix_example.clf b/tests/data/files/clf/matrix_example.clf similarity index 60% rename from tests/data/files/matrix_example.clf rename to tests/data/files/clf/matrix_example.clf index 810aad3228..6d4e9a3a91 100644 --- a/tests/data/files/matrix_example.clf +++ b/tests/data/files/clf/matrix_example.clf @@ -1,10 +1,11 @@ - - Convert output-referred XYZ values to linear RGB. + + Basic matrix example using CLF v2 dim syntax XYZ RGB - XYZ to sRGB matrix + Legacy matrix + Note that dim="3 3 3" should be supported for CLF v2 compatibility 3.24000 -1.53700 -0.49850 -0.96930 1.87600 0.04156 diff --git a/tests/data/files/matrix_example_utf8.clf b/tests/data/files/clf/matrix_example_utf8.clf similarity index 59% rename from tests/data/files/matrix_example_utf8.clf rename to tests/data/files/clf/matrix_example_utf8.clf index a9994ce31b..b8167e9584 100644 --- a/tests/data/files/matrix_example_utf8.clf +++ b/tests/data/files/clf/matrix_example_utf8.clf @@ -1,9 +1,9 @@ - - Test utf8. + + Test utf8 character encoding support. 標準萬國碼 - + 3.24000 -1.53700 -0.49850 -0.96930 1.87600 0.04156 0.05560 -0.20400 1.05730 diff --git a/tests/data/files/matrix_windows.clf b/tests/data/files/clf/matrix_windows.clf similarity index 56% rename from tests/data/files/matrix_windows.clf rename to tests/data/files/clf/matrix_windows.clf index c8ab0dde70..7e7241610c 100644 --- a/tests/data/files/matrix_windows.clf +++ b/tests/data/files/clf/matrix_windows.clf @@ -1,11 +1,11 @@ - - This file has Windows line-endings. - Also, the file does not start with a ?xml header. - - -4095 0 0 -0 4095 0 -0 0 4095 - - + + This file has Windows line-endings. + Also, the file does not start with a ?xml header. + + +4095 0 0 +0 4095 0 +0 0 4095 + + \ No newline at end of file diff --git a/tests/data/files/multiple_ops.clf b/tests/data/files/clf/multiple_ops.clf similarity index 58% rename from tests/data/files/multiple_ops.clf rename to tests/data/files/clf/multiple_ops.clf index d27d7dc689..b94bae34a9 100644 --- a/tests/data/files/multiple_ops.clf +++ b/tests/data/files/clf/multiple_ops.clf @@ -1,5 +1,6 @@ - + + Test with lots of different process nodes scene 1 exterior look @@ -12,7 +13,6 @@ - 64.5@4 940 @ 29 0 215 @@ -66,4 +66,32 @@ 20.0000 900.0000 + + Classic Cineon curve + + + + 3x4 Matrix , 4th column is offset + + 1.2 0.0 0.2 0.002 + 0.0 1.03 0.001 -0.005 + 0.004 -0.007 1.004 0.0 + + + + + + + +0 0 -0.1 +0 0 0.5 +0 1 0 +0 1 1 +1 0 0 +1 0 1 +1 1 0 +1.2 1 1 + + \ No newline at end of file diff --git a/tests/data/files/clf/range.clf b/tests/data/files/clf/range.clf new file mode 100644 index 0000000000..88c38cdedc --- /dev/null +++ b/tests/data/files/clf/range.clf @@ -0,0 +1,13 @@ + + + Basic range example with no style attribute + RGB + RGB + + Note that when style is missing, the default is to clamp. + 16320 + 32640 + 16320 + 32640 + + \ No newline at end of file diff --git a/tests/data/files/clf/range_test1_clamp.clf b/tests/data/files/clf/range_test1_clamp.clf new file mode 100644 index 0000000000..f7e436dee0 --- /dev/null +++ b/tests/data/files/clf/range_test1_clamp.clf @@ -0,0 +1,10 @@ + + + Basic range example + + 16 + 240 + -0.5 + 2 + + diff --git a/tests/data/files/clf/range_test1_noclamp.clf b/tests/data/files/clf/range_test1_noclamp.clf new file mode 100644 index 0000000000..46e9a67cb6 --- /dev/null +++ b/tests/data/files/clf/range_test1_noclamp.clf @@ -0,0 +1,10 @@ + + + Basic range with noClamp style + + 16 + 240 + -0.5 + 2 + + diff --git a/tests/data/files/clf/range_test2.clf b/tests/data/files/clf/range_test2.clf new file mode 100644 index 0000000000..7ae54b15c9 --- /dev/null +++ b/tests/data/files/clf/range_test2.clf @@ -0,0 +1,10 @@ + + + Range that clamps on the low side + + + 0.1 + 1e-1 + + + diff --git a/tests/data/files/clf/tabulation_support.clf b/tests/data/files/clf/tabulation_support.clf new file mode 100644 index 0000000000..c1834d5104 --- /dev/null +++ b/tests/data/files/clf/tabulation_support.clf @@ -0,0 +1,35 @@ + + + Test that tabs work as separators + + + -60 5 75 + -10 50 400 + 0 100 1200 + -40 500 -30 + -80 400 500 + -20 300 900 + -30 1500 -20 + -50 1023 100 + -10 800 300 + 100 -5 -75 + 200 -50 600 + 300 100 1200 + 40 600 30 + 380 400 400 + 20 200 1100 + 530 1500 -50 + 450 1230 500 + 610 1800 300 + 1660 -50 -100 + 1510 150 200 + 900 -40 900 + 1240 300 -50 + 980 500 600 + 820 400 800 + 1030 -100 -50 + 1050 823 200 + 1110 900 1200 + + + diff --git a/tests/data/files/xyz_to_rgb.clf b/tests/data/files/clf/xyz_to_rgb.clf similarity index 80% rename from tests/data/files/xyz_to_rgb.clf rename to tests/data/files/clf/xyz_to_rgb.clf index f45ae26478..9c99efa882 100644 --- a/tests/data/files/xyz_to_rgb.clf +++ b/tests/data/files/clf/xyz_to_rgb.clf @@ -1,16 +1,16 @@ - - Convert output-referred XYZ values to gamma-corrected RGB. + + Example with a Matrix and Lut1D XYZ to sRGB matrix - + 3.24000 -1.53700 -0.49850 -0.96930 1.87600 0.04156 0.05560 -0.20400 1.05730 - linear to 1/2.2 gamma corrected code values + linear to approx. gamma corrected code values 0.00000 0.00000 0.00000 0.28358 0.28358 0.28358 diff --git a/tests/data/files/clf_version_future.clf b/tests/data/files/clf_version_future.clf deleted file mode 100644 index c60989b1b6..0000000000 --- a/tests/data/files/clf_version_future.clf +++ /dev/null @@ -1,18 +0,0 @@ - - - - - - scene 1 exterior look - - 1.000000 1.000000 0.800000 - -0.020000 0.00000 0.150000 - 1.0500000 1.150000 1.40000 - - - 0.750000 - - - \ No newline at end of file diff --git a/tests/data/files/gamma_wrong_power.ctf b/tests/data/files/gamma_wrong_power.ctf deleted file mode 100644 index b308242354..0000000000 --- a/tests/data/files/gamma_wrong_power.ctf +++ /dev/null @@ -1,7 +0,0 @@ - - - The moncurve style requires a gamma >= 1 - - - - diff --git a/tests/data/files/indexMap_test1.clf b/tests/data/files/indexMap_test1_clfv2.clf similarity index 89% rename from tests/data/files/indexMap_test1.clf rename to tests/data/files/indexMap_test1_clfv2.clf index 3b542ecbf7..78e73ed21d 100644 --- a/tests/data/files/indexMap_test1.clf +++ b/tests/data/files/indexMap_test1_clfv2.clf @@ -1,6 +1,7 @@ Index map and CLF test + Note Index map is legal in v2 spec note the 33 is above the usual index max 64.5@4 940 @ 33 diff --git a/tests/data/files/indexMap_test2.clf b/tests/data/files/indexMap_test2_clfv2.clf similarity index 86% rename from tests/data/files/indexMap_test2.clf rename to tests/data/files/indexMap_test2_clfv2.clf index aeb2ec38ef..193964c2e5 100644 --- a/tests/data/files/indexMap_test2.clf +++ b/tests/data/files/indexMap_test2_clfv2.clf @@ -1,6 +1,7 @@ Index map and CLF test + Index map was only allowed up to CLF v2 0 30 33 diff --git a/tests/data/files/indexMap_test3.clf b/tests/data/files/indexMap_test3.ctf similarity index 92% rename from tests/data/files/indexMap_test3.clf rename to tests/data/files/indexMap_test3.ctf index ccf2bac746..48cf121cc2 100644 --- a/tests/data/files/indexMap_test3.clf +++ b/tests/data/files/indexMap_test3.ctf @@ -1,5 +1,5 @@ - + Index map and CLF test - -0.1 - 1e-1 - - - diff --git a/tests/data/files/reference_nested_2.ctf b/tests/data/files/reference_nested_2.ctf index aea001e7f9..b045d2e1d3 100644 --- a/tests/data/files/reference_nested_2.ctf +++ b/tests/data/files/reference_nested_2.ctf @@ -1,5 +1,5 @@ - + diff --git a/tests/data/files/reference_one_matrix.ctf b/tests/data/files/reference_one_matrix.ctf index fbe37a4165..de574c1399 100644 --- a/tests/data/files/reference_one_matrix.ctf +++ b/tests/data/files/reference_one_matrix.ctf @@ -1,5 +1,5 @@ - + diff --git a/tests/data/files/references_same_twice.ctf b/tests/data/files/references_same_twice.ctf index add723f42a..25b9036d02 100644 --- a/tests/data/files/references_same_twice.ctf +++ b/tests/data/files/references_same_twice.ctf @@ -1,5 +1,5 @@ - - + + diff --git a/tests/data/files/references_some_inverted.ctf b/tests/data/files/references_some_inverted.ctf index e2ac227867..8814c29048 100644 --- a/tests/data/files/references_some_inverted.ctf +++ b/tests/data/files/references_some_inverted.ctf @@ -1,12 +1,12 @@ - - + + 0 255 0.1 1.2 - + diff --git a/tests/data/files/tabulation_support.clf b/tests/data/files/tabulation_support.clf deleted file mode 100644 index 36ac6c96cc..0000000000 --- a/tests/data/files/tabulation_support.clf +++ /dev/null @@ -1,35944 +0,0 @@ - - - - - 0 0 0 - 0 0 13 - 1 0 44 - 0 1 94 - 0 1 160 - 1 0 238 - 2 0 327 - 2 0 430 - 2 1 547 - 1 1 676 - 3 1 816 - 2 1 977 - 3 0 1165 - 3 1 1382 - 3 0 1630 - 4 0 1914 - 3 0 2233 - 4 2 2580 - 4 0 2944 - 2 3 3330 - 5 0 3746 - 4 2 4088 - 5 2 4095 - 5 1 4095 - 5 1 4095 - 5 3 4095 - 6 4 4095 - 4 3 4095 - 5 3 4095 - 4 2 4095 - 0 0 4095 - 0 0 4095 - 0 0 4095 - 1 32 0 - 1 33 31 - 1 36 71 - 1 41 122 - 1 47 186 - 1 52 261 - 2 58 350 - 2 64 453 - 2 70 570 - 2 76 696 - 3 82 833 - 3 87 993 - 3 93 1179 - 3 98 1394 - 3 104 1640 - 3 109 1923 - 2 113 2239 - 4 116 2585 - 3 118 2947 - 2 119 3332 - 5 119 3747 - 3 118 4088 - 4 117 4095 - 5 114 4095 - 6 110 4095 - 6 104 4095 - 5 95 4095 - 5 83 4095 - 5 66 4095 - 4 46 4095 - 0 36 4095 - 0 36 4095 - 0 36 4095 - 1 106 0 - 1 107 52 - 1 110 107 - 1 115 168 - 1 121 239 - 2 129 320 - 2 138 413 - 2 147 516 - 2 156 630 - 2 166 752 - 3 174 884 - 3 184 1039 - 3 193 1220 - 3 203 1430 - 3 212 1672 - 3 221 1949 - 3 229 2260 - 3 235 2600 - 4 238 2956 - 2 240 3339 - 5 241 3752 - 4 240 4088 - 5 237 4095 - 6 233 4095 - 3 226 4095 - 5 216 4095 - 3 202 4095 - 5 183 4095 - 5 157 4095 - 3 129 4095 - 0 119 4095 - 0 119 4095 - 0 119 4095 - 1 217 0 - 2 218 71 - 1 220 143 - 2 224 220 - 2 230 303 - 2 237 393 - 2 246 490 - 2 255 595 - 2 264 707 - 2 274 827 - 3 284 956 - 2 294 1107 - 3 305 1282 - 3 317 1487 - 3 329 1722 - 3 340 1991 - 3 350 2293 - 2 358 2622 - 4 362 2971 - 2 365 3351 - 5 366 3761 - 4 366 4088 - 5 364 4095 - 6 360 4095 - 4 352 4095 - 5 341 4095 - 5 326 4095 - 5 305 4095 - 4 277 4095 - 3 250 4095 - 0 242 4095 - 0 242 4095 - 0 242 4095 - 2 353 0 - 2 353 86 - 2 355 174 - 2 358 265 - 2 363 359 - 2 369 458 - 2 376 562 - 3 383 672 - 3 392 786 - 2 400 906 - 3 410 1034 - 3 420 1182 - 3 431 1354 - 3 443 1553 - 4 455 1780 - 4 467 2041 - 4 477 2331 - 3 484 2647 - 4 489 2990 - 3 493 3366 - 4 496 3772 - 4 497 4087 - 5 496 4095 - 6 493 4095 - 5 486 4095 - 3 476 4095 - 5 462 4095 - 5 442 4095 - 4 417 4095 - 3 393 4095 - 0 387 4095 - 0 387 4095 - 0 387 4095 - 2 504 0 - 2 504 99 - 2 505 198 - 2 508 300 - 2 511 405 - 2 516 513 - 2 521 624 - 3 527 739 - 3 534 857 - 3 542 979 - 3 549 1108 - 3 558 1255 - 3 568 1425 - 3 579 1618 - 4 590 1839 - 4 599 2090 - 4 608 2368 - 4 615 2675 - 4 620 3014 - 3 625 3385 - 4 629 3786 - 5 632 4087 - 5 632 4095 - 5 631 4095 - 5 626 4095 - 4 618 4095 - 5 607 4095 - 5 590 4095 - 4 568 4095 - 3 548 4095 - 0 543 4095 - 0 543 4095 - 0 543 4095 - 2 663 0 - 2 663 108 - 2 664 216 - 3 666 327 - 3 669 440 - 3 672 556 - 3 676 674 - 3 681 794 - 3 686 916 - 3 692 1041 - 3 698 1171 - 3 705 1318 - 3 712 1485 - 3 720 1675 - 4 728 1889 - 4 735 2131 - 4 742 2402 - 4 749 2705 - 4 755 3039 - 4 760 3407 - 5 765 3802 - 5 769 4086 - 5 771 4095 - 6 771 4095 - 5 769 4095 - 5 764 4095 - 5 756 4095 - 5 742 4095 - 4 723 4095 - 2 707 4095 - 0 704 4095 - 0 704 4095 - 0 704 4095 - 3 824 0 - 3 824 114 - 3 825 229 - 3 826 346 - 3 828 466 - 2 830 587 - 3 833 711 - 3 836 835 - 3 839 960 - 3 843 1087 - 3 847 1218 - 3 852 1365 - 3 857 1530 - 4 862 1717 - 4 867 1926 - 3 873 2164 - 4 879 2433 - 4 885 2734 - 5 891 3066 - 5 897 3429 - 5 903 3820 - 5 907 4086 - 5 910 4095 - 6 912 4095 - 5 911 4095 - 5 909 4095 - 5 903 4095 - 4 891 4095 - 4 874 4095 - 3 861 4095 - 0 858 4095 - 0 858 4095 - 0 858 4095 - 3 980 0 - 3 980 117 - 2 980 236 - 3 981 358 - 3 982 481 - 2 984 607 - 2 985 734 - 3 987 861 - 3 989 988 - 3 991 1116 - 3 993 1248 - 3 996 1395 - 3 999 1561 - 4 1003 1747 - 4 1007 1956 - 4 1012 2195 - 3 1017 2463 - 4 1023 2763 - 5 1029 3092 - 4 1035 3452 - 5 1040 3837 - 5 1045 4085 - 4 1049 4095 - 5 1051 4095 - 6 1052 4095 - 6 1050 4095 - 5 1045 4095 - 3 1034 4095 - 4 1019 4095 - 3 1008 4095 - 0 1006 4095 - 0 1006 4095 - 0 1006 4095 - 3 1128 0 - 3 1128 119 - 3 1129 239 - 3 1129 363 - 3 1130 489 - 3 1130 617 - 3 1131 747 - 3 1133 876 - 3 1134 1006 - 4 1136 1135 - 4 1138 1269 - 4 1140 1418 - 3 1142 1584 - 4 1145 1772 - 4 1149 1983 - 4 1153 2222 - 4 1158 2491 - 4 1163 2791 - 4 1168 3118 - 4 1174 3474 - 4 1179 3853 - 4 1184 4084 - 5 1188 4095 - 5 1191 4095 - 5 1193 4095 - 5 1192 4095 - 5 1188 4095 - 5 1178 4095 - 4 1164 4095 - 2 1153 4095 - 0 1152 4095 - 0 1152 4095 - 0 1152 4095 - 3 1279 1 - 3 1279 119 - 3 1279 240 - 3 1279 365 - 3 1280 494 - 3 1281 624 - 3 1281 756 - 3 1282 888 - 3 1283 1019 - 4 1285 1151 - 3 1286 1286 - 4 1288 1436 - 4 1290 1605 - 4 1293 1794 - 4 1296 2006 - 4 1299 2247 - 4 1303 2517 - 3 1308 2817 - 3 1313 3143 - 2 1318 3496 - 4 1323 3869 - 5 1328 4083 - 4 1332 4095 - 5 1335 4095 - 5 1338 4095 - 2 1338 4095 - 5 1334 4095 - 5 1324 4095 - 4 1312 4095 - 3 1303 4095 - 0 1303 4095 - 0 1303 4095 - 0 1303 4095 - 3 1446 3 - 3 1446 119 - 3 1446 240 - 3 1446 366 - 3 1447 496 - 4 1447 629 - 3 1448 763 - 3 1449 897 - 3 1450 1031 - 3 1451 1164 - 3 1452 1301 - 3 1453 1453 - 3 1455 1623 - 3 1457 1814 - 3 1460 2028 - 4 1463 2271 - 4 1466 2544 - 4 1470 2844 - 5 1475 3169 - 3 1479 3518 - 4 1484 3885 - 4 1489 4081 - 5 1493 4095 - 5 1497 4095 - 5 1500 4095 - 6 1501 4095 - 5 1497 4095 - 5 1487 4095 - 4 1476 4095 - 2 1470 4095 - 0 1469 4095 - 0 1469 4095 - 0 1469 4095 - 4 1633 0 - 4 1633 117 - 4 1633 238 - 3 1633 365 - 3 1634 497 - 3 1634 632 - 3 1635 768 - 4 1635 905 - 3 1636 1040 - 3 1637 1175 - 3 1638 1314 - 3 1639 1468 - 4 1640 1640 - 4 1642 1833 - 2 1644 2049 - 4 1647 2295 - 4 1650 2570 - 4 1653 2872 - 4 1657 3195 - 5 1661 3540 - 5 1665 3900 - 4 1670 4080 - 4 1674 4095 - 4 1679 4095 - 5 1682 4095 - 5 1683 4095 - 5 1679 4095 - 5 1670 4095 - 2 1660 4095 - 1 1656 4095 - 0 1656 4095 - 0 1656 4095 - 0 1656 4095 - 3 1842 0 - 4 1842 115 - 4 1843 234 - 3 1843 361 - 3 1843 494 - 3 1843 632 - 3 1844 771 - 3 1844 910 - 4 1845 1047 - 4 1845 1184 - 3 1846 1324 - 4 1847 1480 - 3 1848 1654 - 3 1850 1849 - 3 1851 2068 - 4 1854 2317 - 4 1856 2595 - 3 1859 2898 - 4 1862 3220 - 4 1866 3561 - 5 1870 3912 - 5 1874 4078 - 5 1879 4095 - 5 1884 4095 - 4 1887 4095 - 5 1886 4095 - 5 1882 4095 - 4 1874 4095 - 3 1867 4095 - 1 1865 4095 - 0 1865 4095 - 0 1865 4095 - 0 1865 4095 - 4 2078 0 - 4 2078 111 - 3 2078 228 - 4 2079 355 - 3 2079 489 - 3 2079 629 - 4 2079 771 - 4 2080 912 - 4 2080 1051 - 4 2081 1190 - 2 2081 1332 - 4 2082 1490 - 4 2083 1666 - 4 2084 1864 - 4 2086 2085 - 4 2087 2338 - 4 2089 2619 - 3 2092 2924 - 5 2095 3245 - 4 2098 3581 - 5 2102 3923 - 5 2107 4075 - 4 2112 4095 - 5 2116 4095 - 5 2118 4095 - 5 2117 4095 - 4 2112 4095 - 4 2106 4095 - 2 2102 4095 - 0 2102 4095 - 0 2102 4095 - 0 2102 4095 - 0 2102 4095 - 4 2348 0 - 4 2348 105 - 3 2348 219 - 4 2348 345 - 4 2349 480 - 4 2349 622 - 4 2349 767 - 4 2350 911 - 4 2350 1052 - 4 2350 1192 - 3 2351 1336 - 4 2352 1496 - 4 2353 1675 - 4 2354 1875 - 4 2355 2100 - 4 2357 2356 - 4 2359 2642 - 4 2362 2950 - 4 2365 3270 - 5 2368 3600 - 5 2372 3927 - 5 2376 4072 - 5 2380 4095 - 5 2382 4095 - 4 2383 4095 - 3 2382 4095 - 4 2379 4095 - 3 2376 4095 - 2 2375 4095 - 0 2375 4095 - 0 2375 4095 - 0 2375 4095 - 0 2375 4095 - 4 2655 0 - 4 2655 98 - 4 2655 207 - 4 2655 331 - 4 2655 468 - 4 2655 613 - 4 2655 761 - 3 2656 907 - 3 2656 1050 - 4 2656 1192 - 4 2657 1338 - 3 2658 1500 - 4 2658 1682 - 4 2659 1884 - 4 2660 2113 - 4 2662 2373 - 4 2664 2663 - 4 2666 2974 - 4 2668 3290 - 5 2670 3613 - 4 2673 3916 - 5 2675 4068 - 4 2677 4095 - 5 2679 4095 - 3 2679 4095 - 4 2678 4095 - 4 2677 4095 - 3 2677 4095 - 0 2677 4095 - 0 2677 4095 - 0 2677 4095 - 0 2677 4095 - 0 2677 4095 - 4 2983 0 - 4 2983 87 - 4 2983 189 - 4 2983 312 - 4 2983 450 - 4 2983 598 - 4 2983 749 - 4 2983 898 - 4 2984 1043 - 3 2984 1187 - 3 2984 1334 - 4 2984 1498 - 3 2985 1682 - 3 2985 1886 - 4 2986 2118 - 4 2986 2383 - 4 2987 2676 - 4 2988 2988 - 4 2989 3301 - 2 2990 3613 - 4 2991 3898 - 4 2991 4064 - 4 2991 4095 - 4 2991 4095 - 4 2991 4095 - 4 2991 4095 - 3 2991 4095 - 0 2991 4095 - 0 2991 4095 - 0 2991 4095 - 0 2991 4095 - 0 2991 4095 - 0 2991 4095 - 4 3301 0 - 3 3301 71 - 4 3301 165 - 3 3301 286 - 3 3301 426 - 4 3301 577 - 4 3301 732 - 4 3301 883 - 4 3301 1029 - 4 3301 1174 - 3 3301 1323 - 3 3300 1488 - 4 3300 1673 - 4 3300 1879 - 4 3300 2113 - 4 3300 2382 - 3 3300 2679 - 4 3300 2992 - 4 3299 3300 - 3 3299 3601 - 3 3298 3874 - 3 3297 4060 - 4 3296 4095 - 3 3296 4095 - 3 3295 4095 - 2 3295 4095 - 0 3295 4095 - 0 3295 4095 - 0 3295 4095 - 0 3295 4095 - 0 3295 4095 - 0 3295 4095 - 0 3295 4095 - 3 3594 0 - 3 3594 51 - 3 3594 136 - 3 3594 257 - 3 3593 399 - 3 3593 554 - 3 3593 712 - 3 3593 866 - 3 3593 1013 - 2 3593 1159 - 3 3593 1309 - 3 3593 1475 - 3 3593 1661 - 3 3592 1869 - 3 3592 2104 - 2 3592 2376 - 3 3591 2677 - 3 3591 2991 - 3 3590 3295 - 3 3589 3590 - 2 3589 3855 - 2 3588 4058 - 1 3588 4095 - 1 3588 4095 - 0 3588 4095 - 0 3588 4095 - 0 3588 4095 - 0 3588 4095 - 0 3588 4095 - 0 3588 4095 - 0 3588 4095 - 0 3588 4095 - 0 3588 4095 - 1 3852 0 - 1 3852 37 - 1 3852 120 - 1 3852 242 - 1 3852 387 - 1 3852 544 - 1 3852 704 - 1 3852 859 - 1 3852 1006 - 1 3852 1152 - 1 3852 1303 - 1 3852 1469 - 1 3852 1656 - 1 3852 1865 - 1 3852 2102 - 0 3852 2375 - 0 3852 2677 - 0 3852 2991 - 0 3852 3295 - 0 3852 3588 - 0 3852 3852 - 0 3852 4057 - 0 3852 4095 - 0 3852 4095 - 0 3852 4095 - 0 3852 4095 - 0 3852 4095 - 0 3852 4095 - 0 3852 4095 - 0 3852 4095 - 0 3852 4095 - 0 3852 4095 - 0 3852 4095 - 0 4057 0 - 0 4057 36 - 0 4057 119 - 0 4057 242 - 0 4057 387 - 0 4057 543 - 0 4057 704 - 0 4057 858 - 0 4057 1006 - 0 4057 1152 - 0 4057 1303 - 0 4057 1469 - 0 4057 1656 - 0 4057 1865 - 0 4057 2102 - 0 4057 2375 - 0 4057 2677 - 0 4057 2991 - 0 4057 3295 - 0 4057 3588 - 0 4057 3852 - 0 4057 4057 - 0 4057 4095 - 0 4057 4095 - 0 4057 4095 - 0 4057 4095 - 0 4057 4095 - 0 4057 4095 - 0 4057 4095 - 0 4057 4095 - 0 4057 4095 - 0 4057 4095 - 0 4057 4095 - 0 4095 0 - 0 4095 36 - 0 4095 119 - 0 4095 242 - 0 4095 387 - 0 4095 543 - 0 4095 704 - 0 4095 858 - 0 4095 1006 - 0 4095 1152 - 0 4095 1303 - 0 4095 1469 - 0 4095 1656 - 0 4095 1865 - 0 4095 2102 - 0 4095 2375 - 0 4095 2677 - 0 4095 2991 - 0 4095 3295 - 0 4095 3588 - 0 4095 3852 - 0 4095 4057 - 0 4095 4095 - 0 4095 4095 - 0 4095 4095 - 0 4095 4095 - 0 4095 4095 - 0 4095 4095 - 0 4095 4095 - 0 4095 4095 - 0 4095 4095 - 0 4095 4095 - 0 4095 4095 - 0 4095 0 - 0 4095 36 - 0 4095 119 - 0 4095 242 - 0 4095 387 - 0 4095 543 - 0 4095 704 - 0 4095 858 - 0 4095 1006 - 0 4095 1152 - 0 4095 1303 - 0 4095 1469 - 0 4095 1656 - 0 4095 1865 - 0 4095 2102 - 0 4095 2375 - 0 4095 2677 - 0 4095 2991 - 0 4095 3295 - 0 4095 3588 - 0 4095 3852 - 0 4095 4057 - 0 4095 4095 - 0 4095 4095 - 0 4095 4095 - 0 4095 4095 - 0 4095 4095 - 0 4095 4095 - 0 4095 4095 - 0 4095 4095 - 0 4095 4095 - 0 4095 4095 - 0 4095 4095 - 0 4095 0 - 0 4095 36 - 0 4095 119 - 0 4095 242 - 0 4095 387 - 0 4095 543 - 0 4095 704 - 0 4095 858 - 0 4095 1006 - 0 4095 1152 - 0 4095 1303 - 0 4095 1469 - 0 4095 1656 - 0 4095 1865 - 0 4095 2102 - 0 4095 2375 - 0 4095 2677 - 0 4095 2991 - 0 4095 3295 - 0 4095 3588 - 0 4095 3852 - 0 4095 4057 - 0 4095 4095 - 0 4095 4095 - 0 4095 4095 - 0 4095 4095 - 0 4095 4095 - 0 4095 4095 - 0 4095 4095 - 0 4095 4095 - 0 4095 4095 - 0 4095 4095 - 0 4095 4095 - 0 4095 0 - 0 4095 36 - 0 4095 119 - 0 4095 242 - 0 4095 387 - 0 4095 543 - 0 4095 704 - 0 4095 858 - 0 4095 1006 - 0 4095 1152 - 0 4095 1303 - 0 4095 1469 - 0 4095 1656 - 0 4095 1865 - 0 4095 2102 - 0 4095 2375 - 0 4095 2677 - 0 4095 2991 - 0 4095 3295 - 0 4095 3588 - 0 4095 3852 - 0 4095 4057 - 0 4095 4095 - 0 4095 4095 - 0 4095 4095 - 0 4095 4095 - 0 4095 4095 - 0 4095 4095 - 0 4095 4095 - 0 4095 4095 - 0 4095 4095 - 0 4095 4095 - 0 4095 4095 - 0 4095 0 - 0 4095 36 - 0 4095 119 - 0 4095 242 - 0 4095 387 - 0 4095 543 - 0 4095 704 - 0 4095 858 - 0 4095 1006 - 0 4095 1152 - 0 4095 1303 - 0 4095 1469 - 0 4095 1656 - 0 4095 1865 - 0 4095 2102 - 0 4095 2375 - 0 4095 2677 - 0 4095 2991 - 0 4095 3295 - 0 4095 3588 - 0 4095 3852 - 0 4095 4057 - 0 4095 4095 - 0 4095 4095 - 0 4095 4095 - 0 4095 4095 - 0 4095 4095 - 0 4095 4095 - 0 4095 4095 - 0 4095 4095 - 0 4095 4095 - 0 4095 4095 - 0 4095 4095 - 0 4095 0 - 0 4095 36 - 0 4095 119 - 0 4095 242 - 0 4095 387 - 0 4095 543 - 0 4095 704 - 0 4095 858 - 0 4095 1006 - 0 4095 1152 - 0 4095 1303 - 0 4095 1469 - 0 4095 1656 - 0 4095 1865 - 0 4095 2102 - 0 4095 2375 - 0 4095 2677 - 0 4095 2991 - 0 4095 3295 - 0 4095 3588 - 0 4095 3852 - 0 4095 4057 - 0 4095 4095 - 0 4095 4095 - 0 4095 4095 - 0 4095 4095 - 0 4095 4095 - 0 4095 4095 - 0 4095 4095 - 0 4095 4095 - 0 4095 4095 - 0 4095 4095 - 0 4095 4095 - 0 4095 0 - 0 4095 36 - 0 4095 119 - 0 4095 242 - 0 4095 387 - 0 4095 543 - 0 4095 704 - 0 4095 858 - 0 4095 1006 - 0 4095 1152 - 0 4095 1303 - 0 4095 1469 - 0 4095 1656 - 0 4095 1865 - 0 4095 2102 - 0 4095 2375 - 0 4095 2677 - 0 4095 2991 - 0 4095 3295 - 0 4095 3588 - 0 4095 3852 - 0 4095 4057 - 0 4095 4095 - 0 4095 4095 - 0 4095 4095 - 0 4095 4095 - 0 4095 4095 - 0 4095 4095 - 0 4095 4095 - 0 4095 4095 - 0 4095 4095 - 0 4095 4095 - 0 4095 4095 - 0 4095 0 - 0 4095 36 - 0 4095 119 - 0 4095 242 - 0 4095 387 - 0 4095 543 - 0 4095 704 - 0 4095 858 - 0 4095 1006 - 0 4095 1152 - 0 4095 1303 - 0 4095 1469 - 0 4095 1656 - 0 4095 1865 - 0 4095 2102 - 0 4095 2375 - 0 4095 2677 - 0 4095 2991 - 0 4095 3295 - 0 4095 3588 - 0 4095 3852 - 0 4095 4057 - 0 4095 4095 - 0 4095 4095 - 0 4095 4095 - 0 4095 4095 - 0 4095 4095 - 0 4095 4095 - 0 4095 4095 - 0 4095 4095 - 0 4095 4095 - 0 4095 4095 - 0 4095 4095 - 0 4095 0 - 0 4095 36 - 0 4095 119 - 0 4095 242 - 0 4095 387 - 0 4095 543 - 0 4095 704 - 0 4095 858 - 0 4095 1006 - 0 4095 1152 - 0 4095 1303 - 0 4095 1469 - 0 4095 1656 - 0 4095 1865 - 0 4095 2102 - 0 4095 2375 - 0 4095 2677 - 0 4095 2991 - 0 4095 3295 - 0 4095 3588 - 0 4095 3852 - 0 4095 4057 - 0 4095 4095 - 0 4095 4095 - 0 4095 4095 - 0 4095 4095 - 0 4095 4095 - 0 4095 4095 - 0 4095 4095 - 0 4095 4095 - 0 4095 4095 - 0 4095 4095 - 0 4095 4095 - 0 4095 0 - 0 4095 36 - 0 4095 119 - 0 4095 242 - 0 4095 387 - 0 4095 543 - 0 4095 704 - 0 4095 858 - 0 4095 1006 - 0 4095 1152 - 0 4095 1303 - 0 4095 1469 - 0 4095 1656 - 0 4095 1865 - 0 4095 2102 - 0 4095 2375 - 0 4095 2677 - 0 4095 2991 - 0 4095 3295 - 0 4095 3588 - 0 4095 3852 - 0 4095 4057 - 0 4095 4095 - 0 4095 4095 - 0 4095 4095 - 0 4095 4095 - 0 4095 4095 - 0 4095 4095 - 0 4095 4095 - 0 4095 4095 - 0 4095 4095 - 0 4095 4095 - 0 4095 4095 - 0 4095 0 - 0 4095 36 - 0 4095 119 - 0 4095 242 - 0 4095 387 - 0 4095 543 - 0 4095 704 - 0 4095 858 - 0 4095 1006 - 0 4095 1152 - 0 4095 1303 - 0 4095 1469 - 0 4095 1656 - 0 4095 1865 - 0 4095 2102 - 0 4095 2375 - 0 4095 2677 - 0 4095 2991 - 0 4095 3295 - 0 4095 3588 - 0 4095 3852 - 0 4095 4057 - 0 4095 4095 - 0 4095 4095 - 0 4095 4095 - 0 4095 4095 - 0 4095 4095 - 0 4095 4095 - 0 4095 4095 - 0 4095 4095 - 0 4095 4095 - 0 4095 4095 - 0 4095 4095 - 19 0 0 - 22 0 21 - 27 0 54 - 34 0 104 - 42 0 169 - 49 0 246 - 55 0 334 - 62 0 437 - 68 1 554 - 75 1 682 - 81 1 821 - 86 1 982 - 92 1 1169 - 98 1 1385 - 103 2 1633 - 108 2 1917 - 113 2 2235 - 116 2 2582 - 118 2 2945 - 119 1 3331 - 119 0 3746 - 119 2 4088 - 117 3 4095 - 114 2 4095 - 110 1 4095 - 104 1 4095 - 96 1 4095 - 84 3 4095 - 67 3 4095 - 46 1 4095 - 36 0 4095 - 36 0 4095 - 36 0 4095 - 34 35 1 - 35 36 35 - 38 39 76 - 43 43 128 - 48 48 192 - 53 53 268 - 59 59 356 - 65 65 460 - 71 71 576 - 77 77 702 - 82 82 838 - 88 88 998 - 93 93 1183 - 99 99 1397 - 104 104 1643 - 109 109 1925 - 113 113 2241 - 117 116 2586 - 118 118 2948 - 119 119 3333 - 119 119 3748 - 119 118 4088 - 117 117 4095 - 114 114 4095 - 110 110 4095 - 104 104 4095 - 96 95 4095 - 84 83 4095 - 67 66 4095 - 46 46 4095 - 36 36 4095 - 36 36 4095 - 36 36 4095 - 53 109 0 - 53 109 53 - 55 112 109 - 57 117 172 - 60 123 244 - 64 131 325 - 69 139 418 - 73 148 521 - 78 158 634 - 83 166 756 - 87 175 889 - 92 184 1043 - 96 194 1224 - 101 203 1433 - 106 213 1675 - 110 221 1952 - 114 229 2262 - 117 235 2601 - 119 238 2957 - 119 240 3340 - 119 241 3752 - 118 240 4088 - 117 237 4095 - 114 233 4095 - 110 226 4095 - 104 216 4095 - 95 202 4095 - 83 183 4095 - 66 157 4095 - 45 129 4095 - 36 119 4095 - 36 119 4095 - 36 119 4095 - 71 219 0 - 72 220 71 - 72 222 145 - 74 226 222 - 76 232 306 - 78 239 396 - 81 247 493 - 84 256 598 - 87 265 711 - 90 275 830 - 94 285 959 - 97 295 1110 - 101 306 1285 - 105 318 1489 - 109 329 1724 - 112 341 1993 - 115 350 2294 - 118 358 2623 - 119 362 2971 - 119 365 3351 - 119 366 3761 - 118 366 4088 - 117 364 4095 - 114 360 4095 - 110 352 4095 - 103 341 4095 - 95 326 4095 - 83 305 4095 - 66 277 4095 - 45 250 4095 - 36 242 4095 - 36 242 4095 - 36 242 4095 - 87 354 1 - 87 355 87 - 87 357 175 - 88 360 266 - 89 364 361 - 91 370 460 - 93 377 564 - 94 384 674 - 96 393 788 - 99 401 908 - 101 411 1036 - 103 421 1184 - 106 432 1356 - 109 444 1555 - 112 456 1782 - 115 467 2042 - 117 477 2332 - 118 484 2648 - 119 489 2991 - 119 493 3367 - 119 496 3773 - 118 497 4087 - 116 496 4095 - 113 493 4095 - 109 486 4095 - 103 476 4095 - 94 462 4095 - 82 442 4095 - 65 417 4095 - 44 393 4095 - 36 387 4095 - 36 387 4095 - 36 387 4095 - 99 505 1 - 99 505 99 - 99 507 199 - 100 509 301 - 100 512 406 - 101 517 514 - 102 522 626 - 103 528 740 - 105 535 859 - 106 542 981 - 108 550 1110 - 109 559 1257 - 111 569 1426 - 113 579 1620 - 115 590 1841 - 117 600 2091 - 118 608 2369 - 119 615 2676 - 119 620 3014 - 119 625 3386 - 119 629 3787 - 118 632 4087 - 116 632 4095 - 113 631 4095 - 108 626 4095 - 102 618 4095 - 94 607 4095 - 81 590 4095 - 64 568 4095 - 43 548 4095 - 36 543 4095 - 36 543 4095 - 36 543 4095 - 108 664 1 - 108 664 108 - 108 665 217 - 108 667 328 - 109 670 441 - 109 673 557 - 110 677 675 - 111 681 795 - 111 687 917 - 112 692 1042 - 113 698 1172 - 114 705 1319 - 115 713 1486 - 116 720 1676 - 117 728 1890 - 118 736 2131 - 119 742 2402 - 119 749 2705 - 119 755 3040 - 119 760 3407 - 118 765 3803 - 117 769 4086 - 115 771 4095 - 112 771 4095 - 108 769 4095 - 101 764 4095 - 92 756 4095 - 80 742 4095 - 63 723 4095 - 43 707 4095 - 36 704 4095 - 36 704 4095 - 36 704 4095 - 114 825 2 - 114 825 114 - 114 826 229 - 114 827 347 - 114 828 466 - 115 831 588 - 115 833 711 - 115 837 835 - 116 840 961 - 116 844 1087 - 117 848 1218 - 117 852 1365 - 118 857 1531 - 118 862 1717 - 119 868 1927 - 119 873 2165 - 119 879 2434 - 119 885 2735 - 119 891 3066 - 119 897 3429 - 118 903 3820 - 117 907 4086 - 114 910 4095 - 111 912 4095 - 106 911 4095 - 100 909 4095 - 91 902 4095 - 78 891 4095 - 61 874 4095 - 42 861 4095 - 36 858 4095 - 36 858 4095 - 36 858 4095 - 118 980 2 - 118 980 118 - 118 981 236 - 118 982 358 - 118 983 482 - 118 984 607 - 118 985 734 - 118 987 861 - 118 989 989 - 118 991 1117 - 119 994 1249 - 119 996 1396 - 119 999 1561 - 119 1003 1747 - 119 1007 1957 - 119 1012 2195 - 119 1017 2464 - 119 1023 2763 - 119 1029 3093 - 118 1035 3452 - 117 1040 3837 - 116 1045 4085 - 113 1049 4095 - 110 1051 4095 - 105 1052 4095 - 99 1050 4095 - 90 1045 4095 - 77 1034 4095 - 59 1019 4095 - 41 1008 4095 - 36 1006 4095 - 36 1006 4095 - 36 1006 4095 - 119 1128 0 - 119 1129 119 - 119 1129 239 - 119 1129 363 - 119 1130 489 - 119 1131 617 - 119 1132 747 - 119 1133 876 - 119 1134 1006 - 119 1136 1136 - 119 1138 1269 - 119 1140 1418 - 119 1143 1585 - 119 1146 1772 - 119 1149 1983 - 119 1153 2222 - 119 1158 2491 - 119 1163 2791 - 118 1168 3118 - 117 1174 3474 - 116 1179 3854 - 114 1184 4084 - 112 1188 4095 - 108 1191 4095 - 103 1193 4095 - 97 1192 4095 - 88 1188 4095 - 75 1178 4095 - 57 1164 4095 - 39 1153 4095 - 36 1152 4095 - 36 1152 4095 - 36 1152 4095 - 119 1279 1 - 119 1279 119 - 119 1279 240 - 119 1280 365 - 119 1280 494 - 119 1281 624 - 119 1281 756 - 119 1282 888 - 119 1284 1019 - 119 1285 1151 - 119 1286 1286 - 119 1288 1436 - 119 1290 1605 - 119 1293 1794 - 119 1296 2006 - 119 1299 2247 - 118 1303 2518 - 118 1308 2817 - 117 1313 3143 - 116 1318 3496 - 115 1323 3870 - 113 1328 4083 - 110 1332 4095 - 107 1335 4095 - 102 1338 4095 - 95 1338 4095 - 85 1334 4095 - 72 1324 4095 - 55 1312 4095 - 38 1303 4095 - 36 1303 4095 - 36 1303 4095 - 36 1303 4095 - 119 1446 2 - 119 1446 119 - 119 1446 240 - 119 1446 366 - 119 1447 496 - 119 1447 629 - 119 1448 763 - 119 1449 897 - 119 1450 1031 - 118 1451 1164 - 118 1452 1301 - 118 1453 1453 - 118 1455 1623 - 118 1457 1814 - 118 1460 2029 - 118 1463 2272 - 117 1466 2544 - 116 1470 2845 - 116 1475 3169 - 114 1479 3518 - 113 1484 3885 - 111 1489 4081 - 108 1493 4095 - 104 1497 4095 - 99 1500 4095 - 92 1501 4095 - 82 1497 4095 - 69 1487 4095 - 52 1476 4095 - 37 1470 4095 - 36 1469 4095 - 36 1469 4095 - 36 1469 4095 - 117 1633 0 - 117 1633 117 - 117 1633 238 - 117 1633 365 - 117 1634 497 - 117 1634 632 - 117 1635 768 - 117 1635 905 - 117 1636 1040 - 117 1637 1175 - 117 1638 1314 - 117 1639 1468 - 117 1640 1640 - 116 1642 1833 - 116 1644 2049 - 116 1647 2295 - 115 1650 2570 - 114 1653 2872 - 113 1657 3195 - 112 1661 3540 - 111 1665 3900 - 108 1670 4080 - 105 1674 4095 - 101 1679 4095 - 96 1682 4095 - 89 1683 4095 - 78 1679 4095 - 65 1670 4095 - 48 1660 4095 - 37 1656 4095 - 36 1656 4095 - 36 1656 4095 - 36 1656 4095 - 115 1843 0 - 115 1843 115 - 115 1843 234 - 115 1843 361 - 115 1843 494 - 115 1843 632 - 115 1844 771 - 115 1844 910 - 115 1845 1047 - 114 1846 1184 - 114 1846 1324 - 114 1847 1480 - 114 1848 1654 - 114 1850 1849 - 113 1852 2069 - 113 1854 2317 - 112 1856 2595 - 111 1859 2898 - 110 1862 3220 - 109 1866 3561 - 107 1870 3912 - 105 1874 4078 - 101 1879 4095 - 97 1884 4095 - 92 1887 4095 - 84 1886 4095 - 74 1882 4095 - 60 1874 4095 - 44 1867 4095 - 36 1865 4095 - 36 1865 4095 - 36 1865 4095 - 36 1865 4095 - 111 2078 3 - 111 2078 111 - 111 2078 228 - 111 2079 355 - 111 2079 489 - 111 2079 629 - 111 2079 771 - 111 2080 912 - 111 2080 1051 - 111 2081 1190 - 110 2081 1332 - 110 2082 1490 - 110 2083 1666 - 110 2084 1864 - 109 2086 2086 - 109 2087 2338 - 108 2089 2619 - 107 2092 2924 - 106 2095 3245 - 104 2098 3581 - 102 2102 3923 - 100 2107 4075 - 96 2112 4095 - 92 2116 4095 - 86 2118 4095 - 78 2117 4095 - 67 2112 4095 - 53 2106 4095 - 40 2102 4095 - 36 2102 4095 - 36 2102 4095 - 36 2102 4095 - 36 2102 4095 - 106 2348 3 - 106 2348 106 - 106 2348 219 - 106 2349 345 - 105 2349 480 - 105 2349 622 - 105 2349 767 - 105 2350 911 - 105 2350 1052 - 105 2351 1192 - 105 2351 1336 - 104 2352 1496 - 104 2353 1675 - 104 2354 1875 - 103 2355 2100 - 103 2357 2356 - 102 2359 2642 - 101 2362 2950 - 100 2365 3270 - 98 2368 3600 - 96 2372 3927 - 93 2376 4072 - 90 2380 4095 - 85 2382 4095 - 78 2383 4095 - 70 2382 4095 - 59 2379 4095 - 46 2376 4095 - 37 2375 4095 - 36 2375 4095 - 36 2375 4095 - 36 2375 4095 - 36 2375 4095 - 98 2655 2 - 98 2655 98 - 98 2655 207 - 98 2655 331 - 98 2655 468 - 98 2655 613 - 98 2655 761 - 97 2656 907 - 97 2656 1050 - 97 2657 1192 - 97 2657 1338 - 97 2658 1500 - 96 2658 1682 - 96 2659 1884 - 95 2660 2113 - 95 2662 2374 - 94 2664 2663 - 93 2666 2974 - 91 2668 3291 - 90 2670 3613 - 87 2673 3916 - 84 2675 4068 - 80 2677 4095 - 75 2679 4095 - 68 2679 4095 - 60 2678 4095 - 49 2677 4095 - 39 2677 4095 - 36 2677 4095 - 36 2677 4095 - 36 2677 4095 - 36 2677 4095 - 36 2677 4095 - 87 2983 2 - 87 2983 87 - 87 2983 189 - 87 2983 312 - 87 2983 450 - 87 2983 598 - 86 2983 749 - 86 2983 898 - 86 2984 1043 - 86 2984 1187 - 86 2984 1334 - 85 2984 1498 - 85 2985 1682 - 85 2985 1886 - 84 2986 2118 - 83 2986 2383 - 82 2987 2676 - 81 2988 2988 - 80 2989 3301 - 77 2990 3613 - 75 2991 3898 - 72 2991 4064 - 67 2991 4095 - 62 2991 4095 - 55 2991 4095 - 47 2991 4095 - 40 2991 4095 - 36 2991 4095 - 36 2991 4095 - 36 2991 4095 - 36 2991 4095 - 36 2991 4095 - 36 2991 4095 - 71 3301 2 - 71 3301 71 - 71 3301 164 - 71 3301 286 - 71 3301 425 - 71 3301 577 - 71 3301 732 - 71 3301 883 - 70 3301 1029 - 70 3301 1174 - 70 3301 1323 - 69 3300 1488 - 69 3300 1673 - 69 3300 1879 - 68 3300 2113 - 67 3300 2382 - 66 3300 2679 - 65 3300 2992 - 63 3299 3300 - 61 3299 3601 - 59 3298 3874 - 55 3297 4060 - 51 3296 4095 - 47 3296 4095 - 42 3295 4095 - 38 3295 4095 - 36 3295 4095 - 36 3295 4095 - 36 3295 4095 - 36 3295 4095 - 36 3295 4095 - 36 3295 4095 - 36 3295 4095 - 51 3594 2 - 51 3594 51 - 51 3594 136 - 51 3594 257 - 51 3593 399 - 50 3593 554 - 50 3593 712 - 50 3593 866 - 50 3593 1013 - 50 3593 1159 - 50 3593 1309 - 49 3593 1475 - 49 3593 1661 - 49 3592 1869 - 48 3592 2104 - 47 3592 2376 - 46 3591 2677 - 45 3591 2991 - 44 3590 3295 - 42 3589 3590 - 41 3589 3855 - 39 3588 4058 - 37 3588 4095 - 37 3588 4095 - 36 3588 4095 - 36 3588 4095 - 36 3588 4095 - 36 3588 4095 - 36 3588 4095 - 36 3588 4095 - 36 3588 4095 - 36 3588 4095 - 36 3588 4095 - 37 3852 0 - 37 3852 37 - 37 3852 120 - 37 3852 242 - 37 3852 387 - 37 3852 544 - 37 3852 704 - 37 3852 859 - 37 3852 1006 - 37 3852 1152 - 37 3852 1303 - 37 3852 1469 - 37 3852 1656 - 36 3852 1865 - 36 3852 2102 - 36 3852 2375 - 36 3852 2677 - 36 3852 2991 - 36 3852 3295 - 36 3852 3588 - 36 3852 3852 - 36 3852 4057 - 36 3852 4095 - 36 3852 4095 - 36 3852 4095 - 36 3852 4095 - 36 3852 4095 - 36 3852 4095 - 36 3852 4095 - 36 3852 4095 - 36 3852 4095 - 36 3852 4095 - 36 3852 4095 - 36 4057 0 - 36 4057 36 - 36 4057 119 - 36 4057 242 - 36 4057 387 - 36 4057 543 - 36 4057 704 - 36 4057 858 - 36 4057 1006 - 36 4057 1152 - 36 4057 1303 - 36 4057 1469 - 36 4057 1656 - 36 4057 1865 - 36 4057 2102 - 36 4057 2375 - 36 4057 2677 - 36 4057 2991 - 36 4057 3295 - 36 4057 3588 - 36 4057 3852 - 36 4057 4057 - 36 4057 4095 - 36 4057 4095 - 36 4057 4095 - 36 4057 4095 - 36 4057 4095 - 36 4057 4095 - 36 4057 4095 - 36 4057 4095 - 36 4057 4095 - 36 4057 4095 - 36 4057 4095 - 36 4095 0 - 36 4095 36 - 36 4095 119 - 36 4095 242 - 36 4095 387 - 36 4095 543 - 36 4095 704 - 36 4095 858 - 36 4095 1006 - 36 4095 1152 - 36 4095 1303 - 36 4095 1469 - 36 4095 1656 - 36 4095 1865 - 36 4095 2102 - 36 4095 2375 - 36 4095 2677 - 36 4095 2991 - 36 4095 3295 - 36 4095 3588 - 36 4095 3852 - 36 4095 4057 - 36 4095 4095 - 36 4095 4095 - 36 4095 4095 - 36 4095 4095 - 36 4095 4095 - 36 4095 4095 - 36 4095 4095 - 36 4095 4095 - 36 4095 4095 - 36 4095 4095 - 36 4095 4095 - 36 4095 0 - 36 4095 36 - 36 4095 119 - 36 4095 242 - 36 4095 387 - 36 4095 543 - 36 4095 704 - 36 4095 858 - 36 4095 1006 - 36 4095 1152 - 36 4095 1303 - 36 4095 1469 - 36 4095 1656 - 36 4095 1865 - 36 4095 2102 - 36 4095 2375 - 36 4095 2677 - 36 4095 2991 - 36 4095 3295 - 36 4095 3588 - 36 4095 3852 - 36 4095 4057 - 36 4095 4095 - 36 4095 4095 - 36 4095 4095 - 36 4095 4095 - 36 4095 4095 - 36 4095 4095 - 36 4095 4095 - 36 4095 4095 - 36 4095 4095 - 36 4095 4095 - 36 4095 4095 - 36 4095 0 - 36 4095 36 - 36 4095 119 - 36 4095 242 - 36 4095 387 - 36 4095 543 - 36 4095 704 - 36 4095 858 - 36 4095 1006 - 36 4095 1152 - 36 4095 1303 - 36 4095 1469 - 36 4095 1656 - 36 4095 1865 - 36 4095 2102 - 36 4095 2375 - 36 4095 2677 - 36 4095 2991 - 36 4095 3295 - 36 4095 3588 - 36 4095 3852 - 36 4095 4057 - 36 4095 4095 - 36 4095 4095 - 36 4095 4095 - 36 4095 4095 - 36 4095 4095 - 36 4095 4095 - 36 4095 4095 - 36 4095 4095 - 36 4095 4095 - 36 4095 4095 - 36 4095 4095 - 36 4095 0 - 36 4095 36 - 36 4095 119 - 36 4095 242 - 36 4095 387 - 36 4095 543 - 36 4095 704 - 36 4095 858 - 36 4095 1006 - 36 4095 1152 - 36 4095 1303 - 36 4095 1469 - 36 4095 1656 - 36 4095 1865 - 36 4095 2102 - 36 4095 2375 - 36 4095 2677 - 36 4095 2991 - 36 4095 3295 - 36 4095 3588 - 36 4095 3852 - 36 4095 4057 - 36 4095 4095 - 36 4095 4095 - 36 4095 4095 - 36 4095 4095 - 36 4095 4095 - 36 4095 4095 - 36 4095 4095 - 36 4095 4095 - 36 4095 4095 - 36 4095 4095 - 36 4095 4095 - 36 4095 0 - 36 4095 36 - 36 4095 119 - 36 4095 242 - 36 4095 387 - 36 4095 543 - 36 4095 704 - 36 4095 858 - 36 4095 1006 - 36 4095 1152 - 36 4095 1303 - 36 4095 1469 - 36 4095 1656 - 36 4095 1865 - 36 4095 2102 - 36 4095 2375 - 36 4095 2677 - 36 4095 2991 - 36 4095 3295 - 36 4095 3588 - 36 4095 3852 - 36 4095 4057 - 36 4095 4095 - 36 4095 4095 - 36 4095 4095 - 36 4095 4095 - 36 4095 4095 - 36 4095 4095 - 36 4095 4095 - 36 4095 4095 - 36 4095 4095 - 36 4095 4095 - 36 4095 4095 - 36 4095 0 - 36 4095 36 - 36 4095 119 - 36 4095 242 - 36 4095 387 - 36 4095 543 - 36 4095 704 - 36 4095 858 - 36 4095 1006 - 36 4095 1152 - 36 4095 1303 - 36 4095 1469 - 36 4095 1656 - 36 4095 1865 - 36 4095 2102 - 36 4095 2375 - 36 4095 2677 - 36 4095 2991 - 36 4095 3295 - 36 4095 3588 - 36 4095 3852 - 36 4095 4057 - 36 4095 4095 - 36 4095 4095 - 36 4095 4095 - 36 4095 4095 - 36 4095 4095 - 36 4095 4095 - 36 4095 4095 - 36 4095 4095 - 36 4095 4095 - 36 4095 4095 - 36 4095 4095 - 36 4095 0 - 36 4095 36 - 36 4095 119 - 36 4095 242 - 36 4095 387 - 36 4095 543 - 36 4095 704 - 36 4095 858 - 36 4095 1006 - 36 4095 1152 - 36 4095 1303 - 36 4095 1469 - 36 4095 1656 - 36 4095 1865 - 36 4095 2102 - 36 4095 2375 - 36 4095 2677 - 36 4095 2991 - 36 4095 3295 - 36 4095 3588 - 36 4095 3852 - 36 4095 4057 - 36 4095 4095 - 36 4095 4095 - 36 4095 4095 - 36 4095 4095 - 36 4095 4095 - 36 4095 4095 - 36 4095 4095 - 36 4095 4095 - 36 4095 4095 - 36 4095 4095 - 36 4095 4095 - 36 4095 0 - 36 4095 36 - 36 4095 119 - 36 4095 242 - 36 4095 387 - 36 4095 543 - 36 4095 704 - 36 4095 858 - 36 4095 1006 - 36 4095 1152 - 36 4095 1303 - 36 4095 1469 - 36 4095 1656 - 36 4095 1865 - 36 4095 2102 - 36 4095 2375 - 36 4095 2677 - 36 4095 2991 - 36 4095 3295 - 36 4095 3588 - 36 4095 3852 - 36 4095 4057 - 36 4095 4095 - 36 4095 4095 - 36 4095 4095 - 36 4095 4095 - 36 4095 4095 - 36 4095 4095 - 36 4095 4095 - 36 4095 4095 - 36 4095 4095 - 36 4095 4095 - 36 4095 4095 - 36 4095 0 - 36 4095 36 - 36 4095 119 - 36 4095 242 - 36 4095 387 - 36 4095 543 - 36 4095 704 - 36 4095 858 - 36 4095 1006 - 36 4095 1152 - 36 4095 1303 - 36 4095 1469 - 36 4095 1656 - 36 4095 1865 - 36 4095 2102 - 36 4095 2375 - 36 4095 2677 - 36 4095 2991 - 36 4095 3295 - 36 4095 3588 - 36 4095 3852 - 36 4095 4057 - 36 4095 4095 - 36 4095 4095 - 36 4095 4095 - 36 4095 4095 - 36 4095 4095 - 36 4095 4095 - 36 4095 4095 - 36 4095 4095 - 36 4095 4095 - 36 4095 4095 - 36 4095 4095 - 36 4095 0 - 36 4095 36 - 36 4095 119 - 36 4095 242 - 36 4095 387 - 36 4095 543 - 36 4095 704 - 36 4095 858 - 36 4095 1006 - 36 4095 1152 - 36 4095 1303 - 36 4095 1469 - 36 4095 1656 - 36 4095 1865 - 36 4095 2102 - 36 4095 2375 - 36 4095 2677 - 36 4095 2991 - 36 4095 3295 - 36 4095 3588 - 36 4095 3852 - 36 4095 4057 - 36 4095 4095 - 36 4095 4095 - 36 4095 4095 - 36 4095 4095 - 36 4095 4095 - 36 4095 4095 - 36 4095 4095 - 36 4095 4095 - 36 4095 4095 - 36 4095 4095 - 36 4095 4095 - 36 4095 0 - 36 4095 36 - 36 4095 119 - 36 4095 242 - 36 4095 387 - 36 4095 543 - 36 4095 704 - 36 4095 858 - 36 4095 1006 - 36 4095 1152 - 36 4095 1303 - 36 4095 1469 - 36 4095 1656 - 36 4095 1865 - 36 4095 2102 - 36 4095 2375 - 36 4095 2677 - 36 4095 2991 - 36 4095 3295 - 36 4095 3588 - 36 4095 3852 - 36 4095 4057 - 36 4095 4095 - 36 4095 4095 - 36 4095 4095 - 36 4095 4095 - 36 4095 4095 - 36 4095 4095 - 36 4095 4095 - 36 4095 4095 - 36 4095 4095 - 36 4095 4095 - 36 4095 4095 - 69 0 0 - 71 0 34 - 77 0 76 - 86 1 128 - 96 1 192 - 106 0 267 - 118 1 356 - 130 1 459 - 142 0 576 - 154 1 702 - 165 0 838 - 176 1 997 - 187 2 1183 - 198 2 1397 - 208 2 1643 - 218 2 1925 - 227 1 2241 - 234 1 2586 - 238 1 2948 - 240 2 3333 - 241 2 3747 - 240 3 4088 - 238 3 4095 - 233 1 4095 - 226 4 4095 - 216 0 4095 - 203 0 4095 - 183 2 4095 - 158 1 4095 - 130 2 4095 - 119 0 4095 - 119 0 4095 - 119 0 4095 - 85 43 1 - 86 43 43 - 91 45 90 - 97 49 145 - 105 52 210 - 114 57 287 - 124 62 377 - 136 68 480 - 147 73 595 - 158 79 720 - 168 84 855 - 178 89 1012 - 189 94 1196 - 199 99 1408 - 210 104 1653 - 219 109 1933 - 228 113 2248 - 234 117 2591 - 238 118 2951 - 240 119 3335 - 241 119 3749 - 240 118 4088 - 238 117 4095 - 233 114 4095 - 226 110 4095 - 216 104 4095 - 203 95 4095 - 183 83 4095 - 157 66 4095 - 130 45 4095 - 119 36 4095 - 119 36 4095 - 119 36 4095 - 114 116 1 - 115 117 57 - 118 120 117 - 122 124 183 - 128 129 257 - 135 136 340 - 143 144 433 - 152 153 537 - 160 161 650 - 169 170 771 - 177 178 902 - 186 186 1056 - 195 195 1235 - 204 204 1444 - 213 214 1684 - 222 222 1959 - 230 230 2268 - 235 235 2605 - 238 238 2959 - 240 240 3342 - 241 241 3754 - 240 240 4088 - 237 237 4095 - 233 233 4095 - 226 226 4095 - 216 216 4095 - 202 202 4095 - 183 183 4095 - 157 157 4095 - 129 129 4095 - 119 119 4095 - 119 119 4095 - 119 119 4095 - 148 226 1 - 148 226 74 - 150 229 149 - 152 232 229 - 156 238 314 - 161 244 405 - 166 252 503 - 172 260 609 - 178 269 721 - 184 278 841 - 190 287 969 - 197 297 1119 - 204 308 1294 - 211 319 1497 - 219 331 1731 - 226 341 1999 - 232 351 2299 - 237 358 2626 - 239 362 2974 - 240 365 3353 - 241 366 3762 - 240 366 4088 - 237 364 4095 - 232 359 4095 - 225 352 4095 - 215 341 4095 - 202 326 4095 - 182 305 4095 - 156 277 4095 - 129 250 4095 - 119 242 4095 - 119 242 4095 - 119 242 4095 - 177 360 1 - 177 360 88 - 178 362 178 - 179 365 270 - 182 369 366 - 184 375 466 - 188 381 571 - 191 388 681 - 195 396 795 - 199 405 915 - 204 413 1044 - 209 423 1192 - 214 434 1363 - 220 445 1561 - 225 457 1788 - 231 468 2047 - 235 478 2336 - 238 485 2651 - 240 490 2993 - 240 493 3369 - 240 496 3774 - 239 497 4087 - 236 496 4095 - 232 492 4095 - 225 486 4095 - 215 476 4095 - 201 462 4095 - 181 442 4095 - 155 417 4095 - 128 393 4095 - 119 387 4095 - 119 387 4095 - 119 387 4095 - 200 509 1 - 200 509 100 - 200 510 200 - 201 513 303 - 203 516 409 - 204 520 518 - 206 526 630 - 209 531 745 - 211 538 863 - 214 545 986 - 217 553 1115 - 220 561 1262 - 224 571 1431 - 228 581 1624 - 231 591 1845 - 235 601 2094 - 237 609 2371 - 239 615 2678 - 240 621 3016 - 241 626 3387 - 240 629 3788 - 239 632 4087 - 236 632 4095 - 231 631 4095 - 223 626 4095 - 213 618 4095 - 199 607 4095 - 180 590 4095 - 154 568 4095 - 127 548 4095 - 119 543 4095 - 119 543 4095 - 119 543 4095 - 217 667 2 - 217 667 108 - 218 668 218 - 218 670 329 - 219 672 443 - 220 675 559 - 221 679 677 - 223 684 798 - 224 689 920 - 226 694 1045 - 228 700 1175 - 230 707 1322 - 232 714 1489 - 234 722 1679 - 236 729 1892 - 238 736 2134 - 239 743 2404 - 240 749 2707 - 240 755 3041 - 240 761 3408 - 240 765 3804 - 238 769 4086 - 235 771 4095 - 230 771 4095 - 222 769 4095 - 212 764 4095 - 198 756 4095 - 178 742 4095 - 152 723 4095 - 126 707 4095 - 119 704 4095 - 119 704 4095 - 119 704 4095 - 230 827 2 - 230 827 114 - 230 828 230 - 230 829 347 - 230 830 467 - 231 832 589 - 232 835 712 - 232 838 837 - 233 841 962 - 234 845 1089 - 235 849 1220 - 236 853 1367 - 237 858 1533 - 238 863 1719 - 239 868 1928 - 239 874 2166 - 240 879 2435 - 240 885 2736 - 240 892 3067 - 240 897 3430 - 239 903 3821 - 237 907 4086 - 233 911 4095 - 228 912 4095 - 220 911 4095 - 210 909 4095 - 195 902 4095 - 175 891 4095 - 150 874 4095 - 125 861 4095 - 119 858 4095 - 119 858 4095 - 119 858 4095 - 237 981 2 - 237 982 118 - 237 982 237 - 237 983 358 - 237 984 482 - 237 985 608 - 237 986 735 - 238 988 862 - 238 990 989 - 238 992 1118 - 239 994 1249 - 239 997 1397 - 239 1000 1562 - 240 1004 1748 - 240 1008 1958 - 240 1013 2196 - 240 1018 2465 - 240 1023 2765 - 240 1029 3094 - 239 1035 3453 - 238 1040 3838 - 235 1045 4085 - 231 1049 4095 - 226 1051 4095 - 218 1052 4095 - 207 1050 4095 - 193 1045 4095 - 173 1034 4095 - 147 1019 4095 - 124 1008 4095 - 119 1006 4095 - 119 1006 4095 - 119 1006 4095 - 239 1129 3 - 239 1129 119 - 239 1129 239 - 239 1130 363 - 240 1131 489 - 240 1131 618 - 240 1132 747 - 240 1134 877 - 240 1135 1006 - 240 1137 1136 - 240 1138 1270 - 240 1140 1419 - 240 1143 1585 - 240 1146 1773 - 240 1150 1984 - 240 1154 2223 - 240 1158 2492 - 240 1163 2792 - 239 1169 3119 - 238 1174 3475 - 236 1180 3854 - 233 1184 4084 - 229 1189 4095 - 223 1191 4095 - 215 1193 4095 - 205 1192 4095 - 190 1188 4095 - 169 1177 4095 - 144 1163 4095 - 123 1153 4095 - 119 1152 4095 - 119 1152 4095 - 119 1152 4095 - 240 1280 2 - 240 1280 119 - 240 1280 240 - 240 1280 366 - 240 1281 494 - 240 1281 624 - 241 1282 756 - 241 1283 888 - 241 1284 1020 - 241 1285 1151 - 241 1287 1287 - 240 1289 1437 - 240 1291 1605 - 240 1293 1794 - 240 1296 2007 - 240 1300 2248 - 240 1304 2518 - 239 1308 2818 - 238 1313 3144 - 236 1318 3497 - 234 1323 3870 - 231 1328 4083 - 227 1332 4095 - 221 1335 4095 - 212 1338 4095 - 201 1338 4095 - 186 1334 4095 - 166 1324 4095 - 141 1311 4095 - 121 1303 4095 - 119 1303 4095 - 119 1303 4095 - 119 1303 4095 - 240 1446 1 - 240 1447 119 - 240 1447 240 - 240 1447 366 - 240 1447 496 - 240 1448 629 - 240 1448 763 - 240 1449 898 - 240 1450 1031 - 240 1451 1164 - 240 1452 1301 - 240 1454 1454 - 239 1456 1624 - 239 1458 1815 - 239 1460 2029 - 238 1463 2272 - 238 1467 2545 - 237 1470 2845 - 235 1475 3170 - 234 1479 3519 - 231 1484 3886 - 228 1489 4081 - 223 1493 4095 - 217 1497 4095 - 208 1500 4095 - 197 1501 4095 - 181 1497 4095 - 161 1487 4095 - 137 1476 4095 - 120 1470 4095 - 119 1469 4095 - 119 1469 4095 - 119 1469 4095 - 238 1633 2 - 238 1633 117 - 238 1634 238 - 238 1634 365 - 238 1634 497 - 238 1634 632 - 238 1635 768 - 238 1636 905 - 238 1636 1040 - 238 1637 1175 - 237 1638 1314 - 237 1639 1468 - 237 1641 1640 - 237 1642 1833 - 236 1645 2050 - 235 1647 2296 - 235 1650 2570 - 233 1653 2872 - 232 1657 3195 - 230 1661 3540 - 227 1666 3900 - 223 1670 4080 - 218 1674 4095 - 212 1679 4095 - 203 1682 4095 - 191 1683 4095 - 175 1678 4095 - 155 1670 4095 - 133 1660 4095 - 120 1656 4095 - 119 1656 4095 - 119 1656 4095 - 119 1656 4095 - 234 1843 3 - 234 1843 115 - 234 1843 234 - 234 1843 361 - 234 1843 494 - 234 1844 632 - 234 1844 771 - 234 1845 910 - 234 1845 1047 - 234 1846 1184 - 233 1847 1324 - 233 1847 1480 - 233 1849 1655 - 232 1850 1850 - 232 1852 2069 - 231 1854 2318 - 230 1856 2595 - 228 1859 2899 - 227 1862 3221 - 224 1866 3561 - 221 1870 3912 - 217 1874 4078 - 212 1879 4095 - 205 1884 4095 - 196 1887 4095 - 184 1886 4095 - 168 1882 4095 - 148 1874 4095 - 128 1867 4095 - 119 1865 4095 - 119 1865 4095 - 119 1865 4095 - 119 1865 4095 - 228 2079 1 - 228 2079 111 - 228 2079 228 - 228 2079 355 - 228 2079 489 - 228 2079 629 - 228 2080 771 - 228 2080 912 - 228 2080 1051 - 227 2081 1190 - 227 2082 1332 - 227 2082 1490 - 226 2083 1666 - 226 2084 1864 - 225 2086 2086 - 224 2087 2338 - 223 2089 2619 - 221 2092 2924 - 219 2095 3245 - 217 2098 3581 - 214 2103 3923 - 210 2107 4075 - 204 2112 4095 - 197 2116 4095 - 187 2118 4095 - 175 2117 4095 - 158 2112 4095 - 139 2106 4095 - 123 2102 4095 - 119 2102 4095 - 119 2102 4095 - 119 2102 4095 - 119 2102 4095 - 219 2349 2 - 219 2349 105 - 219 2349 219 - 219 2349 345 - 219 2349 480 - 219 2349 622 - 219 2349 767 - 218 2350 911 - 218 2350 1052 - 218 2351 1192 - 218 2351 1336 - 217 2352 1496 - 217 2353 1675 - 216 2354 1875 - 215 2355 2100 - 214 2357 2357 - 213 2359 2642 - 212 2362 2950 - 209 2365 3270 - 207 2368 3600 - 203 2372 3927 - 199 2376 4072 - 193 2380 4095 - 185 2382 4095 - 175 2383 4095 - 162 2382 4095 - 147 2379 4095 - 130 2376 4095 - 120 2375 4095 - 119 2375 4095 - 119 2375 4095 - 119 2375 4095 - 119 2375 4095 - 207 2655 1 - 207 2655 98 - 206 2655 206 - 206 2655 331 - 206 2655 468 - 206 2655 613 - 206 2656 761 - 206 2656 907 - 206 2656 1050 - 205 2657 1192 - 205 2657 1338 - 205 2658 1500 - 204 2659 1682 - 203 2660 1884 - 203 2661 2113 - 201 2662 2374 - 200 2664 2663 - 198 2666 2974 - 196 2668 3291 - 193 2670 3613 - 189 2673 3916 - 184 2675 4068 - 178 2677 4095 - 170 2679 4095 - 160 2679 4095 - 148 2678 4095 - 134 2677 4095 - 122 2677 4095 - 119 2677 4095 - 119 2677 4095 - 119 2677 4095 - 119 2677 4095 - 119 2677 4095 - 189 2983 3 - 189 2983 87 - 189 2983 189 - 189 2983 312 - 189 2983 450 - 188 2983 598 - 188 2983 749 - 188 2984 898 - 188 2984 1043 - 187 2984 1187 - 187 2984 1334 - 187 2985 1498 - 186 2985 1682 - 185 2985 1886 - 184 2986 2118 - 183 2986 2383 - 182 2987 2676 - 180 2988 2988 - 177 2989 3301 - 174 2990 3613 - 170 2991 3897 - 165 2991 4064 - 159 2991 4095 - 151 2991 4095 - 142 2991 4095 - 132 2991 4095 - 123 2991 4095 - 119 2991 4095 - 119 2991 4095 - 119 2991 4095 - 119 2991 4095 - 119 2991 4095 - 119 2991 4095 - 164 3301 2 - 164 3301 71 - 164 3301 164 - 164 3301 285 - 164 3301 425 - 164 3301 577 - 164 3301 732 - 164 3301 883 - 163 3301 1029 - 163 3301 1174 - 163 3301 1323 - 162 3300 1488 - 162 3300 1673 - 161 3300 1879 - 160 3300 2113 - 159 3300 2381 - 157 3300 2679 - 155 3300 2992 - 153 3299 3300 - 150 3299 3601 - 146 3298 3874 - 142 3297 4060 - 137 3296 4095 - 131 3296 4095 - 125 3295 4095 - 121 3295 4095 - 119 3295 4095 - 119 3295 4095 - 119 3295 4095 - 119 3295 4095 - 119 3295 4095 - 119 3295 4095 - 119 3295 4095 - 136 3594 1 - 136 3594 51 - 136 3593 136 - 136 3593 257 - 136 3593 399 - 136 3593 554 - 135 3593 712 - 135 3593 866 - 135 3593 1013 - 135 3593 1159 - 135 3593 1308 - 134 3593 1475 - 134 3592 1661 - 133 3592 1869 - 132 3592 2104 - 132 3592 2376 - 130 3591 2677 - 129 3591 2991 - 128 3590 3295 - 126 3589 3590 - 124 3589 3855 - 122 3588 4058 - 120 3588 4095 - 120 3588 4095 - 119 3588 4095 - 119 3588 4095 - 119 3588 4095 - 119 3588 4095 - 119 3588 4095 - 119 3588 4095 - 119 3588 4095 - 119 3588 4095 - 119 3588 4095 - 120 3852 0 - 120 3852 37 - 120 3852 120 - 120 3852 242 - 120 3852 387 - 120 3852 544 - 120 3852 704 - 120 3852 859 - 120 3852 1006 - 120 3852 1152 - 120 3852 1303 - 120 3852 1469 - 120 3852 1656 - 120 3852 1865 - 119 3852 2102 - 119 3852 2375 - 119 3852 2677 - 119 3852 2991 - 119 3852 3295 - 119 3852 3588 - 119 3852 3852 - 119 3852 4057 - 119 3852 4095 - 119 3852 4095 - 119 3852 4095 - 119 3852 4095 - 119 3852 4095 - 119 3852 4095 - 119 3852 4095 - 119 3852 4095 - 119 3852 4095 - 119 3852 4095 - 119 3852 4095 - 119 4057 0 - 119 4057 36 - 119 4057 119 - 119 4057 242 - 119 4057 387 - 119 4057 543 - 119 4057 704 - 119 4057 858 - 119 4057 1006 - 119 4057 1152 - 119 4057 1303 - 119 4057 1469 - 119 4057 1656 - 119 4057 1865 - 119 4057 2102 - 119 4057 2375 - 119 4057 2677 - 119 4057 2991 - 119 4057 3295 - 119 4057 3588 - 119 4057 3852 - 119 4057 4057 - 119 4057 4095 - 119 4057 4095 - 119 4057 4095 - 119 4057 4095 - 119 4057 4095 - 119 4057 4095 - 119 4057 4095 - 119 4057 4095 - 119 4057 4095 - 119 4057 4095 - 119 4057 4095 - 119 4095 0 - 119 4095 36 - 119 4095 119 - 119 4095 242 - 119 4095 387 - 119 4095 543 - 119 4095 704 - 119 4095 858 - 119 4095 1006 - 119 4095 1152 - 119 4095 1303 - 119 4095 1469 - 119 4095 1656 - 119 4095 1865 - 119 4095 2102 - 119 4095 2375 - 119 4095 2677 - 119 4095 2991 - 119 4095 3295 - 119 4095 3588 - 119 4095 3852 - 119 4095 4057 - 119 4095 4095 - 119 4095 4095 - 119 4095 4095 - 119 4095 4095 - 119 4095 4095 - 119 4095 4095 - 119 4095 4095 - 119 4095 4095 - 119 4095 4095 - 119 4095 4095 - 119 4095 4095 - 119 4095 0 - 119 4095 36 - 119 4095 119 - 119 4095 242 - 119 4095 387 - 119 4095 543 - 119 4095 704 - 119 4095 858 - 119 4095 1006 - 119 4095 1152 - 119 4095 1303 - 119 4095 1469 - 119 4095 1656 - 119 4095 1865 - 119 4095 2102 - 119 4095 2375 - 119 4095 2677 - 119 4095 2991 - 119 4095 3295 - 119 4095 3588 - 119 4095 3852 - 119 4095 4057 - 119 4095 4095 - 119 4095 4095 - 119 4095 4095 - 119 4095 4095 - 119 4095 4095 - 119 4095 4095 - 119 4095 4095 - 119 4095 4095 - 119 4095 4095 - 119 4095 4095 - 119 4095 4095 - 119 4095 0 - 119 4095 36 - 119 4095 119 - 119 4095 242 - 119 4095 387 - 119 4095 543 - 119 4095 704 - 119 4095 858 - 119 4095 1006 - 119 4095 1152 - 119 4095 1303 - 119 4095 1469 - 119 4095 1656 - 119 4095 1865 - 119 4095 2102 - 119 4095 2375 - 119 4095 2677 - 119 4095 2991 - 119 4095 3295 - 119 4095 3588 - 119 4095 3852 - 119 4095 4057 - 119 4095 4095 - 119 4095 4095 - 119 4095 4095 - 119 4095 4095 - 119 4095 4095 - 119 4095 4095 - 119 4095 4095 - 119 4095 4095 - 119 4095 4095 - 119 4095 4095 - 119 4095 4095 - 119 4095 0 - 119 4095 36 - 119 4095 119 - 119 4095 242 - 119 4095 387 - 119 4095 543 - 119 4095 704 - 119 4095 858 - 119 4095 1006 - 119 4095 1152 - 119 4095 1303 - 119 4095 1469 - 119 4095 1656 - 119 4095 1865 - 119 4095 2102 - 119 4095 2375 - 119 4095 2677 - 119 4095 2991 - 119 4095 3295 - 119 4095 3588 - 119 4095 3852 - 119 4095 4057 - 119 4095 4095 - 119 4095 4095 - 119 4095 4095 - 119 4095 4095 - 119 4095 4095 - 119 4095 4095 - 119 4095 4095 - 119 4095 4095 - 119 4095 4095 - 119 4095 4095 - 119 4095 4095 - 119 4095 0 - 119 4095 36 - 119 4095 119 - 119 4095 242 - 119 4095 387 - 119 4095 543 - 119 4095 704 - 119 4095 858 - 119 4095 1006 - 119 4095 1152 - 119 4095 1303 - 119 4095 1469 - 119 4095 1656 - 119 4095 1865 - 119 4095 2102 - 119 4095 2375 - 119 4095 2677 - 119 4095 2991 - 119 4095 3295 - 119 4095 3588 - 119 4095 3852 - 119 4095 4057 - 119 4095 4095 - 119 4095 4095 - 119 4095 4095 - 119 4095 4095 - 119 4095 4095 - 119 4095 4095 - 119 4095 4095 - 119 4095 4095 - 119 4095 4095 - 119 4095 4095 - 119 4095 4095 - 119 4095 0 - 119 4095 36 - 119 4095 119 - 119 4095 242 - 119 4095 387 - 119 4095 543 - 119 4095 704 - 119 4095 858 - 119 4095 1006 - 119 4095 1152 - 119 4095 1303 - 119 4095 1469 - 119 4095 1656 - 119 4095 1865 - 119 4095 2102 - 119 4095 2375 - 119 4095 2677 - 119 4095 2991 - 119 4095 3295 - 119 4095 3588 - 119 4095 3852 - 119 4095 4057 - 119 4095 4095 - 119 4095 4095 - 119 4095 4095 - 119 4095 4095 - 119 4095 4095 - 119 4095 4095 - 119 4095 4095 - 119 4095 4095 - 119 4095 4095 - 119 4095 4095 - 119 4095 4095 - 119 4095 0 - 119 4095 36 - 119 4095 119 - 119 4095 242 - 119 4095 387 - 119 4095 543 - 119 4095 704 - 119 4095 858 - 119 4095 1006 - 119 4095 1152 - 119 4095 1303 - 119 4095 1469 - 119 4095 1656 - 119 4095 1865 - 119 4095 2102 - 119 4095 2375 - 119 4095 2677 - 119 4095 2991 - 119 4095 3295 - 119 4095 3588 - 119 4095 3852 - 119 4095 4057 - 119 4095 4095 - 119 4095 4095 - 119 4095 4095 - 119 4095 4095 - 119 4095 4095 - 119 4095 4095 - 119 4095 4095 - 119 4095 4095 - 119 4095 4095 - 119 4095 4095 - 119 4095 4095 - 119 4095 0 - 119 4095 36 - 119 4095 119 - 119 4095 242 - 119 4095 387 - 119 4095 543 - 119 4095 704 - 119 4095 858 - 119 4095 1006 - 119 4095 1152 - 119 4095 1303 - 119 4095 1469 - 119 4095 1656 - 119 4095 1865 - 119 4095 2102 - 119 4095 2375 - 119 4095 2677 - 119 4095 2991 - 119 4095 3295 - 119 4095 3588 - 119 4095 3852 - 119 4095 4057 - 119 4095 4095 - 119 4095 4095 - 119 4095 4095 - 119 4095 4095 - 119 4095 4095 - 119 4095 4095 - 119 4095 4095 - 119 4095 4095 - 119 4095 4095 - 119 4095 4095 - 119 4095 4095 - 119 4095 0 - 119 4095 36 - 119 4095 119 - 119 4095 242 - 119 4095 387 - 119 4095 543 - 119 4095 704 - 119 4095 858 - 119 4095 1006 - 119 4095 1152 - 119 4095 1303 - 119 4095 1469 - 119 4095 1656 - 119 4095 1865 - 119 4095 2102 - 119 4095 2375 - 119 4095 2677 - 119 4095 2991 - 119 4095 3295 - 119 4095 3588 - 119 4095 3852 - 119 4095 4057 - 119 4095 4095 - 119 4095 4095 - 119 4095 4095 - 119 4095 4095 - 119 4095 4095 - 119 4095 4095 - 119 4095 4095 - 119 4095 4095 - 119 4095 4095 - 119 4095 4095 - 119 4095 4095 - 119 4095 0 - 119 4095 36 - 119 4095 119 - 119 4095 242 - 119 4095 387 - 119 4095 543 - 119 4095 704 - 119 4095 858 - 119 4095 1006 - 119 4095 1152 - 119 4095 1303 - 119 4095 1469 - 119 4095 1656 - 119 4095 1865 - 119 4095 2102 - 119 4095 2375 - 119 4095 2677 - 119 4095 2991 - 119 4095 3295 - 119 4095 3588 - 119 4095 3852 - 119 4095 4057 - 119 4095 4095 - 119 4095 4095 - 119 4095 4095 - 119 4095 4095 - 119 4095 4095 - 119 4095 4095 - 119 4095 4095 - 119 4095 4095 - 119 4095 4095 - 119 4095 4095 - 119 4095 4095 - 119 4095 0 - 119 4095 36 - 119 4095 119 - 119 4095 242 - 119 4095 387 - 119 4095 543 - 119 4095 704 - 119 4095 858 - 119 4095 1006 - 119 4095 1152 - 119 4095 1303 - 119 4095 1469 - 119 4095 1656 - 119 4095 1865 - 119 4095 2102 - 119 4095 2375 - 119 4095 2677 - 119 4095 2991 - 119 4095 3295 - 119 4095 3588 - 119 4095 3852 - 119 4095 4057 - 119 4095 4095 - 119 4095 4095 - 119 4095 4095 - 119 4095 4095 - 119 4095 4095 - 119 4095 4095 - 119 4095 4095 - 119 4095 4095 - 119 4095 4095 - 119 4095 4095 - 119 4095 4095 - 141 0 0 - 143 1 47 - 148 1 97 - 156 1 155 - 167 1 222 - 180 0 300 - 195 1 392 - 211 1 495 - 227 1 609 - 242 0 733 - 257 0 867 - 272 1 1023 - 287 2 1206 - 302 1 1417 - 318 1 1661 - 332 2 1940 - 345 2 2253 - 355 1 2594 - 361 0 2953 - 364 2 3337 - 366 1 3750 - 366 2 4088 - 364 3 4095 - 360 0 4095 - 353 2 4095 - 342 3 4095 - 327 1 4095 - 306 1 4095 - 278 3 4095 - 251 3 4095 - 242 0 4095 - 242 0 4095 - 242 0 4095 - 156 51 1 - 157 52 51 - 161 53 106 - 168 56 167 - 178 59 237 - 190 63 317 - 204 68 409 - 218 72 513 - 233 77 626 - 247 82 749 - 261 86 881 - 275 91 1036 - 290 96 1218 - 304 101 1428 - 319 105 1670 - 333 110 1947 - 345 114 2259 - 355 117 2599 - 361 118 2955 - 364 119 3339 - 366 119 3752 - 366 118 4088 - 364 117 4095 - 360 114 4095 - 353 110 4095 - 342 104 4095 - 327 95 4095 - 306 83 4095 - 278 66 4095 - 251 45 4095 - 242 36 4095 - 242 36 4095 - 242 36 4095 - 191 128 1 - 192 129 63 - 195 131 129 - 201 135 200 - 208 139 277 - 217 145 363 - 228 152 458 - 239 160 562 - 250 167 674 - 262 174 794 - 273 182 925 - 285 190 1077 - 298 198 1254 - 311 207 1461 - 324 215 1699 - 337 223 1972 - 348 230 2278 - 356 236 2612 - 361 239 2964 - 364 240 3345 - 366 241 3756 - 366 240 4088 - 364 237 4095 - 360 233 4095 - 352 226 4095 - 341 216 4095 - 326 202 4095 - 305 183 4095 - 278 157 4095 - 250 129 4095 - 242 119 4095 - 242 119 4095 - 242 119 4095 - 234 237 1 - 235 237 77 - 237 239 157 - 240 243 240 - 245 247 327 - 251 253 420 - 258 260 520 - 266 267 626 - 274 275 739 - 282 284 858 - 291 292 987 - 301 302 1136 - 311 312 1310 - 322 322 1512 - 332 333 1744 - 343 343 2010 - 352 352 2308 - 358 359 2632 - 362 362 2978 - 365 365 3356 - 366 366 3765 - 366 366 4087 - 364 364 4095 - 359 359 4095 - 352 352 4095 - 341 341 4095 - 326 326 4095 - 304 304 4095 - 277 277 4095 - 250 250 4095 - 242 242 4095 - 242 242 4095 - 242 242 4095 - 273 368 1 - 273 369 90 - 275 370 182 - 277 373 276 - 280 377 374 - 284 382 476 - 288 388 582 - 293 395 692 - 299 402 808 - 305 410 928 - 311 418 1056 - 318 427 1204 - 325 437 1375 - 334 448 1572 - 342 459 1798 - 349 470 2055 - 356 479 2342 - 360 485 2655 - 363 490 2997 - 365 494 3372 - 366 496 3776 - 366 497 4087 - 363 496 4095 - 359 492 4095 - 351 486 4095 - 340 476 4095 - 325 462 4095 - 303 442 4095 - 276 416 4095 - 249 393 4095 - 242 387 4095 - 242 387 4095 - 242 387 4095 - 305 515 1 - 305 516 101 - 306 517 203 - 307 519 307 - 309 522 414 - 312 526 524 - 315 531 637 - 318 537 753 - 321 543 872 - 325 550 994 - 330 557 1123 - 334 565 1271 - 340 574 1440 - 345 583 1632 - 351 593 1852 - 356 602 2100 - 360 609 2376 - 362 616 2682 - 365 621 3019 - 366 626 3390 - 366 629 3790 - 365 632 4087 - 363 632 4095 - 358 630 4095 - 350 626 4095 - 338 618 4095 - 323 607 4095 - 302 590 4095 - 274 568 4095 - 249 548 4095 - 242 543 4095 - 242 543 4095 - 242 543 4095 - 330 672 1 - 330 672 109 - 331 673 219 - 331 675 331 - 333 677 446 - 334 680 563 - 336 684 682 - 338 688 803 - 340 693 925 - 343 698 1051 - 345 703 1181 - 348 710 1328 - 351 716 1495 - 354 723 1684 - 357 731 1897 - 360 737 2137 - 362 744 2407 - 364 750 2710 - 365 756 3044 - 366 761 3411 - 366 766 3806 - 365 769 4086 - 361 771 4095 - 356 771 4095 - 348 769 4095 - 337 764 4095 - 321 756 4095 - 299 742 4095 - 272 723 4095 - 248 707 4095 - 242 704 4095 - 242 704 4095 - 242 704 4095 - 348 830 1 - 348 830 115 - 348 831 231 - 349 832 349 - 349 833 469 - 350 835 591 - 351 838 715 - 352 841 840 - 353 844 965 - 354 847 1092 - 356 851 1223 - 357 855 1370 - 359 860 1536 - 360 864 1722 - 362 869 1931 - 363 875 2169 - 364 880 2438 - 365 886 2739 - 366 892 3070 - 366 898 3432 - 365 903 3822 - 364 907 4085 - 360 911 4095 - 354 912 4095 - 346 911 4095 - 335 909 4095 - 319 902 4095 - 297 890 4095 - 270 874 4095 - 247 861 4095 - 242 858 4095 - 242 858 4095 - 242 858 4095 - 358 983 1 - 358 984 118 - 359 984 237 - 359 985 359 - 359 985 483 - 359 987 609 - 360 988 736 - 360 990 863 - 361 991 991 - 361 993 1119 - 362 996 1251 - 362 998 1398 - 363 1001 1564 - 364 1005 1750 - 364 1009 1960 - 365 1013 2198 - 366 1019 2467 - 366 1024 2767 - 366 1030 3096 - 366 1035 3455 - 365 1041 3839 - 362 1046 4085 - 358 1049 4095 - 352 1051 4095 - 344 1052 4095 - 332 1050 4095 - 316 1045 4095 - 294 1034 4095 - 268 1019 4095 - 246 1008 4095 - 242 1006 4095 - 242 1006 4095 - 242 1006 4095 - 363 1130 2 - 363 1130 119 - 363 1131 240 - 363 1131 363 - 363 1132 490 - 364 1133 618 - 364 1134 748 - 364 1135 878 - 364 1136 1007 - 364 1138 1137 - 365 1139 1271 - 365 1141 1420 - 365 1144 1587 - 366 1147 1774 - 366 1150 1985 - 366 1154 2225 - 366 1159 2494 - 366 1164 2794 - 366 1169 3121 - 365 1174 3476 - 363 1180 3855 - 360 1185 4084 - 356 1189 4095 - 350 1191 4095 - 341 1193 4095 - 329 1192 4095 - 313 1188 4095 - 291 1177 4095 - 265 1163 4095 - 244 1153 4095 - 242 1152 4095 - 242 1152 4095 - 242 1152 4095 - 366 1280 1 - 366 1281 119 - 366 1281 240 - 366 1281 366 - 366 1282 494 - 366 1282 625 - 366 1283 757 - 366 1284 889 - 366 1285 1020 - 366 1286 1152 - 366 1288 1287 - 366 1289 1438 - 366 1291 1607 - 366 1294 1795 - 366 1297 2008 - 366 1300 2249 - 366 1304 2520 - 365 1309 2820 - 365 1313 3145 - 363 1319 3498 - 361 1324 3871 - 358 1328 4083 - 353 1333 4095 - 346 1335 4095 - 337 1338 4095 - 325 1338 4095 - 309 1334 4095 - 287 1324 4095 - 261 1311 4095 - 243 1303 4095 - 242 1303 4095 - 242 1303 4095 - 242 1303 4095 - 366 1447 0 - 366 1447 119 - 366 1447 240 - 366 1448 366 - 366 1448 496 - 366 1449 629 - 366 1449 764 - 366 1450 898 - 366 1451 1031 - 366 1452 1165 - 366 1453 1302 - 366 1454 1454 - 366 1456 1625 - 366 1458 1815 - 365 1461 2030 - 365 1464 2273 - 364 1467 2546 - 364 1471 2846 - 362 1475 3171 - 361 1480 3519 - 358 1485 3886 - 354 1489 4081 - 349 1493 4095 - 342 1497 4095 - 333 1500 4095 - 321 1501 4095 - 304 1497 4095 - 282 1487 4095 - 258 1476 4095 - 243 1470 4095 - 242 1469 4095 - 242 1469 4095 - 242 1469 4095 - 365 1634 1 - 365 1634 117 - 365 1634 238 - 365 1634 365 - 365 1635 497 - 365 1635 632 - 365 1636 769 - 365 1636 905 - 365 1637 1040 - 364 1638 1176 - 364 1639 1314 - 364 1640 1469 - 364 1641 1641 - 363 1643 1834 - 363 1645 2050 - 362 1647 2296 - 361 1650 2571 - 360 1654 2873 - 359 1657 3196 - 357 1661 3541 - 354 1666 3900 - 349 1670 4080 - 344 1674 4095 - 337 1679 4095 - 327 1682 4095 - 314 1683 4095 - 297 1678 4095 - 276 1670 4095 - 253 1660 4095 - 242 1656 4095 - 242 1656 4095 - 242 1656 4095 - 242 1656 4095 - 361 1843 2 - 361 1843 115 - 361 1843 234 - 361 1844 361 - 361 1844 494 - 361 1844 632 - 361 1845 771 - 361 1845 910 - 361 1846 1047 - 360 1846 1184 - 360 1847 1325 - 360 1848 1481 - 360 1849 1655 - 359 1850 1850 - 358 1852 2069 - 358 1854 2318 - 356 1857 2596 - 355 1859 2899 - 353 1863 3221 - 351 1866 3562 - 347 1870 3912 - 343 1874 4077 - 337 1879 4095 - 330 1884 4095 - 320 1887 4095 - 306 1886 4095 - 289 1882 4095 - 268 1874 4095 - 249 1867 4095 - 242 1865 4095 - 242 1865 4095 - 242 1865 4095 - 242 1865 4095 - 355 2079 0 - 355 2079 111 - 355 2079 228 - 355 2079 355 - 355 2079 489 - 355 2080 629 - 355 2080 771 - 354 2080 912 - 354 2081 1051 - 354 2081 1190 - 354 2082 1332 - 353 2083 1490 - 353 2084 1667 - 352 2085 1864 - 351 2086 2086 - 350 2088 2338 - 349 2090 2620 - 347 2092 2925 - 345 2095 3246 - 342 2099 3582 - 339 2103 3924 - 334 2107 4075 - 328 2112 4095 - 320 2116 4095 - 310 2118 4095 - 296 2117 4095 - 279 2112 4095 - 260 2106 4095 - 245 2102 4095 - 242 2102 4095 - 242 2102 4095 - 242 2102 4095 - 242 2102 4095 - 345 2349 3 - 345 2349 105 - 345 2349 219 - 345 2349 345 - 345 2349 480 - 344 2349 622 - 344 2350 767 - 344 2350 911 - 344 2351 1052 - 344 2351 1192 - 343 2352 1336 - 343 2352 1496 - 342 2353 1675 - 342 2354 1875 - 341 2356 2100 - 340 2357 2357 - 338 2359 2643 - 337 2362 2951 - 334 2365 3270 - 331 2368 3601 - 328 2372 3927 - 323 2376 4072 - 316 2380 4095 - 308 2382 4095 - 297 2383 4095 - 283 2382 4095 - 267 2379 4095 - 251 2376 4095 - 242 2375 4095 - 242 2375 4095 - 242 2375 4095 - 242 2375 4095 - 242 2375 4095 - 331 2655 0 - 331 2655 98 - 331 2655 206 - 331 2655 331 - 331 2655 468 - 331 2656 613 - 330 2656 761 - 330 2656 907 - 330 2657 1050 - 330 2657 1192 - 329 2657 1338 - 329 2658 1501 - 328 2659 1682 - 328 2660 1884 - 327 2661 2113 - 325 2662 2374 - 324 2664 2664 - 322 2666 2974 - 319 2668 3291 - 316 2671 3613 - 312 2673 3916 - 307 2676 4068 - 300 2678 4095 - 291 2679 4095 - 281 2679 4095 - 268 2678 4095 - 255 2677 4095 - 244 2677 4095 - 242 2677 4095 - 242 2677 4095 - 242 2677 4095 - 242 2677 4095 - 242 2677 4095 - 312 2983 3 - 312 2983 87 - 311 2983 189 - 311 2983 311 - 311 2983 450 - 311 2983 598 - 311 2984 749 - 311 2984 898 - 310 2984 1043 - 310 2984 1187 - 310 2984 1334 - 309 2985 1498 - 309 2985 1681 - 308 2985 1886 - 307 2986 2118 - 305 2987 2383 - 304 2987 2676 - 302 2988 2988 - 299 2989 3301 - 296 2990 3613 - 291 2991 3897 - 286 2991 4064 - 279 2992 4095 - 271 2991 4095 - 262 2991 4095 - 253 2991 4095 - 245 2991 4095 - 242 2991 4095 - 242 2991 4095 - 242 2991 4095 - 242 2991 4095 - 242 2991 4095 - 242 2991 4095 - 285 3301 1 - 285 3301 71 - 285 3301 164 - 285 3301 285 - 285 3301 425 - 285 3301 576 - 285 3301 731 - 285 3301 883 - 284 3301 1029 - 284 3301 1174 - 283 3301 1323 - 283 3300 1488 - 282 3300 1673 - 282 3300 1879 - 281 3300 2113 - 279 3300 2381 - 278 3300 2679 - 276 3300 2992 - 273 3299 3299 - 270 3299 3601 - 267 3298 3874 - 262 3297 4060 - 257 3296 4095 - 252 3296 4095 - 247 3295 4095 - 243 3295 4095 - 242 3295 4095 - 242 3295 4095 - 242 3295 4095 - 242 3295 4095 - 242 3295 4095 - 242 3295 4095 - 242 3295 4095 - 257 3593 0 - 257 3593 50 - 257 3593 136 - 257 3593 257 - 256 3593 399 - 256 3593 554 - 256 3593 712 - 256 3593 866 - 256 3593 1013 - 256 3593 1159 - 255 3593 1308 - 255 3593 1475 - 255 3592 1661 - 254 3592 1869 - 253 3592 2104 - 253 3591 2376 - 252 3591 2677 - 250 3591 2991 - 249 3590 3295 - 247 3589 3589 - 246 3589 3855 - 244 3588 4058 - 243 3588 4095 - 242 3588 4095 - 242 3588 4095 - 242 3588 4095 - 242 3588 4095 - 242 3588 4095 - 242 3588 4095 - 242 3588 4095 - 242 3588 4095 - 242 3588 4095 - 242 3588 4095 - 242 3852 1 - 242 3852 37 - 242 3852 120 - 242 3852 242 - 242 3852 387 - 242 3852 544 - 242 3852 704 - 242 3852 859 - 242 3852 1006 - 242 3852 1152 - 242 3852 1303 - 242 3852 1469 - 242 3852 1656 - 242 3852 1865 - 242 3852 2102 - 242 3852 2375 - 242 3852 2677 - 242 3852 2991 - 242 3852 3295 - 242 3852 3588 - 242 3852 3852 - 242 3852 4057 - 242 3852 4095 - 242 3852 4095 - 242 3852 4095 - 242 3852 4095 - 242 3852 4095 - 242 3852 4095 - 242 3852 4095 - 242 3852 4095 - 242 3852 4095 - 242 3852 4095 - 242 3852 4095 - 242 4057 0 - 242 4057 36 - 242 4057 119 - 242 4057 242 - 242 4057 387 - 242 4057 543 - 242 4057 704 - 242 4057 858 - 242 4057 1006 - 242 4057 1152 - 242 4057 1303 - 242 4057 1469 - 242 4057 1656 - 242 4057 1865 - 242 4057 2102 - 242 4057 2375 - 242 4057 2677 - 242 4057 2991 - 242 4057 3295 - 242 4057 3588 - 242 4057 3852 - 242 4057 4057 - 242 4057 4095 - 242 4057 4095 - 242 4057 4095 - 242 4057 4095 - 242 4057 4095 - 242 4057 4095 - 242 4057 4095 - 242 4057 4095 - 242 4057 4095 - 242 4057 4095 - 242 4057 4095 - 242 4095 0 - 242 4095 36 - 242 4095 119 - 242 4095 242 - 242 4095 387 - 242 4095 543 - 242 4095 704 - 242 4095 858 - 242 4095 1006 - 242 4095 1152 - 242 4095 1303 - 242 4095 1469 - 242 4095 1656 - 242 4095 1865 - 242 4095 2102 - 242 4095 2375 - 242 4095 2677 - 242 4095 2991 - 242 4095 3295 - 242 4095 3588 - 242 4095 3852 - 242 4095 4057 - 242 4095 4095 - 242 4095 4095 - 242 4095 4095 - 242 4095 4095 - 242 4095 4095 - 242 4095 4095 - 242 4095 4095 - 242 4095 4095 - 242 4095 4095 - 242 4095 4095 - 242 4095 4095 - 242 4095 0 - 242 4095 36 - 242 4095 119 - 242 4095 242 - 242 4095 387 - 242 4095 543 - 242 4095 704 - 242 4095 858 - 242 4095 1006 - 242 4095 1152 - 242 4095 1303 - 242 4095 1469 - 242 4095 1656 - 242 4095 1865 - 242 4095 2102 - 242 4095 2375 - 242 4095 2677 - 242 4095 2991 - 242 4095 3295 - 242 4095 3588 - 242 4095 3852 - 242 4095 4057 - 242 4095 4095 - 242 4095 4095 - 242 4095 4095 - 242 4095 4095 - 242 4095 4095 - 242 4095 4095 - 242 4095 4095 - 242 4095 4095 - 242 4095 4095 - 242 4095 4095 - 242 4095 4095 - 242 4095 0 - 242 4095 36 - 242 4095 119 - 242 4095 242 - 242 4095 387 - 242 4095 543 - 242 4095 704 - 242 4095 858 - 242 4095 1006 - 242 4095 1152 - 242 4095 1303 - 242 4095 1469 - 242 4095 1656 - 242 4095 1865 - 242 4095 2102 - 242 4095 2375 - 242 4095 2677 - 242 4095 2991 - 242 4095 3295 - 242 4095 3588 - 242 4095 3852 - 242 4095 4057 - 242 4095 4095 - 242 4095 4095 - 242 4095 4095 - 242 4095 4095 - 242 4095 4095 - 242 4095 4095 - 242 4095 4095 - 242 4095 4095 - 242 4095 4095 - 242 4095 4095 - 242 4095 4095 - 242 4095 0 - 242 4095 36 - 242 4095 119 - 242 4095 242 - 242 4095 387 - 242 4095 543 - 242 4095 704 - 242 4095 858 - 242 4095 1006 - 242 4095 1152 - 242 4095 1303 - 242 4095 1469 - 242 4095 1656 - 242 4095 1865 - 242 4095 2102 - 242 4095 2375 - 242 4095 2677 - 242 4095 2991 - 242 4095 3295 - 242 4095 3588 - 242 4095 3852 - 242 4095 4057 - 242 4095 4095 - 242 4095 4095 - 242 4095 4095 - 242 4095 4095 - 242 4095 4095 - 242 4095 4095 - 242 4095 4095 - 242 4095 4095 - 242 4095 4095 - 242 4095 4095 - 242 4095 4095 - 242 4095 0 - 242 4095 36 - 242 4095 119 - 242 4095 242 - 242 4095 387 - 242 4095 543 - 242 4095 704 - 242 4095 858 - 242 4095 1006 - 242 4095 1152 - 242 4095 1303 - 242 4095 1469 - 242 4095 1656 - 242 4095 1865 - 242 4095 2102 - 242 4095 2375 - 242 4095 2677 - 242 4095 2991 - 242 4095 3295 - 242 4095 3588 - 242 4095 3852 - 242 4095 4057 - 242 4095 4095 - 242 4095 4095 - 242 4095 4095 - 242 4095 4095 - 242 4095 4095 - 242 4095 4095 - 242 4095 4095 - 242 4095 4095 - 242 4095 4095 - 242 4095 4095 - 242 4095 4095 - 242 4095 0 - 242 4095 36 - 242 4095 119 - 242 4095 242 - 242 4095 387 - 242 4095 543 - 242 4095 704 - 242 4095 858 - 242 4095 1006 - 242 4095 1152 - 242 4095 1303 - 242 4095 1469 - 242 4095 1656 - 242 4095 1865 - 242 4095 2102 - 242 4095 2375 - 242 4095 2677 - 242 4095 2991 - 242 4095 3295 - 242 4095 3588 - 242 4095 3852 - 242 4095 4057 - 242 4095 4095 - 242 4095 4095 - 242 4095 4095 - 242 4095 4095 - 242 4095 4095 - 242 4095 4095 - 242 4095 4095 - 242 4095 4095 - 242 4095 4095 - 242 4095 4095 - 242 4095 4095 - 242 4095 0 - 242 4095 36 - 242 4095 119 - 242 4095 242 - 242 4095 387 - 242 4095 543 - 242 4095 704 - 242 4095 858 - 242 4095 1006 - 242 4095 1152 - 242 4095 1303 - 242 4095 1469 - 242 4095 1656 - 242 4095 1865 - 242 4095 2102 - 242 4095 2375 - 242 4095 2677 - 242 4095 2991 - 242 4095 3295 - 242 4095 3588 - 242 4095 3852 - 242 4095 4057 - 242 4095 4095 - 242 4095 4095 - 242 4095 4095 - 242 4095 4095 - 242 4095 4095 - 242 4095 4095 - 242 4095 4095 - 242 4095 4095 - 242 4095 4095 - 242 4095 4095 - 242 4095 4095 - 242 4095 0 - 242 4095 36 - 242 4095 119 - 242 4095 242 - 242 4095 387 - 242 4095 543 - 242 4095 704 - 242 4095 858 - 242 4095 1006 - 242 4095 1152 - 242 4095 1303 - 242 4095 1469 - 242 4095 1656 - 242 4095 1865 - 242 4095 2102 - 242 4095 2375 - 242 4095 2677 - 242 4095 2991 - 242 4095 3295 - 242 4095 3588 - 242 4095 3852 - 242 4095 4057 - 242 4095 4095 - 242 4095 4095 - 242 4095 4095 - 242 4095 4095 - 242 4095 4095 - 242 4095 4095 - 242 4095 4095 - 242 4095 4095 - 242 4095 4095 - 242 4095 4095 - 242 4095 4095 - 242 4095 0 - 242 4095 36 - 242 4095 119 - 242 4095 242 - 242 4095 387 - 242 4095 543 - 242 4095 704 - 242 4095 858 - 242 4095 1006 - 242 4095 1152 - 242 4095 1303 - 242 4095 1469 - 242 4095 1656 - 242 4095 1865 - 242 4095 2102 - 242 4095 2375 - 242 4095 2677 - 242 4095 2991 - 242 4095 3295 - 242 4095 3588 - 242 4095 3852 - 242 4095 4057 - 242 4095 4095 - 242 4095 4095 - 242 4095 4095 - 242 4095 4095 - 242 4095 4095 - 242 4095 4095 - 242 4095 4095 - 242 4095 4095 - 242 4095 4095 - 242 4095 4095 - 242 4095 4095 - 242 4095 0 - 242 4095 36 - 242 4095 119 - 242 4095 242 - 242 4095 387 - 242 4095 543 - 242 4095 704 - 242 4095 858 - 242 4095 1006 - 242 4095 1152 - 242 4095 1303 - 242 4095 1469 - 242 4095 1656 - 242 4095 1865 - 242 4095 2102 - 242 4095 2375 - 242 4095 2677 - 242 4095 2991 - 242 4095 3295 - 242 4095 3588 - 242 4095 3852 - 242 4095 4057 - 242 4095 4095 - 242 4095 4095 - 242 4095 4095 - 242 4095 4095 - 242 4095 4095 - 242 4095 4095 - 242 4095 4095 - 242 4095 4095 - 242 4095 4095 - 242 4095 4095 - 242 4095 4095 - 242 4095 0 - 242 4095 36 - 242 4095 119 - 242 4095 242 - 242 4095 387 - 242 4095 543 - 242 4095 704 - 242 4095 858 - 242 4095 1006 - 242 4095 1152 - 242 4095 1303 - 242 4095 1469 - 242 4095 1656 - 242 4095 1865 - 242 4095 2102 - 242 4095 2375 - 242 4095 2677 - 242 4095 2991 - 242 4095 3295 - 242 4095 3588 - 242 4095 3852 - 242 4095 4057 - 242 4095 4095 - 242 4095 4095 - 242 4095 4095 - 242 4095 4095 - 242 4095 4095 - 242 4095 4095 - 242 4095 4095 - 242 4095 4095 - 242 4095 4095 - 242 4095 4095 - 242 4095 4095 - 234 1 1 - 235 1 58 - 240 1 118 - 248 1 184 - 260 0 258 - 274 0 341 - 290 1 435 - 307 1 539 - 324 1 651 - 341 1 772 - 358 0 904 - 376 1 1057 - 394 1 1236 - 413 2 1445 - 431 1 1685 - 449 2 1960 - 465 2 2268 - 478 1 2605 - 486 0 2960 - 491 3 3342 - 495 2 3754 - 497 2 4088 - 496 3 4095 - 493 0 4095 - 487 1 4095 - 477 2 4095 - 464 1 4095 - 444 0 4095 - 418 3 4095 - 394 3 4095 - 387 0 4095 - 387 0 4095 - 387 0 4095 - 248 61 1 - 249 61 61 - 254 63 125 - 261 65 194 - 272 67 270 - 285 70 355 - 299 74 450 - 315 78 553 - 331 82 666 - 347 86 786 - 363 90 916 - 380 94 1069 - 397 98 1247 - 415 102 1455 - 434 107 1693 - 451 111 1967 - 466 115 2274 - 479 117 2609 - 486 118 2962 - 491 119 3344 - 495 119 3755 - 497 118 4088 - 496 117 4095 - 493 114 4095 - 487 110 4095 - 477 103 4095 - 464 95 4095 - 444 83 4095 - 418 66 4095 - 394 45 4095 - 387 36 4095 - 387 36 4095 - 387 36 4095 - 286 143 1 - 287 143 71 - 290 145 143 - 296 148 220 - 304 152 303 - 314 157 392 - 326 162 489 - 338 168 594 - 351 175 706 - 364 181 825 - 378 188 954 - 392 195 1105 - 408 202 1281 - 424 210 1485 - 440 218 1720 - 456 225 1990 - 470 232 2292 - 480 236 2621 - 487 239 2970 - 492 240 3350 - 495 241 3760 - 497 240 4088 - 496 237 4095 - 493 233 4095 - 487 226 4095 - 477 216 4095 - 463 202 4095 - 444 182 4095 - 418 156 4095 - 394 129 4095 - 387 119 4095 - 387 119 4095 - 387 119 4095 - 333 251 1 - 333 251 82 - 336 253 166 - 339 255 253 - 345 259 344 - 352 264 440 - 360 270 542 - 369 277 649 - 379 284 763 - 389 291 882 - 399 299 1010 - 411 307 1159 - 423 316 1332 - 436 326 1532 - 450 336 1762 - 463 345 2025 - 474 353 2319 - 483 359 2639 - 488 363 2984 - 493 365 3361 - 496 366 3768 - 497 366 4087 - 496 364 4095 - 493 359 4095 - 486 352 4095 - 476 340 4095 - 463 325 4095 - 443 304 4095 - 417 276 4095 - 393 250 4095 - 387 242 4095 - 387 242 4095 - 387 242 4095 - 378 380 1 - 378 380 93 - 379 382 188 - 382 384 285 - 385 387 385 - 390 392 489 - 395 397 596 - 402 403 708 - 408 410 825 - 416 417 945 - 423 425 1074 - 432 433 1221 - 441 442 1392 - 451 452 1588 - 462 463 1812 - 472 472 2067 - 480 480 2351 - 486 486 2662 - 490 490 3002 - 494 494 3376 - 496 496 3779 - 497 497 4087 - 496 496 4095 - 492 492 4095 - 486 486 4095 - 476 476 4095 - 462 462 4095 - 442 442 4095 - 416 416 4095 - 393 393 4095 - 387 387 4095 - 387 387 4095 - 387 387 4095 - 416 525 2 - 416 525 103 - 417 526 206 - 419 528 312 - 421 531 421 - 424 534 532 - 428 539 646 - 432 544 763 - 436 550 883 - 441 556 1006 - 447 562 1136 - 453 570 1283 - 459 578 1451 - 466 587 1643 - 473 596 1861 - 479 604 2108 - 484 611 2382 - 489 616 2687 - 492 622 3024 - 495 626 3394 - 496 630 3793 - 497 632 4087 - 495 632 4095 - 491 630 4095 - 484 626 4095 - 474 618 4095 - 460 607 4095 - 440 590 4095 - 415 568 4095 - 392 548 4095 - 387 543 4095 - 387 543 4095 - 387 543 4095 - 447 679 2 - 447 679 110 - 448 680 221 - 449 681 335 - 450 683 450 - 452 686 568 - 454 690 688 - 457 693 809 - 460 698 933 - 463 703 1058 - 466 708 1189 - 470 713 1336 - 474 720 1502 - 478 726 1690 - 482 733 1903 - 485 739 2143 - 488 745 2412 - 491 751 2714 - 494 756 3048 - 496 761 3414 - 497 766 3808 - 496 769 4086 - 494 771 4095 - 490 771 4095 - 483 769 4095 - 473 764 4095 - 458 755 4095 - 438 741 4095 - 413 723 4095 - 391 707 4095 - 387 704 4095 - 387 704 4095 - 387 704 4095 - 470 835 1 - 470 835 115 - 470 835 232 - 471 836 350 - 471 838 471 - 472 840 594 - 473 842 718 - 475 844 843 - 476 847 969 - 478 850 1096 - 480 854 1228 - 482 858 1375 - 484 862 1540 - 486 866 1726 - 488 871 1935 - 490 876 2173 - 492 881 2442 - 494 887 2742 - 495 893 3073 - 497 898 3435 - 497 903 3824 - 496 908 4085 - 493 911 4095 - 489 912 4095 - 481 911 4095 - 471 908 4095 - 456 902 4095 - 436 890 4095 - 411 874 4095 - 391 861 4095 - 387 858 4095 - 387 858 4095 - 387 858 4095 - 483 986 0 - 483 986 118 - 483 987 237 - 484 987 359 - 484 988 484 - 484 989 610 - 485 990 737 - 485 992 865 - 486 993 993 - 487 995 1121 - 487 997 1254 - 488 1000 1401 - 489 1003 1567 - 490 1006 1753 - 492 1010 1963 - 493 1015 2201 - 494 1020 2470 - 496 1025 2770 - 496 1030 3098 - 497 1036 3457 - 496 1041 3841 - 495 1046 4085 - 492 1049 4095 - 487 1051 4095 - 479 1052 4095 - 469 1050 4095 - 454 1045 4095 - 433 1034 4095 - 409 1019 4095 - 390 1008 4095 - 387 1006 4095 - 387 1006 4095 - 387 1006 4095 - 490 1132 0 - 490 1132 119 - 490 1132 240 - 490 1133 364 - 490 1133 490 - 490 1134 619 - 491 1135 749 - 491 1136 879 - 491 1138 1009 - 492 1139 1139 - 492 1141 1273 - 493 1143 1422 - 493 1145 1589 - 494 1148 1776 - 495 1152 1988 - 495 1155 2227 - 496 1160 2497 - 497 1165 2796 - 497 1170 3123 - 497 1175 3478 - 496 1180 3857 - 494 1185 4084 - 490 1189 4095 - 484 1191 4095 - 476 1193 4095 - 466 1192 4095 - 450 1188 4095 - 430 1177 4095 - 406 1163 4095 - 389 1153 4095 - 387 1152 4095 - 387 1152 4095 - 387 1152 4095 - 494 1282 1 - 494 1282 119 - 494 1282 240 - 494 1282 366 - 494 1283 494 - 494 1283 625 - 494 1284 757 - 495 1285 890 - 495 1286 1021 - 495 1287 1153 - 495 1289 1289 - 495 1291 1439 - 496 1293 1608 - 496 1295 1797 - 496 1298 2010 - 497 1301 2251 - 497 1305 2522 - 497 1309 2822 - 496 1314 3147 - 496 1319 3499 - 494 1324 3872 - 492 1329 4083 - 487 1333 4095 - 481 1336 4095 - 473 1338 4095 - 462 1338 4095 - 447 1334 4095 - 426 1324 4095 - 403 1311 4095 - 388 1303 4095 - 387 1303 4095 - 387 1303 4095 - 387 1303 4095 - 496 1448 2 - 496 1448 119 - 496 1449 240 - 496 1449 366 - 496 1449 496 - 496 1450 630 - 496 1450 764 - 497 1451 898 - 497 1452 1032 - 497 1453 1166 - 497 1454 1303 - 497 1455 1455 - 497 1457 1626 - 497 1459 1817 - 497 1462 2031 - 497 1464 2275 - 496 1468 2547 - 496 1472 2848 - 495 1476 3172 - 494 1480 3521 - 492 1485 3887 - 489 1489 4081 - 484 1493 4095 - 478 1497 4095 - 470 1500 4095 - 458 1501 4095 - 442 1496 4095 - 422 1487 4095 - 400 1476 4095 - 387 1470 4095 - 387 1469 4095 - 387 1469 4095 - 387 1469 4095 - 497 1635 2 - 497 1635 117 - 497 1635 238 - 497 1635 365 - 497 1636 496 - 496 1636 632 - 496 1636 769 - 496 1637 905 - 496 1638 1041 - 496 1639 1176 - 496 1639 1315 - 496 1641 1469 - 496 1642 1642 - 496 1644 1835 - 495 1646 2051 - 495 1648 2297 - 494 1651 2572 - 494 1654 2874 - 492 1658 3198 - 490 1662 3542 - 488 1666 3901 - 484 1670 4079 - 479 1675 4095 - 473 1679 4095 - 464 1682 4095 - 452 1683 4095 - 436 1678 4095 - 416 1670 4095 - 396 1660 4095 - 387 1656 4095 - 387 1656 4095 - 387 1656 4095 - 387 1656 4095 - 494 1844 2 - 494 1844 115 - 494 1844 234 - 494 1844 361 - 494 1844 494 - 494 1845 632 - 494 1845 771 - 494 1846 910 - 494 1846 1047 - 494 1847 1184 - 493 1848 1325 - 493 1849 1481 - 493 1850 1656 - 493 1851 1851 - 492 1853 2070 - 491 1855 2319 - 490 1857 2597 - 489 1860 2901 - 487 1863 3222 - 485 1866 3562 - 482 1870 3913 - 478 1875 4077 - 473 1879 4095 - 467 1884 4095 - 457 1887 4095 - 445 1886 4095 - 428 1882 4095 - 409 1874 4095 - 392 1867 4095 - 387 1865 4095 - 387 1865 4095 - 387 1865 4095 - 387 1865 4095 - 489 2080 2 - 489 2080 111 - 489 2080 228 - 489 2080 355 - 489 2080 489 - 489 2080 629 - 489 2080 771 - 489 2081 912 - 488 2081 1051 - 488 2082 1190 - 488 2082 1332 - 488 2083 1490 - 487 2084 1667 - 487 2085 1864 - 486 2087 2086 - 485 2088 2339 - 484 2090 2620 - 482 2092 2926 - 480 2095 3246 - 478 2099 3582 - 475 2103 3924 - 471 2108 4075 - 465 2112 4095 - 458 2116 4095 - 448 2118 4095 - 435 2117 4095 - 419 2112 4095 - 402 2106 4095 - 389 2102 4095 - 387 2102 4095 - 387 2102 4095 - 387 2102 4095 - 387 2102 4095 - 480 2349 2 - 480 2349 105 - 480 2349 219 - 480 2350 344 - 480 2350 480 - 480 2350 622 - 480 2350 767 - 479 2351 911 - 479 2351 1052 - 479 2352 1192 - 479 2352 1336 - 478 2353 1497 - 478 2354 1675 - 477 2355 1875 - 476 2356 2101 - 476 2358 2357 - 474 2360 2643 - 473 2362 2951 - 471 2365 3271 - 468 2369 3601 - 464 2373 3927 - 460 2376 4072 - 454 2380 4095 - 446 2383 4095 - 436 2383 4095 - 423 2382 4095 - 408 2379 4095 - 395 2376 4095 - 387 2375 4095 - 387 2375 4095 - 387 2375 4095 - 387 2375 4095 - 387 2375 4095 - 468 2656 2 - 468 2656 97 - 468 2656 206 - 467 2656 331 - 467 2656 467 - 467 2656 612 - 467 2656 761 - 467 2657 907 - 467 2657 1050 - 466 2657 1192 - 466 2658 1338 - 466 2658 1501 - 465 2659 1682 - 464 2660 1885 - 464 2661 2113 - 462 2663 2374 - 461 2664 2664 - 459 2666 2974 - 457 2668 3291 - 454 2671 3613 - 450 2673 3916 - 445 2676 4068 - 439 2678 4095 - 431 2679 4095 - 421 2679 4095 - 409 2678 4095 - 397 2677 4095 - 389 2677 4095 - 387 2677 4095 - 387 2677 4095 - 387 2677 4095 - 387 2677 4095 - 387 2677 4095 - 450 2983 2 - 450 2983 86 - 449 2983 188 - 449 2983 311 - 449 2984 449 - 449 2984 597 - 449 2984 749 - 449 2984 898 - 448 2984 1042 - 448 2984 1186 - 448 2985 1334 - 447 2985 1498 - 447 2985 1681 - 446 2986 1886 - 445 2986 2118 - 444 2987 2383 - 442 2987 2676 - 440 2988 2988 - 438 2989 3301 - 435 2990 3612 - 431 2991 3897 - 426 2991 4064 - 420 2992 4095 - 412 2991 4095 - 404 2991 4095 - 396 2991 4095 - 389 2991 4095 - 387 2991 4095 - 387 2991 4095 - 387 2991 4095 - 387 2991 4095 - 387 2991 4095 - 387 2991 4095 - 425 3301 2 - 425 3301 71 - 425 3301 164 - 425 3301 285 - 425 3301 425 - 425 3301 576 - 424 3301 731 - 424 3301 883 - 424 3301 1028 - 424 3301 1174 - 423 3300 1322 - 423 3300 1488 - 422 3300 1672 - 422 3300 1879 - 421 3300 2113 - 420 3300 2381 - 418 3300 2679 - 416 3300 2992 - 414 3299 3299 - 411 3299 3601 - 408 3298 3873 - 404 3297 4060 - 400 3296 4095 - 395 3296 4095 - 390 3295 4095 - 387 3295 4095 - 387 3295 4095 - 387 3295 4095 - 387 3295 4095 - 387 3295 4095 - 387 3295 4095 - 387 3295 4095 - 387 3295 4095 - 399 3593 2 - 399 3593 50 - 399 3593 135 - 399 3593 256 - 399 3593 399 - 399 3593 554 - 399 3593 712 - 399 3593 866 - 398 3593 1013 - 398 3593 1159 - 398 3593 1308 - 398 3593 1475 - 397 3592 1661 - 397 3592 1869 - 396 3592 2104 - 396 3591 2376 - 395 3591 2677 - 394 3590 2991 - 393 3590 3295 - 391 3589 3589 - 390 3589 3855 - 388 3588 4058 - 387 3588 4095 - 387 3588 4095 - 387 3588 4095 - 387 3588 4095 - 387 3588 4095 - 387 3588 4095 - 387 3588 4095 - 387 3588 4095 - 387 3588 4095 - 387 3588 4095 - 387 3588 4095 - 387 3852 1 - 387 3852 37 - 387 3852 120 - 387 3852 242 - 387 3852 387 - 387 3852 543 - 387 3852 704 - 387 3852 859 - 387 3852 1006 - 387 3852 1152 - 387 3852 1303 - 387 3852 1469 - 387 3852 1656 - 387 3852 1865 - 387 3852 2102 - 387 3852 2375 - 387 3852 2677 - 387 3852 2991 - 387 3852 3295 - 387 3852 3588 - 387 3852 3852 - 387 3852 4057 - 387 3852 4095 - 387 3852 4095 - 387 3852 4095 - 387 3852 4095 - 387 3852 4095 - 387 3852 4095 - 387 3852 4095 - 387 3852 4095 - 387 3852 4095 - 387 3852 4095 - 387 3852 4095 - 387 4057 0 - 387 4057 36 - 387 4057 119 - 387 4057 242 - 387 4057 387 - 387 4057 543 - 387 4057 704 - 387 4057 858 - 387 4057 1006 - 387 4057 1152 - 387 4057 1303 - 387 4057 1469 - 387 4057 1656 - 387 4057 1865 - 387 4057 2102 - 387 4057 2375 - 387 4057 2677 - 387 4057 2991 - 387 4057 3295 - 387 4057 3588 - 387 4057 3852 - 387 4057 4057 - 387 4057 4095 - 387 4057 4095 - 387 4057 4095 - 387 4057 4095 - 387 4057 4095 - 387 4057 4095 - 387 4057 4095 - 387 4057 4095 - 387 4057 4095 - 387 4057 4095 - 387 4057 4095 - 387 4095 0 - 387 4095 36 - 387 4095 119 - 387 4095 242 - 387 4095 387 - 387 4095 543 - 387 4095 704 - 387 4095 858 - 387 4095 1006 - 387 4095 1152 - 387 4095 1303 - 387 4095 1469 - 387 4095 1656 - 387 4095 1865 - 387 4095 2102 - 387 4095 2375 - 387 4095 2677 - 387 4095 2991 - 387 4095 3295 - 387 4095 3588 - 387 4095 3852 - 387 4095 4057 - 387 4095 4095 - 387 4095 4095 - 387 4095 4095 - 387 4095 4095 - 387 4095 4095 - 387 4095 4095 - 387 4095 4095 - 387 4095 4095 - 387 4095 4095 - 387 4095 4095 - 387 4095 4095 - 387 4095 0 - 387 4095 36 - 387 4095 119 - 387 4095 242 - 387 4095 387 - 387 4095 543 - 387 4095 704 - 387 4095 858 - 387 4095 1006 - 387 4095 1152 - 387 4095 1303 - 387 4095 1469 - 387 4095 1656 - 387 4095 1865 - 387 4095 2102 - 387 4095 2375 - 387 4095 2677 - 387 4095 2991 - 387 4095 3295 - 387 4095 3588 - 387 4095 3852 - 387 4095 4057 - 387 4095 4095 - 387 4095 4095 - 387 4095 4095 - 387 4095 4095 - 387 4095 4095 - 387 4095 4095 - 387 4095 4095 - 387 4095 4095 - 387 4095 4095 - 387 4095 4095 - 387 4095 4095 - 387 4095 0 - 387 4095 36 - 387 4095 119 - 387 4095 242 - 387 4095 387 - 387 4095 543 - 387 4095 704 - 387 4095 858 - 387 4095 1006 - 387 4095 1152 - 387 4095 1303 - 387 4095 1469 - 387 4095 1656 - 387 4095 1865 - 387 4095 2102 - 387 4095 2375 - 387 4095 2677 - 387 4095 2991 - 387 4095 3295 - 387 4095 3588 - 387 4095 3852 - 387 4095 4057 - 387 4095 4095 - 387 4095 4095 - 387 4095 4095 - 387 4095 4095 - 387 4095 4095 - 387 4095 4095 - 387 4095 4095 - 387 4095 4095 - 387 4095 4095 - 387 4095 4095 - 387 4095 4095 - 387 4095 0 - 387 4095 36 - 387 4095 119 - 387 4095 242 - 387 4095 387 - 387 4095 543 - 387 4095 704 - 387 4095 858 - 387 4095 1006 - 387 4095 1152 - 387 4095 1303 - 387 4095 1469 - 387 4095 1656 - 387 4095 1865 - 387 4095 2102 - 387 4095 2375 - 387 4095 2677 - 387 4095 2991 - 387 4095 3295 - 387 4095 3588 - 387 4095 3852 - 387 4095 4057 - 387 4095 4095 - 387 4095 4095 - 387 4095 4095 - 387 4095 4095 - 387 4095 4095 - 387 4095 4095 - 387 4095 4095 - 387 4095 4095 - 387 4095 4095 - 387 4095 4095 - 387 4095 4095 - 387 4095 0 - 387 4095 36 - 387 4095 119 - 387 4095 242 - 387 4095 387 - 387 4095 543 - 387 4095 704 - 387 4095 858 - 387 4095 1006 - 387 4095 1152 - 387 4095 1303 - 387 4095 1469 - 387 4095 1656 - 387 4095 1865 - 387 4095 2102 - 387 4095 2375 - 387 4095 2677 - 387 4095 2991 - 387 4095 3295 - 387 4095 3588 - 387 4095 3852 - 387 4095 4057 - 387 4095 4095 - 387 4095 4095 - 387 4095 4095 - 387 4095 4095 - 387 4095 4095 - 387 4095 4095 - 387 4095 4095 - 387 4095 4095 - 387 4095 4095 - 387 4095 4095 - 387 4095 4095 - 387 4095 0 - 387 4095 36 - 387 4095 119 - 387 4095 242 - 387 4095 387 - 387 4095 543 - 387 4095 704 - 387 4095 858 - 387 4095 1006 - 387 4095 1152 - 387 4095 1303 - 387 4095 1469 - 387 4095 1656 - 387 4095 1865 - 387 4095 2102 - 387 4095 2375 - 387 4095 2677 - 387 4095 2991 - 387 4095 3295 - 387 4095 3588 - 387 4095 3852 - 387 4095 4057 - 387 4095 4095 - 387 4095 4095 - 387 4095 4095 - 387 4095 4095 - 387 4095 4095 - 387 4095 4095 - 387 4095 4095 - 387 4095 4095 - 387 4095 4095 - 387 4095 4095 - 387 4095 4095 - 387 4095 0 - 387 4095 36 - 387 4095 119 - 387 4095 242 - 387 4095 387 - 387 4095 543 - 387 4095 704 - 387 4095 858 - 387 4095 1006 - 387 4095 1152 - 387 4095 1303 - 387 4095 1469 - 387 4095 1656 - 387 4095 1865 - 387 4095 2102 - 387 4095 2375 - 387 4095 2677 - 387 4095 2991 - 387 4095 3295 - 387 4095 3588 - 387 4095 3852 - 387 4095 4057 - 387 4095 4095 - 387 4095 4095 - 387 4095 4095 - 387 4095 4095 - 387 4095 4095 - 387 4095 4095 - 387 4095 4095 - 387 4095 4095 - 387 4095 4095 - 387 4095 4095 - 387 4095 4095 - 387 4095 0 - 387 4095 36 - 387 4095 119 - 387 4095 242 - 387 4095 387 - 387 4095 543 - 387 4095 704 - 387 4095 858 - 387 4095 1006 - 387 4095 1152 - 387 4095 1303 - 387 4095 1469 - 387 4095 1656 - 387 4095 1865 - 387 4095 2102 - 387 4095 2375 - 387 4095 2677 - 387 4095 2991 - 387 4095 3295 - 387 4095 3588 - 387 4095 3852 - 387 4095 4057 - 387 4095 4095 - 387 4095 4095 - 387 4095 4095 - 387 4095 4095 - 387 4095 4095 - 387 4095 4095 - 387 4095 4095 - 387 4095 4095 - 387 4095 4095 - 387 4095 4095 - 387 4095 4095 - 387 4095 0 - 387 4095 36 - 387 4095 119 - 387 4095 242 - 387 4095 387 - 387 4095 543 - 387 4095 704 - 387 4095 858 - 387 4095 1006 - 387 4095 1152 - 387 4095 1303 - 387 4095 1469 - 387 4095 1656 - 387 4095 1865 - 387 4095 2102 - 387 4095 2375 - 387 4095 2677 - 387 4095 2991 - 387 4095 3295 - 387 4095 3588 - 387 4095 3852 - 387 4095 4057 - 387 4095 4095 - 387 4095 4095 - 387 4095 4095 - 387 4095 4095 - 387 4095 4095 - 387 4095 4095 - 387 4095 4095 - 387 4095 4095 - 387 4095 4095 - 387 4095 4095 - 387 4095 4095 - 387 4095 0 - 387 4095 36 - 387 4095 119 - 387 4095 242 - 387 4095 387 - 387 4095 543 - 387 4095 704 - 387 4095 858 - 387 4095 1006 - 387 4095 1152 - 387 4095 1303 - 387 4095 1469 - 387 4095 1656 - 387 4095 1865 - 387 4095 2102 - 387 4095 2375 - 387 4095 2677 - 387 4095 2991 - 387 4095 3295 - 387 4095 3588 - 387 4095 3852 - 387 4095 4057 - 387 4095 4095 - 387 4095 4095 - 387 4095 4095 - 387 4095 4095 - 387 4095 4095 - 387 4095 4095 - 387 4095 4095 - 387 4095 4095 - 387 4095 4095 - 387 4095 4095 - 387 4095 4095 - 387 4095 0 - 387 4095 36 - 387 4095 119 - 387 4095 242 - 387 4095 387 - 387 4095 543 - 387 4095 704 - 387 4095 858 - 387 4095 1006 - 387 4095 1152 - 387 4095 1303 - 387 4095 1469 - 387 4095 1656 - 387 4095 1865 - 387 4095 2102 - 387 4095 2375 - 387 4095 2677 - 387 4095 2991 - 387 4095 3295 - 387 4095 3588 - 387 4095 3852 - 387 4095 4057 - 387 4095 4095 - 387 4095 4095 - 387 4095 4095 - 387 4095 4095 - 387 4095 4095 - 387 4095 4095 - 387 4095 4095 - 387 4095 4095 - 387 4095 4095 - 387 4095 4095 - 387 4095 4095 - 348 1 1 - 350 1 69 - 354 0 139 - 362 0 215 - 373 0 296 - 386 0 384 - 401 1 481 - 418 2 585 - 435 1 697 - 452 1 817 - 470 1 946 - 489 1 1097 - 509 1 1273 - 530 2 1478 - 551 2 1714 - 571 2 1985 - 590 2 2288 - 604 1 2618 - 614 0 2968 - 621 3 3349 - 627 3 3759 - 630 2 4088 - 632 3 4095 - 631 0 4095 - 627 1 4095 - 620 3 4095 - 609 1 4095 - 593 3 4095 - 570 3 4095 - 549 3 4095 - 543 0 4095 - 543 0 4095 - 543 0 4095 - 361 71 1 - 363 71 71 - 367 72 144 - 374 74 222 - 384 76 305 - 396 78 395 - 410 81 492 - 426 84 597 - 442 87 709 - 458 90 828 - 475 94 957 - 493 97 1107 - 512 101 1283 - 533 105 1487 - 553 109 1722 - 573 112 1991 - 591 115 2293 - 605 118 2622 - 614 119 2971 - 621 119 3351 - 627 119 3760 - 631 118 4088 - 632 117 4095 - 631 114 4095 - 627 109 4095 - 620 103 4095 - 609 95 4095 - 592 83 4095 - 570 66 4095 - 549 45 4095 - 543 36 4095 - 543 36 4095 - 543 36 4095 - 397 158 1 - 398 158 78 - 402 160 158 - 407 162 242 - 415 165 330 - 425 169 423 - 436 173 523 - 449 178 630 - 462 183 742 - 476 189 861 - 491 194 990 - 507 200 1139 - 524 207 1313 - 542 214 1514 - 561 221 1746 - 578 227 2012 - 595 233 2309 - 607 237 2632 - 615 239 2978 - 622 240 3357 - 627 240 3765 - 631 239 4087 - 632 237 4095 - 631 232 4095 - 627 225 4095 - 620 215 4095 - 609 201 4095 - 592 182 4095 - 570 156 4095 - 549 129 4095 - 543 119 4095 - 543 119 4095 - 543 119 4095 - 444 266 1 - 445 266 87 - 447 268 176 - 451 270 268 - 456 273 363 - 464 277 463 - 472 282 567 - 482 288 676 - 492 294 791 - 503 300 910 - 515 307 1038 - 527 314 1186 - 542 322 1358 - 557 331 1556 - 572 340 1784 - 587 348 2043 - 600 355 2333 - 610 360 2649 - 617 363 2991 - 623 365 3367 - 628 366 3773 - 631 366 4087 - 632 363 4095 - 631 359 4095 - 627 351 4095 - 619 340 4095 - 608 325 4095 - 591 303 4095 - 569 276 4095 - 549 250 4095 - 543 242 4095 - 543 242 4095 - 543 242 4095 - 491 393 1 - 492 394 97 - 493 395 194 - 496 397 295 - 500 400 398 - 505 404 504 - 511 408 614 - 517 414 727 - 525 420 845 - 533 426 966 - 542 432 1095 - 551 440 1242 - 562 448 1412 - 574 457 1607 - 586 466 1829 - 597 475 2081 - 606 482 2362 - 613 487 2670 - 619 491 3009 - 625 494 3381 - 629 496 3783 - 631 497 4087 - 632 496 4095 - 631 492 4095 - 626 485 4095 - 619 475 4095 - 607 461 4095 - 590 441 4095 - 568 416 4095 - 548 393 4095 - 543 387 4095 - 543 387 4095 - 543 387 4095 - 534 536 2 - 534 536 105 - 535 537 211 - 537 539 319 - 539 541 429 - 543 544 542 - 547 548 658 - 551 553 776 - 557 558 897 - 562 564 1021 - 568 569 1151 - 575 576 1298 - 583 583 1466 - 590 591 1657 - 599 599 1873 - 606 606 2117 - 612 612 2390 - 617 618 2694 - 622 622 3030 - 627 627 3399 - 630 630 3797 - 632 632 4086 - 632 632 4095 - 630 630 4095 - 625 625 4095 - 618 618 4095 - 606 606 4095 - 589 589 4095 - 567 567 4095 - 548 548 4095 - 543 543 4095 - 543 543 4095 - 543 543 4095 - 569 687 2 - 569 687 111 - 570 688 224 - 571 689 338 - 572 691 455 - 575 694 574 - 577 697 695 - 580 700 818 - 583 704 942 - 587 708 1067 - 591 713 1198 - 595 718 1345 - 599 724 1511 - 604 729 1699 - 609 735 1910 - 613 741 2149 - 617 746 2418 - 621 752 2720 - 625 757 3053 - 628 762 3418 - 631 766 3811 - 632 770 4086 - 632 771 4095 - 629 771 4095 - 624 769 4095 - 616 764 4095 - 605 755 4095 - 587 741 4095 - 566 722 4095 - 547 707 4095 - 543 704 4095 - 543 704 4095 - 543 704 4095 - 595 840 1 - 595 840 116 - 595 841 233 - 596 842 352 - 596 843 474 - 598 845 597 - 599 847 722 - 601 849 848 - 602 852 974 - 604 854 1102 - 606 857 1233 - 608 861 1380 - 611 864 1545 - 613 868 1731 - 616 873 1940 - 619 877 2178 - 622 883 2447 - 625 888 2747 - 628 894 3078 - 630 899 3439 - 632 904 3827 - 632 908 4085 - 631 911 4095 - 628 912 4095 - 623 911 4095 - 615 908 4095 - 603 902 4095 - 585 890 4095 - 564 874 4095 - 547 861 4095 - 543 858 4095 - 543 858 4095 - 543 858 4095 - 610 989 0 - 610 989 118 - 610 990 238 - 611 990 360 - 611 991 485 - 612 992 612 - 612 993 739 - 613 994 867 - 614 996 995 - 615 998 1124 - 616 1000 1257 - 617 1002 1404 - 618 1005 1570 - 620 1008 1757 - 622 1012 1967 - 624 1016 2205 - 626 1021 2474 - 628 1026 2774 - 630 1031 3102 - 631 1037 3460 - 632 1042 3843 - 632 1046 4084 - 630 1050 4095 - 627 1051 4095 - 621 1052 4095 - 613 1050 4095 - 601 1045 4095 - 583 1034 4095 - 562 1019 4095 - 546 1007 4095 - 543 1006 4095 - 543 1006 4095 - 543 1006 4095 - 619 1134 0 - 619 1135 119 - 619 1135 240 - 619 1135 364 - 620 1136 491 - 620 1136 620 - 620 1137 750 - 621 1138 880 - 621 1140 1010 - 622 1141 1141 - 622 1143 1275 - 623 1145 1424 - 624 1147 1591 - 625 1150 1779 - 626 1153 1991 - 628 1157 2230 - 629 1161 2500 - 630 1166 2799 - 631 1171 3126 - 632 1176 3481 - 632 1181 3859 - 631 1185 4083 - 629 1189 4095 - 625 1191 4095 - 619 1193 4095 - 611 1192 4095 - 598 1187 4095 - 580 1177 4095 - 560 1163 4095 - 545 1153 4095 - 543 1152 4095 - 543 1152 4095 - 543 1152 4095 - 625 1284 1 - 625 1284 119 - 625 1284 241 - 625 1284 366 - 626 1285 495 - 626 1285 626 - 626 1286 758 - 626 1287 891 - 627 1288 1022 - 627 1289 1155 - 627 1290 1290 - 628 1292 1441 - 628 1294 1610 - 629 1296 1799 - 630 1299 2012 - 630 1302 2254 - 631 1306 2525 - 632 1310 2825 - 632 1315 3150 - 632 1320 3502 - 632 1324 3874 - 630 1329 4082 - 628 1333 4095 - 623 1336 4095 - 617 1338 4095 - 608 1338 4095 - 595 1334 4095 - 577 1324 4095 - 557 1311 4095 - 544 1303 4095 - 543 1303 4095 - 543 1303 4095 - 543 1303 4095 - 630 1450 2 - 630 1450 118 - 630 1450 240 - 630 1450 366 - 630 1451 496 - 630 1451 630 - 630 1452 765 - 630 1452 899 - 630 1453 1033 - 630 1454 1167 - 631 1455 1304 - 631 1457 1456 - 631 1458 1627 - 631 1460 1818 - 632 1463 2033 - 632 1465 2277 - 632 1469 2549 - 632 1472 2850 - 632 1476 3174 - 631 1481 3523 - 630 1485 3888 - 628 1490 4081 - 625 1494 4095 - 620 1497 4095 - 614 1500 4095 - 604 1501 4095 - 591 1496 4095 - 573 1487 4095 - 554 1476 4095 - 544 1470 4095 - 543 1469 4095 - 543 1469 4095 - 543 1469 4095 - 632 1636 2 - 632 1636 117 - 632 1636 238 - 632 1636 365 - 632 1637 496 - 632 1637 632 - 632 1638 769 - 632 1638 906 - 632 1639 1041 - 632 1640 1177 - 632 1640 1316 - 632 1642 1470 - 632 1643 1643 - 632 1645 1836 - 632 1647 2053 - 632 1649 2299 - 632 1652 2574 - 631 1655 2876 - 631 1658 3199 - 630 1662 3544 - 628 1666 3902 - 625 1671 4079 - 621 1675 4095 - 617 1679 4095 - 610 1682 4095 - 600 1683 4095 - 585 1678 4095 - 568 1669 4095 - 551 1660 4095 - 543 1656 4095 - 543 1656 4095 - 543 1656 4095 - 543 1656 4095 - 632 1845 3 - 632 1845 114 - 632 1845 234 - 632 1845 361 - 632 1845 494 - 632 1846 632 - 632 1846 771 - 631 1847 910 - 631 1847 1047 - 631 1848 1185 - 631 1848 1325 - 631 1849 1482 - 631 1850 1656 - 631 1852 1851 - 630 1853 2071 - 630 1855 2320 - 629 1858 2598 - 629 1860 2902 - 628 1863 3224 - 626 1867 3563 - 624 1871 3913 - 621 1875 4077 - 617 1880 4095 - 611 1884 4095 - 604 1887 4095 - 593 1886 4095 - 579 1882 4095 - 562 1874 4095 - 548 1867 4095 - 543 1865 4095 - 543 1865 4095 - 543 1865 4095 - 543 1865 4095 - 629 2080 2 - 629 2080 111 - 629 2080 228 - 629 2080 354 - 629 2081 489 - 629 2081 628 - 628 2081 771 - 628 2082 912 - 628 2082 1051 - 628 2083 1190 - 628 2083 1333 - 628 2084 1491 - 627 2085 1667 - 627 2086 1865 - 626 2087 2087 - 626 2089 2340 - 625 2091 2621 - 624 2093 2927 - 622 2096 3247 - 620 2099 3583 - 618 2104 3924 - 615 2108 4075 - 610 2113 4095 - 604 2116 4095 - 596 2118 4095 - 585 2117 4095 - 571 2112 4095 - 556 2106 4095 - 545 2102 4095 - 543 2102 4095 - 543 2102 4095 - 543 2102 4095 - 543 2102 4095 - 622 2350 2 - 622 2350 105 - 622 2350 218 - 622 2350 344 - 622 2350 480 - 622 2351 622 - 622 2351 767 - 622 2351 911 - 621 2352 1051 - 621 2352 1192 - 621 2353 1337 - 621 2353 1497 - 620 2354 1676 - 620 2355 1876 - 619 2357 2101 - 619 2358 2358 - 618 2360 2644 - 616 2363 2952 - 615 2366 3272 - 613 2369 3602 - 610 2373 3927 - 606 2377 4072 - 601 2380 4095 - 594 2383 4095 - 585 2383 4095 - 574 2382 4095 - 562 2379 4095 - 550 2376 4095 - 544 2375 4095 - 543 2375 4095 - 543 2375 4095 - 543 2375 4095 - 543 2375 4095 - 612 2656 2 - 612 2656 97 - 612 2656 206 - 612 2656 330 - 612 2656 467 - 612 2657 612 - 612 2657 760 - 612 2657 907 - 612 2658 1050 - 611 2658 1192 - 611 2658 1338 - 611 2659 1501 - 610 2660 1682 - 610 2661 1885 - 609 2662 2113 - 608 2663 2374 - 607 2665 2664 - 605 2667 2975 - 603 2669 3292 - 601 2671 3613 - 598 2673 3915 - 593 2676 4068 - 588 2678 4095 - 581 2679 4095 - 572 2679 4095 - 562 2678 4095 - 552 2677 4095 - 545 2677 4095 - 543 2677 4095 - 543 2677 4095 - 543 2677 4095 - 543 2677 4095 - 543 2677 4095 - 597 2984 2 - 597 2984 86 - 597 2984 188 - 597 2984 311 - 597 2984 449 - 597 2984 597 - 597 2984 749 - 597 2984 898 - 596 2984 1042 - 596 2985 1186 - 596 2985 1334 - 595 2985 1498 - 595 2985 1681 - 594 2986 1886 - 593 2986 2118 - 592 2987 2383 - 591 2988 2677 - 589 2988 2988 - 587 2989 3301 - 584 2990 3612 - 581 2991 3896 - 577 2991 4064 - 571 2992 4095 - 565 2991 4095 - 558 2991 4095 - 551 2991 4095 - 545 2991 4095 - 543 2991 4095 - 543 2991 4095 - 543 2991 4095 - 543 2991 4095 - 543 2991 4095 - 543 2991 4095 - 576 3301 1 - 576 3301 70 - 576 3301 163 - 576 3301 284 - 576 3301 424 - 576 3301 576 - 576 3301 731 - 575 3301 882 - 575 3300 1028 - 575 3300 1173 - 575 3300 1322 - 574 3300 1487 - 574 3300 1672 - 573 3300 1879 - 572 3300 2112 - 571 3300 2381 - 570 3300 2679 - 568 3299 2992 - 566 3299 3299 - 564 3299 3601 - 561 3298 3873 - 558 3297 4060 - 554 3296 4095 - 550 3296 4095 - 546 3295 4095 - 544 3295 4095 - 543 3295 4095 - 543 3295 4095 - 543 3295 4095 - 543 3295 4095 - 543 3295 4095 - 543 3295 4095 - 543 3295 4095 - 554 3593 2 - 554 3593 50 - 554 3593 135 - 554 3593 256 - 554 3593 399 - 553 3593 553 - 553 3593 712 - 553 3593 866 - 553 3593 1012 - 553 3593 1158 - 553 3593 1308 - 552 3592 1474 - 552 3592 1660 - 552 3592 1868 - 551 3592 2104 - 551 3591 2376 - 550 3591 2677 - 549 3590 2991 - 548 3590 3295 - 547 3589 3589 - 546 3589 3855 - 545 3588 4058 - 544 3588 4095 - 543 3588 4095 - 543 3588 4095 - 543 3588 4095 - 543 3588 4095 - 543 3588 4095 - 543 3588 4095 - 543 3588 4095 - 543 3588 4095 - 543 3588 4095 - 543 3588 4095 - 543 3852 0 - 543 3852 37 - 543 3852 120 - 543 3852 242 - 543 3852 387 - 543 3852 543 - 543 3852 704 - 543 3852 859 - 543 3852 1006 - 543 3852 1152 - 543 3852 1303 - 543 3852 1469 - 543 3852 1656 - 543 3852 1865 - 543 3852 2102 - 543 3852 2375 - 543 3852 2677 - 543 3852 2991 - 543 3852 3295 - 543 3852 3588 - 543 3852 3852 - 543 3852 4057 - 543 3852 4095 - 543 3852 4095 - 543 3852 4095 - 543 3852 4095 - 543 3852 4095 - 543 3852 4095 - 543 3852 4095 - 543 3852 4095 - 543 3852 4095 - 543 3852 4095 - 543 3852 4095 - 543 4057 0 - 543 4057 36 - 543 4057 119 - 543 4057 242 - 543 4057 387 - 543 4057 543 - 543 4057 704 - 543 4057 858 - 543 4057 1006 - 543 4057 1152 - 543 4057 1303 - 543 4057 1469 - 543 4057 1656 - 543 4057 1865 - 543 4057 2102 - 543 4057 2375 - 543 4057 2677 - 543 4057 2991 - 543 4057 3295 - 543 4057 3588 - 543 4057 3852 - 543 4057 4057 - 543 4057 4095 - 543 4057 4095 - 543 4057 4095 - 543 4057 4095 - 543 4057 4095 - 543 4057 4095 - 543 4057 4095 - 543 4057 4095 - 543 4057 4095 - 543 4057 4095 - 543 4057 4095 - 543 4095 0 - 543 4095 36 - 543 4095 119 - 543 4095 242 - 543 4095 387 - 543 4095 543 - 543 4095 704 - 543 4095 858 - 543 4095 1006 - 543 4095 1152 - 543 4095 1303 - 543 4095 1469 - 543 4095 1656 - 543 4095 1865 - 543 4095 2102 - 543 4095 2375 - 543 4095 2677 - 543 4095 2991 - 543 4095 3295 - 543 4095 3588 - 543 4095 3852 - 543 4095 4057 - 543 4095 4095 - 543 4095 4095 - 543 4095 4095 - 543 4095 4095 - 543 4095 4095 - 543 4095 4095 - 543 4095 4095 - 543 4095 4095 - 543 4095 4095 - 543 4095 4095 - 543 4095 4095 - 543 4095 0 - 543 4095 36 - 543 4095 119 - 543 4095 242 - 543 4095 387 - 543 4095 543 - 543 4095 704 - 543 4095 858 - 543 4095 1006 - 543 4095 1152 - 543 4095 1303 - 543 4095 1469 - 543 4095 1656 - 543 4095 1865 - 543 4095 2102 - 543 4095 2375 - 543 4095 2677 - 543 4095 2991 - 543 4095 3295 - 543 4095 3588 - 543 4095 3852 - 543 4095 4057 - 543 4095 4095 - 543 4095 4095 - 543 4095 4095 - 543 4095 4095 - 543 4095 4095 - 543 4095 4095 - 543 4095 4095 - 543 4095 4095 - 543 4095 4095 - 543 4095 4095 - 543 4095 4095 - 543 4095 0 - 543 4095 36 - 543 4095 119 - 543 4095 242 - 543 4095 387 - 543 4095 543 - 543 4095 704 - 543 4095 858 - 543 4095 1006 - 543 4095 1152 - 543 4095 1303 - 543 4095 1469 - 543 4095 1656 - 543 4095 1865 - 543 4095 2102 - 543 4095 2375 - 543 4095 2677 - 543 4095 2991 - 543 4095 3295 - 543 4095 3588 - 543 4095 3852 - 543 4095 4057 - 543 4095 4095 - 543 4095 4095 - 543 4095 4095 - 543 4095 4095 - 543 4095 4095 - 543 4095 4095 - 543 4095 4095 - 543 4095 4095 - 543 4095 4095 - 543 4095 4095 - 543 4095 4095 - 543 4095 0 - 543 4095 36 - 543 4095 119 - 543 4095 242 - 543 4095 387 - 543 4095 543 - 543 4095 704 - 543 4095 858 - 543 4095 1006 - 543 4095 1152 - 543 4095 1303 - 543 4095 1469 - 543 4095 1656 - 543 4095 1865 - 543 4095 2102 - 543 4095 2375 - 543 4095 2677 - 543 4095 2991 - 543 4095 3295 - 543 4095 3588 - 543 4095 3852 - 543 4095 4057 - 543 4095 4095 - 543 4095 4095 - 543 4095 4095 - 543 4095 4095 - 543 4095 4095 - 543 4095 4095 - 543 4095 4095 - 543 4095 4095 - 543 4095 4095 - 543 4095 4095 - 543 4095 4095 - 543 4095 0 - 543 4095 36 - 543 4095 119 - 543 4095 242 - 543 4095 387 - 543 4095 543 - 543 4095 704 - 543 4095 858 - 543 4095 1006 - 543 4095 1152 - 543 4095 1303 - 543 4095 1469 - 543 4095 1656 - 543 4095 1865 - 543 4095 2102 - 543 4095 2375 - 543 4095 2677 - 543 4095 2991 - 543 4095 3295 - 543 4095 3588 - 543 4095 3852 - 543 4095 4057 - 543 4095 4095 - 543 4095 4095 - 543 4095 4095 - 543 4095 4095 - 543 4095 4095 - 543 4095 4095 - 543 4095 4095 - 543 4095 4095 - 543 4095 4095 - 543 4095 4095 - 543 4095 4095 - 543 4095 0 - 543 4095 36 - 543 4095 119 - 543 4095 242 - 543 4095 387 - 543 4095 543 - 543 4095 704 - 543 4095 858 - 543 4095 1006 - 543 4095 1152 - 543 4095 1303 - 543 4095 1469 - 543 4095 1656 - 543 4095 1865 - 543 4095 2102 - 543 4095 2375 - 543 4095 2677 - 543 4095 2991 - 543 4095 3295 - 543 4095 3588 - 543 4095 3852 - 543 4095 4057 - 543 4095 4095 - 543 4095 4095 - 543 4095 4095 - 543 4095 4095 - 543 4095 4095 - 543 4095 4095 - 543 4095 4095 - 543 4095 4095 - 543 4095 4095 - 543 4095 4095 - 543 4095 4095 - 543 4095 0 - 543 4095 36 - 543 4095 119 - 543 4095 242 - 543 4095 387 - 543 4095 543 - 543 4095 704 - 543 4095 858 - 543 4095 1006 - 543 4095 1152 - 543 4095 1303 - 543 4095 1469 - 543 4095 1656 - 543 4095 1865 - 543 4095 2102 - 543 4095 2375 - 543 4095 2677 - 543 4095 2991 - 543 4095 3295 - 543 4095 3588 - 543 4095 3852 - 543 4095 4057 - 543 4095 4095 - 543 4095 4095 - 543 4095 4095 - 543 4095 4095 - 543 4095 4095 - 543 4095 4095 - 543 4095 4095 - 543 4095 4095 - 543 4095 4095 - 543 4095 4095 - 543 4095 4095 - 543 4095 0 - 543 4095 36 - 543 4095 119 - 543 4095 242 - 543 4095 387 - 543 4095 543 - 543 4095 704 - 543 4095 858 - 543 4095 1006 - 543 4095 1152 - 543 4095 1303 - 543 4095 1469 - 543 4095 1656 - 543 4095 1865 - 543 4095 2102 - 543 4095 2375 - 543 4095 2677 - 543 4095 2991 - 543 4095 3295 - 543 4095 3588 - 543 4095 3852 - 543 4095 4057 - 543 4095 4095 - 543 4095 4095 - 543 4095 4095 - 543 4095 4095 - 543 4095 4095 - 543 4095 4095 - 543 4095 4095 - 543 4095 4095 - 543 4095 4095 - 543 4095 4095 - 543 4095 4095 - 543 4095 0 - 543 4095 36 - 543 4095 119 - 543 4095 242 - 543 4095 387 - 543 4095 543 - 543 4095 704 - 543 4095 858 - 543 4095 1006 - 543 4095 1152 - 543 4095 1303 - 543 4095 1469 - 543 4095 1656 - 543 4095 1865 - 543 4095 2102 - 543 4095 2375 - 543 4095 2677 - 543 4095 2991 - 543 4095 3295 - 543 4095 3588 - 543 4095 3852 - 543 4095 4057 - 543 4095 4095 - 543 4095 4095 - 543 4095 4095 - 543 4095 4095 - 543 4095 4095 - 543 4095 4095 - 543 4095 4095 - 543 4095 4095 - 543 4095 4095 - 543 4095 4095 - 543 4095 4095 - 543 4095 0 - 543 4095 36 - 543 4095 119 - 543 4095 242 - 543 4095 387 - 543 4095 543 - 543 4095 704 - 543 4095 858 - 543 4095 1006 - 543 4095 1152 - 543 4095 1303 - 543 4095 1469 - 543 4095 1656 - 543 4095 1865 - 543 4095 2102 - 543 4095 2375 - 543 4095 2677 - 543 4095 2991 - 543 4095 3295 - 543 4095 3588 - 543 4095 3852 - 543 4095 4057 - 543 4095 4095 - 543 4095 4095 - 543 4095 4095 - 543 4095 4095 - 543 4095 4095 - 543 4095 4095 - 543 4095 4095 - 543 4095 4095 - 543 4095 4095 - 543 4095 4095 - 543 4095 4095 - 543 4095 0 - 543 4095 36 - 543 4095 119 - 543 4095 242 - 543 4095 387 - 543 4095 543 - 543 4095 704 - 543 4095 858 - 543 4095 1006 - 543 4095 1152 - 543 4095 1303 - 543 4095 1469 - 543 4095 1656 - 543 4095 1865 - 543 4095 2102 - 543 4095 2375 - 543 4095 2677 - 543 4095 2991 - 543 4095 3295 - 543 4095 3588 - 543 4095 3852 - 543 4095 4057 - 543 4095 4095 - 543 4095 4095 - 543 4095 4095 - 543 4095 4095 - 543 4095 4095 - 543 4095 4095 - 543 4095 4095 - 543 4095 4095 - 543 4095 4095 - 543 4095 4095 - 543 4095 4095 - 480 1 1 - 481 1 79 - 485 1 159 - 492 0 243 - 501 1 331 - 513 1 425 - 526 1 525 - 542 2 631 - 558 2 744 - 574 1 863 - 592 1 991 - 611 0 1140 - 632 1 1314 - 653 1 1515 - 676 2 1747 - 698 2 2013 - 717 2 2310 - 733 0 2633 - 743 1 2979 - 752 3 3357 - 760 3 3765 - 766 2 4087 - 770 3 4095 - 771 0 4095 - 770 1 4095 - 766 3 4095 - 758 2 4095 - 745 3 4095 - 726 3 4095 - 708 2 4095 - 704 0 4095 - 704 0 4095 - 704 0 4095 - 491 81 1 - 492 81 81 - 496 81 163 - 502 82 248 - 511 84 338 - 522 85 433 - 535 88 533 - 549 90 640 - 564 92 753 - 580 95 872 - 597 98 1000 - 615 101 1149 - 635 104 1322 - 657 107 1523 - 678 110 1754 - 699 113 2018 - 718 116 2314 - 733 118 2636 - 744 119 2981 - 753 119 3359 - 760 119 3767 - 766 118 4087 - 770 116 4095 - 771 113 4095 - 770 109 4095 - 766 103 4095 - 758 94 4095 - 745 82 4095 - 726 65 4095 - 708 45 4095 - 704 36 4095 - 704 36 4095 - 704 36 4095 - 523 172 1 - 524 173 86 - 527 174 173 - 532 175 263 - 539 178 356 - 548 181 455 - 559 184 558 - 571 188 666 - 585 192 780 - 598 197 900 - 613 201 1028 - 630 206 1176 - 647 212 1348 - 667 218 1547 - 686 224 1775 - 705 230 2036 - 722 234 2328 - 735 238 2645 - 745 239 2988 - 754 240 3365 - 761 240 3771 - 766 239 4087 - 770 237 4095 - 771 232 4095 - 770 225 4095 - 765 215 4095 - 758 201 4095 - 744 181 4095 - 726 155 4095 - 708 128 4095 - 704 119 4095 - 704 119 4095 - 704 119 4095 - 567 282 1 - 567 282 93 - 569 283 187 - 573 285 283 - 579 287 383 - 586 291 486 - 594 295 593 - 604 299 705 - 614 304 821 - 626 310 941 - 638 315 1070 - 651 322 1217 - 666 329 1388 - 682 336 1584 - 699 344 1808 - 714 351 2064 - 728 357 2349 - 739 361 2660 - 747 364 3001 - 755 366 3375 - 762 366 3778 - 767 366 4087 - 770 363 4095 - 771 358 4095 - 770 351 4095 - 765 340 4095 - 757 324 4095 - 744 303 4095 - 725 275 4095 - 708 249 4095 - 704 242 4095 - 704 242 4095 - 704 242 4095 - 614 408 2 - 614 408 100 - 616 409 202 - 618 411 305 - 622 413 411 - 628 417 521 - 634 421 633 - 641 425 749 - 649 430 867 - 657 436 990 - 666 441 1119 - 677 448 1266 - 688 455 1435 - 700 463 1628 - 713 471 1848 - 725 478 2097 - 735 483 2373 - 743 488 2679 - 751 492 3017 - 757 495 3388 - 763 496 3789 - 768 497 4087 - 771 495 4095 - 771 492 4095 - 769 485 4095 - 765 475 4095 - 757 461 4095 - 743 441 4095 - 724 415 4095 - 708 392 4095 - 704 387 4095 - 704 387 4095 - 704 387 4095 - 658 548 2 - 658 548 107 - 659 549 215 - 661 550 326 - 664 553 438 - 667 555 554 - 672 559 671 - 677 563 791 - 682 567 913 - 688 572 1037 - 694 577 1167 - 702 583 1315 - 710 589 1482 - 718 596 1672 - 727 603 1886 - 734 609 2128 - 741 614 2399 - 748 619 2702 - 754 623 3037 - 760 627 3405 - 765 630 3801 - 769 632 4086 - 771 632 4095 - 771 630 4095 - 769 625 4095 - 764 617 4095 - 756 606 4095 - 742 589 4095 - 723 567 4095 - 707 548 4095 - 704 543 4095 - 704 543 4095 - 704 543 4095 - 695 696 2 - 695 697 113 - 696 697 227 - 697 698 343 - 699 700 461 - 701 702 581 - 704 705 704 - 707 708 827 - 710 711 952 - 714 715 1078 - 718 719 1209 - 722 723 1356 - 727 728 1521 - 732 733 1708 - 737 738 1919 - 742 743 2157 - 748 748 2426 - 753 753 2727 - 758 758 3060 - 763 763 3424 - 767 767 3815 - 770 770 4086 - 771 771 4095 - 771 771 4095 - 768 768 4095 - 763 763 4095 - 755 755 4095 - 741 741 4095 - 722 722 4095 - 707 707 4095 - 704 704 4095 - 704 704 4095 - 704 704 4095 - 722 846 2 - 722 847 117 - 723 847 234 - 723 848 355 - 724 849 477 - 726 850 601 - 727 852 727 - 729 854 853 - 731 856 980 - 733 859 1108 - 735 861 1239 - 737 864 1386 - 740 867 1551 - 743 871 1737 - 746 875 1946 - 750 879 2184 - 754 884 2453 - 758 889 2753 - 761 895 3083 - 765 900 3444 - 768 904 3831 - 771 908 4085 - 771 911 4095 - 771 912 4095 - 767 911 4095 - 762 908 4095 - 753 902 4095 - 739 889 4095 - 721 873 4095 - 706 861 4095 - 704 858 4095 - 704 858 4095 - 704 858 4095 - 739 993 2 - 739 993 118 - 740 993 238 - 740 994 361 - 740 994 486 - 741 995 613 - 742 996 742 - 743 998 870 - 744 999 998 - 745 1001 1128 - 746 1002 1260 - 747 1005 1408 - 749 1007 1574 - 751 1010 1761 - 754 1014 1971 - 756 1018 2210 - 759 1022 2479 - 762 1027 2779 - 765 1032 3107 - 767 1037 3464 - 770 1042 3846 - 771 1046 4084 - 771 1050 4095 - 770 1052 4095 - 766 1052 4095 - 761 1050 4095 - 751 1045 4095 - 737 1033 4095 - 719 1018 4095 - 705 1007 4095 - 704 1006 4095 - 704 1006 4095 - 704 1006 4095 - 750 1137 2 - 750 1137 119 - 750 1137 240 - 750 1138 364 - 751 1138 492 - 751 1139 621 - 752 1140 751 - 752 1141 882 - 753 1142 1012 - 754 1143 1143 - 754 1145 1278 - 755 1147 1427 - 757 1149 1595 - 758 1152 1783 - 760 1155 1994 - 761 1158 2234 - 763 1162 2504 - 765 1167 2804 - 768 1172 3130 - 769 1176 3484 - 771 1181 3861 - 771 1186 4083 - 771 1189 4095 - 769 1191 4095 - 765 1193 4095 - 759 1192 4095 - 749 1187 4095 - 734 1177 4095 - 717 1163 4095 - 705 1153 4095 - 704 1152 4095 - 704 1152 4095 - 704 1152 4095 - 758 1286 1 - 758 1286 119 - 758 1286 241 - 758 1286 366 - 759 1287 495 - 759 1287 626 - 759 1288 759 - 760 1289 892 - 760 1290 1024 - 761 1291 1156 - 761 1292 1292 - 762 1294 1443 - 763 1296 1612 - 763 1298 1802 - 765 1301 2015 - 766 1304 2257 - 767 1307 2528 - 768 1311 2828 - 770 1316 3153 - 771 1320 3504 - 771 1325 3876 - 771 1329 4082 - 770 1333 4095 - 768 1336 4095 - 764 1338 4095 - 757 1338 4095 - 747 1334 4095 - 732 1323 4095 - 715 1311 4095 - 704 1303 4095 - 704 1303 4095 - 704 1303 4095 - 704 1303 4095 - 765 1452 2 - 765 1452 118 - 765 1452 240 - 765 1452 366 - 765 1452 497 - 765 1453 630 - 765 1453 765 - 765 1454 900 - 766 1455 1034 - 766 1456 1168 - 766 1457 1305 - 767 1458 1458 - 767 1460 1629 - 768 1462 1820 - 768 1464 2035 - 769 1467 2279 - 770 1470 2552 - 770 1473 2853 - 771 1477 3177 - 771 1482 3525 - 771 1486 3890 - 771 1490 4081 - 769 1494 4095 - 766 1497 4095 - 762 1500 4095 - 754 1501 4095 - 743 1496 4095 - 728 1487 4095 - 713 1475 4095 - 704 1470 4095 - 704 1469 4095 - 704 1469 4095 - 704 1469 4095 - 769 1637 1 - 769 1638 117 - 769 1638 238 - 769 1638 364 - 769 1638 496 - 769 1638 632 - 769 1639 769 - 769 1640 906 - 770 1640 1042 - 770 1641 1177 - 770 1642 1317 - 770 1643 1471 - 770 1644 1644 - 770 1646 1837 - 771 1648 2054 - 771 1650 2301 - 771 1653 2576 - 771 1656 2878 - 771 1659 3201 - 771 1663 3545 - 770 1667 3903 - 769 1671 4079 - 767 1675 4095 - 763 1679 4095 - 758 1682 4095 - 751 1682 4095 - 739 1678 4095 - 724 1669 4095 - 710 1660 4095 - 704 1656 4095 - 704 1656 4095 - 704 1656 4095 - 704 1656 4095 - 771 1846 2 - 771 1846 114 - 771 1846 233 - 771 1846 360 - 771 1847 494 - 771 1847 631 - 771 1847 771 - 771 1848 910 - 771 1848 1048 - 771 1849 1185 - 771 1850 1326 - 771 1850 1482 - 771 1851 1657 - 771 1853 1852 - 771 1854 2072 - 771 1856 2321 - 771 1859 2600 - 771 1861 2904 - 770 1864 3225 - 769 1867 3565 - 768 1871 3914 - 766 1875 4077 - 764 1880 4095 - 760 1884 4095 - 754 1887 4095 - 745 1886 4095 - 733 1881 4095 - 719 1874 4095 - 707 1867 4095 - 704 1865 4095 - 704 1865 4095 - 704 1865 4095 - 704 1865 4095 - 771 2081 3 - 771 2081 110 - 771 2081 227 - 771 2081 354 - 771 2082 488 - 771 2082 628 - 771 2082 771 - 771 2082 912 - 771 2083 1051 - 770 2083 1190 - 770 2084 1333 - 770 2085 1491 - 770 2086 1668 - 770 2087 1866 - 770 2088 2088 - 769 2089 2341 - 769 2091 2622 - 768 2094 2928 - 767 2097 3249 - 766 2100 3584 - 764 2104 3925 - 762 2109 4075 - 759 2113 4095 - 754 2116 4095 - 748 2118 4095 - 738 2116 4095 - 726 2112 4095 - 714 2106 4095 - 705 2102 4095 - 704 2102 4095 - 704 2102 4095 - 704 2102 4095 - 704 2102 4095 - 767 2351 2 - 767 2351 105 - 767 2351 218 - 767 2351 344 - 767 2351 479 - 767 2351 621 - 767 2352 767 - 767 2352 910 - 767 2353 1051 - 766 2353 1192 - 766 2354 1337 - 766 2354 1497 - 766 2355 1676 - 766 2356 1876 - 765 2358 2102 - 765 2359 2359 - 764 2361 2645 - 763 2364 2953 - 762 2367 3273 - 761 2370 3602 - 758 2373 3926 - 756 2377 4071 - 752 2380 4095 - 746 2383 4095 - 739 2383 4095 - 729 2382 4095 - 719 2379 4095 - 709 2376 4095 - 704 2375 4095 - 704 2375 4095 - 704 2375 4095 - 704 2375 4095 - 704 2375 4095 - 760 2657 3 - 760 2657 97 - 760 2657 205 - 760 2657 330 - 760 2657 467 - 760 2657 612 - 760 2658 760 - 760 2658 907 - 760 2658 1049 - 760 2659 1192 - 759 2659 1338 - 759 2660 1501 - 759 2660 1682 - 758 2661 1885 - 758 2662 2114 - 757 2664 2375 - 756 2665 2665 - 755 2667 2976 - 754 2669 3292 - 752 2671 3613 - 749 2674 3915 - 745 2676 4068 - 741 2678 4095 - 735 2679 4095 - 728 2679 4095 - 719 2678 4095 - 711 2677 4095 - 705 2677 4095 - 704 2677 4095 - 704 2677 4095 - 704 2677 4095 - 704 2677 4095 - 704 2677 4095 - 749 2984 2 - 749 2984 86 - 749 2984 187 - 749 2984 310 - 748 2984 448 - 748 2984 596 - 748 2984 748 - 748 2985 897 - 748 2985 1042 - 748 2985 1186 - 747 2985 1334 - 747 2985 1498 - 747 2986 1681 - 746 2986 1886 - 745 2987 2118 - 744 2987 2383 - 743 2988 2677 - 742 2989 2989 - 740 2989 3301 - 738 2990 3612 - 735 2991 3896 - 731 2991 4064 - 727 2992 4095 - 721 2991 4095 - 716 2991 4095 - 710 2991 4095 - 705 2991 4095 - 704 2991 4095 - 704 2991 4095 - 704 2991 4095 - 704 2991 4095 - 704 2991 4095 - 704 2991 4095 - 731 3301 2 - 731 3301 70 - 731 3301 163 - 731 3301 284 - 731 3301 424 - 731 3301 575 - 730 3300 730 - 730 3300 882 - 730 3300 1028 - 730 3300 1173 - 730 3300 1322 - 729 3300 1487 - 729 3300 1672 - 728 3300 1879 - 728 3300 2112 - 727 3300 2381 - 726 3300 2679 - 724 3299 2991 - 723 3299 3299 - 721 3298 3600 - 718 3298 3872 - 716 3297 4060 - 712 3296 4095 - 709 3295 4095 - 706 3295 4095 - 704 3295 4095 - 704 3295 4095 - 704 3295 4095 - 704 3295 4095 - 704 3295 4095 - 704 3295 4095 - 704 3295 4095 - 704 3295 4095 - 712 3593 0 - 712 3593 50 - 712 3593 135 - 712 3593 256 - 712 3593 398 - 712 3593 553 - 712 3593 712 - 712 3593 865 - 711 3593 1012 - 711 3592 1158 - 711 3592 1308 - 711 3592 1474 - 711 3592 1660 - 710 3592 1868 - 710 3591 2104 - 709 3591 2376 - 709 3591 2677 - 708 3590 2991 - 707 3590 3295 - 707 3589 3589 - 706 3589 3854 - 705 3588 4058 - 704 3588 4095 - 704 3588 4095 - 704 3588 4095 - 704 3588 4095 - 704 3588 4095 - 704 3588 4095 - 704 3588 4095 - 704 3588 4095 - 704 3588 4095 - 704 3588 4095 - 704 3588 4095 - 704 3852 0 - 704 3852 37 - 704 3852 120 - 704 3852 242 - 704 3852 387 - 704 3852 543 - 704 3852 704 - 704 3852 859 - 704 3852 1006 - 704 3852 1152 - 704 3852 1303 - 704 3852 1469 - 704 3852 1656 - 704 3852 1865 - 704 3852 2102 - 704 3852 2375 - 704 3852 2677 - 704 3852 2991 - 704 3852 3295 - 704 3852 3588 - 704 3852 3852 - 704 3852 4057 - 704 3852 4095 - 704 3852 4095 - 704 3852 4095 - 704 3852 4095 - 704 3852 4095 - 704 3852 4095 - 704 3852 4095 - 704 3852 4095 - 704 3852 4095 - 704 3852 4095 - 704 3852 4095 - 704 4057 0 - 704 4057 36 - 704 4057 119 - 704 4057 242 - 704 4057 387 - 704 4057 543 - 704 4057 704 - 704 4057 858 - 704 4057 1006 - 704 4057 1152 - 704 4057 1303 - 704 4057 1469 - 704 4057 1656 - 704 4057 1865 - 704 4057 2102 - 704 4057 2375 - 704 4057 2677 - 704 4057 2991 - 704 4057 3295 - 704 4057 3588 - 704 4057 3852 - 704 4057 4057 - 704 4057 4095 - 704 4057 4095 - 704 4057 4095 - 704 4057 4095 - 704 4057 4095 - 704 4057 4095 - 704 4057 4095 - 704 4057 4095 - 704 4057 4095 - 704 4057 4095 - 704 4057 4095 - 704 4095 0 - 704 4095 36 - 704 4095 119 - 704 4095 242 - 704 4095 387 - 704 4095 543 - 704 4095 704 - 704 4095 858 - 704 4095 1006 - 704 4095 1152 - 704 4095 1303 - 704 4095 1469 - 704 4095 1656 - 704 4095 1865 - 704 4095 2102 - 704 4095 2375 - 704 4095 2677 - 704 4095 2991 - 704 4095 3295 - 704 4095 3588 - 704 4095 3852 - 704 4095 4057 - 704 4095 4095 - 704 4095 4095 - 704 4095 4095 - 704 4095 4095 - 704 4095 4095 - 704 4095 4095 - 704 4095 4095 - 704 4095 4095 - 704 4095 4095 - 704 4095 4095 - 704 4095 4095 - 704 4095 0 - 704 4095 36 - 704 4095 119 - 704 4095 242 - 704 4095 387 - 704 4095 543 - 704 4095 704 - 704 4095 858 - 704 4095 1006 - 704 4095 1152 - 704 4095 1303 - 704 4095 1469 - 704 4095 1656 - 704 4095 1865 - 704 4095 2102 - 704 4095 2375 - 704 4095 2677 - 704 4095 2991 - 704 4095 3295 - 704 4095 3588 - 704 4095 3852 - 704 4095 4057 - 704 4095 4095 - 704 4095 4095 - 704 4095 4095 - 704 4095 4095 - 704 4095 4095 - 704 4095 4095 - 704 4095 4095 - 704 4095 4095 - 704 4095 4095 - 704 4095 4095 - 704 4095 4095 - 704 4095 0 - 704 4095 36 - 704 4095 119 - 704 4095 242 - 704 4095 387 - 704 4095 543 - 704 4095 704 - 704 4095 858 - 704 4095 1006 - 704 4095 1152 - 704 4095 1303 - 704 4095 1469 - 704 4095 1656 - 704 4095 1865 - 704 4095 2102 - 704 4095 2375 - 704 4095 2677 - 704 4095 2991 - 704 4095 3295 - 704 4095 3588 - 704 4095 3852 - 704 4095 4057 - 704 4095 4095 - 704 4095 4095 - 704 4095 4095 - 704 4095 4095 - 704 4095 4095 - 704 4095 4095 - 704 4095 4095 - 704 4095 4095 - 704 4095 4095 - 704 4095 4095 - 704 4095 4095 - 704 4095 0 - 704 4095 36 - 704 4095 119 - 704 4095 242 - 704 4095 387 - 704 4095 543 - 704 4095 704 - 704 4095 858 - 704 4095 1006 - 704 4095 1152 - 704 4095 1303 - 704 4095 1469 - 704 4095 1656 - 704 4095 1865 - 704 4095 2102 - 704 4095 2375 - 704 4095 2677 - 704 4095 2991 - 704 4095 3295 - 704 4095 3588 - 704 4095 3852 - 704 4095 4057 - 704 4095 4095 - 704 4095 4095 - 704 4095 4095 - 704 4095 4095 - 704 4095 4095 - 704 4095 4095 - 704 4095 4095 - 704 4095 4095 - 704 4095 4095 - 704 4095 4095 - 704 4095 4095 - 704 4095 0 - 704 4095 36 - 704 4095 119 - 704 4095 242 - 704 4095 387 - 704 4095 543 - 704 4095 704 - 704 4095 858 - 704 4095 1006 - 704 4095 1152 - 704 4095 1303 - 704 4095 1469 - 704 4095 1656 - 704 4095 1865 - 704 4095 2102 - 704 4095 2375 - 704 4095 2677 - 704 4095 2991 - 704 4095 3295 - 704 4095 3588 - 704 4095 3852 - 704 4095 4057 - 704 4095 4095 - 704 4095 4095 - 704 4095 4095 - 704 4095 4095 - 704 4095 4095 - 704 4095 4095 - 704 4095 4095 - 704 4095 4095 - 704 4095 4095 - 704 4095 4095 - 704 4095 4095 - 704 4095 0 - 704 4095 36 - 704 4095 119 - 704 4095 242 - 704 4095 387 - 704 4095 543 - 704 4095 704 - 704 4095 858 - 704 4095 1006 - 704 4095 1152 - 704 4095 1303 - 704 4095 1469 - 704 4095 1656 - 704 4095 1865 - 704 4095 2102 - 704 4095 2375 - 704 4095 2677 - 704 4095 2991 - 704 4095 3295 - 704 4095 3588 - 704 4095 3852 - 704 4095 4057 - 704 4095 4095 - 704 4095 4095 - 704 4095 4095 - 704 4095 4095 - 704 4095 4095 - 704 4095 4095 - 704 4095 4095 - 704 4095 4095 - 704 4095 4095 - 704 4095 4095 - 704 4095 4095 - 704 4095 0 - 704 4095 36 - 704 4095 119 - 704 4095 242 - 704 4095 387 - 704 4095 543 - 704 4095 704 - 704 4095 858 - 704 4095 1006 - 704 4095 1152 - 704 4095 1303 - 704 4095 1469 - 704 4095 1656 - 704 4095 1865 - 704 4095 2102 - 704 4095 2375 - 704 4095 2677 - 704 4095 2991 - 704 4095 3295 - 704 4095 3588 - 704 4095 3852 - 704 4095 4057 - 704 4095 4095 - 704 4095 4095 - 704 4095 4095 - 704 4095 4095 - 704 4095 4095 - 704 4095 4095 - 704 4095 4095 - 704 4095 4095 - 704 4095 4095 - 704 4095 4095 - 704 4095 4095 - 704 4095 0 - 704 4095 36 - 704 4095 119 - 704 4095 242 - 704 4095 387 - 704 4095 543 - 704 4095 704 - 704 4095 858 - 704 4095 1006 - 704 4095 1152 - 704 4095 1303 - 704 4095 1469 - 704 4095 1656 - 704 4095 1865 - 704 4095 2102 - 704 4095 2375 - 704 4095 2677 - 704 4095 2991 - 704 4095 3295 - 704 4095 3588 - 704 4095 3852 - 704 4095 4057 - 704 4095 4095 - 704 4095 4095 - 704 4095 4095 - 704 4095 4095 - 704 4095 4095 - 704 4095 4095 - 704 4095 4095 - 704 4095 4095 - 704 4095 4095 - 704 4095 4095 - 704 4095 4095 - 704 4095 0 - 704 4095 36 - 704 4095 119 - 704 4095 242 - 704 4095 387 - 704 4095 543 - 704 4095 704 - 704 4095 858 - 704 4095 1006 - 704 4095 1152 - 704 4095 1303 - 704 4095 1469 - 704 4095 1656 - 704 4095 1865 - 704 4095 2102 - 704 4095 2375 - 704 4095 2677 - 704 4095 2991 - 704 4095 3295 - 704 4095 3588 - 704 4095 3852 - 704 4095 4057 - 704 4095 4095 - 704 4095 4095 - 704 4095 4095 - 704 4095 4095 - 704 4095 4095 - 704 4095 4095 - 704 4095 4095 - 704 4095 4095 - 704 4095 4095 - 704 4095 4095 - 704 4095 4095 - 704 4095 0 - 704 4095 36 - 704 4095 119 - 704 4095 242 - 704 4095 387 - 704 4095 543 - 704 4095 704 - 704 4095 858 - 704 4095 1006 - 704 4095 1152 - 704 4095 1303 - 704 4095 1469 - 704 4095 1656 - 704 4095 1865 - 704 4095 2102 - 704 4095 2375 - 704 4095 2677 - 704 4095 2991 - 704 4095 3295 - 704 4095 3588 - 704 4095 3852 - 704 4095 4057 - 704 4095 4095 - 704 4095 4095 - 704 4095 4095 - 704 4095 4095 - 704 4095 4095 - 704 4095 4095 - 704 4095 4095 - 704 4095 4095 - 704 4095 4095 - 704 4095 4095 - 704 4095 4095 - 704 4095 0 - 704 4095 36 - 704 4095 119 - 704 4095 242 - 704 4095 387 - 704 4095 543 - 704 4095 704 - 704 4095 858 - 704 4095 1006 - 704 4095 1152 - 704 4095 1303 - 704 4095 1469 - 704 4095 1656 - 704 4095 1865 - 704 4095 2102 - 704 4095 2375 - 704 4095 2677 - 704 4095 2991 - 704 4095 3295 - 704 4095 3588 - 704 4095 3852 - 704 4095 4057 - 704 4095 4095 - 704 4095 4095 - 704 4095 4095 - 704 4095 4095 - 704 4095 4095 - 704 4095 4095 - 704 4095 4095 - 704 4095 4095 - 704 4095 4095 - 704 4095 4095 - 704 4095 4095 - 623 1 2 - 624 1 87 - 627 1 176 - 632 0 267 - 640 1 362 - 650 1 462 - 662 1 566 - 676 1 675 - 691 2 789 - 706 1 909 - 723 0 1037 - 741 0 1185 - 762 1 1356 - 783 0 1555 - 806 2 1782 - 828 2 2042 - 847 2 2332 - 862 1 2648 - 874 1 2991 - 885 3 3367 - 894 3 3772 - 902 2 4087 - 907 3 4095 - 911 2 4095 - 912 3 4095 - 910 0 4095 - 905 3 4095 - 894 3 4095 - 878 2 4095 - 862 2 4095 - 858 0 4095 - 858 0 4095 - 858 0 4095 - 632 89 1 - 633 89 89 - 636 89 178 - 641 90 271 - 649 91 367 - 658 92 467 - 670 94 572 - 683 95 682 - 697 98 796 - 712 100 916 - 728 102 1044 - 746 104 1192 - 766 107 1363 - 787 109 1561 - 809 112 1788 - 830 115 2047 - 848 117 2336 - 863 118 2651 - 874 119 2993 - 885 119 3368 - 894 119 3774 - 902 118 4087 - 908 116 4095 - 911 113 4095 - 912 109 4095 - 910 103 4095 - 905 94 4095 - 894 82 4095 - 878 65 4095 - 862 44 4095 - 858 36 4095 - 858 36 4095 - 858 36 4095 - 659 186 1 - 660 186 92 - 663 187 186 - 667 188 282 - 674 190 381 - 682 192 484 - 692 195 591 - 704 198 703 - 716 201 818 - 729 205 939 - 744 208 1067 - 760 213 1214 - 778 217 1385 - 797 222 1581 - 816 227 1806 - 835 232 2062 - 852 236 2348 - 865 238 2659 - 876 240 3000 - 886 241 3374 - 895 240 3778 - 902 239 4087 - 908 236 4095 - 911 232 4095 - 912 224 4095 - 910 214 4095 - 905 200 4095 - 894 181 4095 - 877 155 4095 - 862 128 4095 - 858 119 4095 - 858 119 4095 - 858 119 4095 - 699 297 1 - 700 297 98 - 702 298 197 - 706 299 298 - 711 301 402 - 717 304 509 - 725 307 620 - 735 311 734 - 745 315 852 - 756 320 973 - 768 324 1102 - 781 330 1249 - 796 336 1419 - 812 342 1613 - 829 348 1835 - 844 354 2086 - 858 359 2365 - 869 362 2672 - 879 364 3011 - 888 366 3383 - 896 366 3785 - 903 365 4087 - 908 363 4095 - 911 358 4095 - 912 350 4095 - 910 339 4095 - 905 324 4095 - 893 302 4095 - 877 275 4095 - 862 249 4095 - 858 242 4095 - 858 242 4095 - 858 242 4095 - 744 422 2 - 745 423 104 - 746 424 209 - 749 425 316 - 753 427 425 - 758 430 538 - 764 433 653 - 771 437 770 - 779 441 891 - 787 446 1014 - 796 451 1144 - 807 456 1291 - 818 462 1459 - 830 469 1651 - 843 475 1868 - 854 481 2113 - 864 485 2386 - 874 489 2690 - 882 492 3027 - 891 495 3396 - 898 497 3795 - 904 497 4087 - 909 495 4095 - 912 491 4095 - 912 484 4095 - 909 474 4095 - 904 460 4095 - 893 440 4095 - 876 415 4095 - 862 392 4095 - 858 387 4095 - 858 387 4095 - 858 387 4095 - 788 561 2 - 788 561 110 - 789 562 220 - 791 563 333 - 794 565 448 - 797 567 565 - 802 570 685 - 807 573 806 - 812 577 929 - 818 581 1055 - 824 585 1185 - 832 590 1332 - 840 595 1499 - 848 601 1687 - 856 606 1900 - 864 611 2140 - 872 616 2410 - 879 620 2712 - 887 624 3046 - 894 628 3412 - 900 631 3807 - 906 632 4086 - 910 632 4095 - 912 630 4095 - 911 625 4095 - 909 617 4095 - 903 605 4095 - 892 588 4095 - 875 566 4095 - 861 548 4095 - 858 543 4095 - 858 543 4095 - 858 543 4095 - 825 706 2 - 825 706 114 - 826 707 230 - 827 708 347 - 829 709 467 - 831 711 589 - 834 713 712 - 837 716 837 - 840 719 962 - 844 722 1089 - 848 725 1220 - 852 729 1367 - 857 732 1532 - 862 737 1718 - 868 741 1928 - 873 745 2166 - 879 750 2435 - 885 755 2735 - 891 759 3067 - 897 764 3430 - 903 767 3820 - 907 770 4086 - 910 772 4095 - 912 771 4095 - 911 768 4095 - 909 763 4095 - 902 754 4095 - 891 740 4095 - 874 722 4095 - 861 707 4095 - 858 704 4095 - 858 704 4095 - 858 704 4095 - 852 853 2 - 852 853 117 - 853 853 236 - 853 854 357 - 854 855 480 - 856 856 605 - 857 858 732 - 859 859 859 - 861 861 986 - 863 863 1114 - 865 865 1246 - 867 868 1393 - 870 871 1558 - 874 874 1744 - 877 878 1953 - 881 882 2191 - 886 886 2460 - 891 891 2760 - 896 896 3089 - 900 901 3449 - 905 905 3835 - 909 909 4085 - 911 911 4095 - 912 912 4095 - 911 911 4095 - 908 908 4095 - 901 901 4095 - 889 889 4095 - 873 873 4095 - 860 860 4095 - 858 858 4095 - 858 858 4095 - 858 858 4095 - 870 997 2 - 870 997 119 - 870 997 239 - 870 998 362 - 871 998 488 - 871 999 615 - 872 1000 744 - 873 1001 873 - 874 1002 1002 - 876 1004 1131 - 877 1006 1265 - 879 1008 1413 - 881 1010 1579 - 883 1013 1766 - 886 1016 1977 - 889 1020 2216 - 892 1024 2485 - 896 1029 2784 - 900 1033 3112 - 904 1038 3469 - 907 1043 3850 - 910 1047 4084 - 912 1050 4095 - 912 1052 4095 - 910 1052 4095 - 907 1050 4095 - 900 1044 4095 - 887 1033 4095 - 872 1018 4095 - 860 1007 4095 - 858 1006 4095 - 858 1006 4095 - 858 1006 4095 - 882 1140 2 - 882 1140 119 - 882 1141 240 - 882 1141 365 - 883 1141 492 - 883 1142 622 - 884 1143 753 - 884 1144 884 - 885 1145 1015 - 886 1146 1146 - 887 1148 1281 - 888 1149 1430 - 890 1151 1598 - 891 1154 1786 - 893 1157 1998 - 896 1160 2239 - 898 1164 2509 - 901 1168 2808 - 904 1173 3135 - 907 1177 3488 - 909 1182 3864 - 911 1186 4083 - 912 1190 4095 - 911 1192 4095 - 910 1193 4095 - 906 1192 4095 - 898 1187 4095 - 885 1176 4095 - 870 1162 4095 - 859 1153 4095 - 858 1152 4095 - 858 1152 4095 - 858 1152 4095 - 892 1288 1 - 892 1289 119 - 892 1289 240 - 892 1289 366 - 892 1289 495 - 892 1290 627 - 893 1291 760 - 893 1291 893 - 894 1292 1026 - 894 1293 1158 - 895 1295 1294 - 896 1296 1446 - 897 1298 1615 - 898 1300 1805 - 900 1302 2018 - 901 1305 2260 - 903 1309 2532 - 905 1313 2832 - 907 1317 3157 - 909 1321 3508 - 911 1326 3878 - 912 1330 4082 - 912 1333 4095 - 911 1336 4095 - 909 1338 4095 - 904 1338 4095 - 896 1333 4095 - 883 1323 4095 - 868 1311 4095 - 859 1303 4095 - 858 1303 4095 - 858 1303 4095 - 858 1303 4095 - 900 1454 2 - 900 1454 118 - 900 1454 240 - 900 1454 366 - 900 1454 497 - 900 1455 630 - 901 1455 766 - 901 1456 901 - 901 1457 1035 - 902 1458 1169 - 902 1459 1307 - 903 1460 1460 - 903 1461 1631 - 904 1463 1822 - 905 1465 2038 - 906 1468 2282 - 907 1471 2555 - 908 1474 2856 - 910 1478 3180 - 911 1482 3528 - 912 1487 3892 - 912 1491 4081 - 911 1494 4095 - 910 1498 4095 - 907 1500 4095 - 902 1500 4095 - 893 1496 4095 - 880 1486 4095 - 866 1475 4095 - 859 1470 4095 - 858 1469 4095 - 858 1469 4095 - 858 1469 4095 - 906 1639 1 - 906 1639 117 - 906 1639 237 - 906 1640 364 - 906 1640 496 - 906 1640 632 - 907 1641 770 - 907 1641 907 - 907 1642 1042 - 907 1642 1178 - 907 1643 1318 - 908 1644 1472 - 908 1646 1645 - 909 1647 1839 - 909 1649 2056 - 910 1651 2303 - 910 1654 2579 - 911 1657 2881 - 911 1660 3204 - 912 1664 3547 - 912 1668 3904 - 911 1671 4079 - 910 1676 4095 - 909 1680 4095 - 905 1683 4095 - 899 1682 4095 - 889 1678 4095 - 876 1669 4095 - 864 1660 4095 - 859 1656 4095 - 858 1656 4095 - 858 1656 4095 - 858 1656 4095 - 910 1847 2 - 910 1847 114 - 910 1848 233 - 910 1848 360 - 910 1848 493 - 910 1848 631 - 910 1849 771 - 911 1849 911 - 911 1850 1048 - 911 1850 1186 - 911 1851 1327 - 911 1852 1483 - 911 1853 1658 - 911 1854 1854 - 911 1855 2073 - 912 1857 2323 - 912 1859 2602 - 912 1862 2906 - 912 1865 3227 - 912 1868 3566 - 911 1872 3915 - 910 1876 4077 - 909 1881 4095 - 906 1885 4095 - 902 1887 4095 - 895 1886 4095 - 884 1881 4095 - 872 1873 4095 - 862 1867 4095 - 858 1865 4095 - 858 1865 4095 - 858 1865 4095 - 858 1865 4095 - 912 2082 3 - 912 2082 110 - 912 2082 227 - 912 2082 353 - 912 2083 488 - 912 2083 628 - 912 2083 770 - 912 2084 912 - 912 2084 1051 - 912 2084 1190 - 912 2085 1333 - 912 2086 1492 - 912 2086 1668 - 912 2088 1866 - 912 2089 2089 - 912 2090 2342 - 911 2092 2624 - 911 2094 2930 - 911 2097 3250 - 910 2101 3585 - 909 2105 3925 - 908 2109 4074 - 906 2113 4095 - 902 2116 4095 - 897 2118 4095 - 889 2116 4095 - 878 2112 4095 - 867 2106 4095 - 860 2102 4095 - 858 2102 4095 - 858 2102 4095 - 858 2102 4095 - 858 2102 4095 - 911 2352 0 - 911 2352 104 - 910 2352 217 - 910 2352 343 - 910 2352 479 - 910 2353 621 - 910 2353 766 - 910 2353 910 - 910 2354 1051 - 910 2354 1192 - 910 2355 1337 - 910 2355 1497 - 910 2356 1676 - 910 2357 1877 - 910 2358 2102 - 909 2360 2360 - 909 2362 2646 - 908 2365 2955 - 908 2367 3274 - 907 2371 3603 - 905 2374 3926 - 903 2378 4071 - 900 2381 4095 - 895 2383 4095 - 889 2383 4095 - 881 2382 4095 - 871 2379 4095 - 863 2376 4095 - 859 2375 4095 - 858 2375 4095 - 858 2375 4095 - 858 2375 4095 - 858 2375 4095 - 907 2658 3 - 907 2658 97 - 907 2658 205 - 907 2658 329 - 907 2658 466 - 906 2658 611 - 906 2659 760 - 906 2659 906 - 906 2659 1049 - 906 2660 1192 - 906 2660 1338 - 906 2661 1501 - 906 2661 1682 - 905 2662 1885 - 905 2663 2114 - 904 2664 2375 - 904 2666 2666 - 903 2668 2976 - 901 2670 3293 - 900 2672 3614 - 898 2674 3914 - 895 2676 4068 - 891 2678 4095 - 886 2679 4095 - 879 2679 4095 - 872 2678 4095 - 864 2677 4095 - 859 2677 4095 - 858 2677 4095 - 858 2677 4095 - 858 2677 4095 - 858 2677 4095 - 858 2677 4095 - 897 2984 2 - 897 2984 85 - 897 2985 187 - 897 2985 309 - 897 2985 448 - 897 2985 596 - 897 2985 748 - 897 2985 897 - 897 2985 1042 - 897 2985 1186 - 896 2986 1334 - 896 2986 1498 - 896 2986 1681 - 895 2987 1886 - 895 2987 2117 - 894 2988 2383 - 893 2988 2677 - 892 2989 2989 - 890 2990 3301 - 888 2990 3612 - 886 2991 3895 - 882 2991 4064 - 878 2992 4095 - 874 2991 4095 - 869 2991 4095 - 863 2991 4095 - 860 2991 4095 - 858 2991 4095 - 858 2991 4095 - 858 2991 4095 - 858 2991 4095 - 858 2991 4095 - 858 2991 4095 - 882 3300 2 - 882 3300 69 - 882 3300 162 - 882 3300 283 - 882 3300 423 - 882 3300 575 - 882 3300 730 - 882 3300 882 - 881 3300 1027 - 881 3300 1173 - 881 3300 1322 - 881 3300 1487 - 880 3300 1672 - 880 3300 1878 - 879 3300 2112 - 878 3300 2381 - 878 3300 2679 - 876 3299 2991 - 875 3299 3299 - 873 3298 3600 - 871 3298 3872 - 869 3297 4060 - 866 3296 4095 - 863 3295 4095 - 860 3295 4095 - 859 3295 4095 - 858 3295 4095 - 858 3295 4095 - 858 3295 4095 - 858 3295 4095 - 858 3295 4095 - 858 3295 4095 - 858 3295 4095 - 865 3593 1 - 865 3593 49 - 865 3593 134 - 865 3593 255 - 865 3593 398 - 865 3593 553 - 865 3592 711 - 865 3592 865 - 865 3592 1012 - 865 3592 1158 - 865 3592 1308 - 865 3592 1474 - 864 3592 1660 - 864 3592 1868 - 864 3591 2104 - 863 3591 2376 - 863 3591 2677 - 862 3590 2991 - 862 3590 3295 - 861 3589 3589 - 860 3588 3854 - 859 3588 4058 - 859 3588 4095 - 859 3588 4095 - 858 3588 4095 - 858 3588 4095 - 858 3588 4095 - 858 3588 4095 - 858 3588 4095 - 858 3588 4095 - 858 3588 4095 - 858 3588 4095 - 858 3588 4095 - 859 3852 1 - 859 3852 37 - 859 3852 120 - 859 3852 242 - 859 3852 387 - 859 3852 543 - 859 3852 704 - 858 3852 858 - 858 3852 1006 - 858 3852 1152 - 858 3852 1303 - 858 3852 1469 - 858 3852 1656 - 858 3852 1865 - 858 3852 2102 - 858 3852 2375 - 858 3852 2677 - 858 3852 2991 - 858 3852 3295 - 858 3852 3588 - 858 3852 3852 - 858 3852 4057 - 858 3852 4095 - 858 3852 4095 - 858 3852 4095 - 858 3852 4095 - 858 3852 4095 - 858 3852 4095 - 858 3852 4095 - 858 3852 4095 - 858 3852 4095 - 858 3852 4095 - 858 3852 4095 - 858 4057 0 - 858 4057 36 - 858 4057 119 - 858 4057 242 - 858 4057 387 - 858 4057 543 - 858 4057 704 - 858 4057 858 - 858 4057 1006 - 858 4057 1152 - 858 4057 1303 - 858 4057 1469 - 858 4057 1656 - 858 4057 1865 - 858 4057 2102 - 858 4057 2375 - 858 4057 2677 - 858 4057 2991 - 858 4057 3295 - 858 4057 3588 - 858 4057 3852 - 858 4057 4057 - 858 4057 4095 - 858 4057 4095 - 858 4057 4095 - 858 4057 4095 - 858 4057 4095 - 858 4057 4095 - 858 4057 4095 - 858 4057 4095 - 858 4057 4095 - 858 4057 4095 - 858 4057 4095 - 858 4095 0 - 858 4095 36 - 858 4095 119 - 858 4095 242 - 858 4095 387 - 858 4095 543 - 858 4095 704 - 858 4095 858 - 858 4095 1006 - 858 4095 1152 - 858 4095 1303 - 858 4095 1469 - 858 4095 1656 - 858 4095 1865 - 858 4095 2102 - 858 4095 2375 - 858 4095 2677 - 858 4095 2991 - 858 4095 3295 - 858 4095 3588 - 858 4095 3852 - 858 4095 4057 - 858 4095 4095 - 858 4095 4095 - 858 4095 4095 - 858 4095 4095 - 858 4095 4095 - 858 4095 4095 - 858 4095 4095 - 858 4095 4095 - 858 4095 4095 - 858 4095 4095 - 858 4095 4095 - 858 4095 0 - 858 4095 36 - 858 4095 119 - 858 4095 242 - 858 4095 387 - 858 4095 543 - 858 4095 704 - 858 4095 858 - 858 4095 1006 - 858 4095 1152 - 858 4095 1303 - 858 4095 1469 - 858 4095 1656 - 858 4095 1865 - 858 4095 2102 - 858 4095 2375 - 858 4095 2677 - 858 4095 2991 - 858 4095 3295 - 858 4095 3588 - 858 4095 3852 - 858 4095 4057 - 858 4095 4095 - 858 4095 4095 - 858 4095 4095 - 858 4095 4095 - 858 4095 4095 - 858 4095 4095 - 858 4095 4095 - 858 4095 4095 - 858 4095 4095 - 858 4095 4095 - 858 4095 4095 - 858 4095 0 - 858 4095 36 - 858 4095 119 - 858 4095 242 - 858 4095 387 - 858 4095 543 - 858 4095 704 - 858 4095 858 - 858 4095 1006 - 858 4095 1152 - 858 4095 1303 - 858 4095 1469 - 858 4095 1656 - 858 4095 1865 - 858 4095 2102 - 858 4095 2375 - 858 4095 2677 - 858 4095 2991 - 858 4095 3295 - 858 4095 3588 - 858 4095 3852 - 858 4095 4057 - 858 4095 4095 - 858 4095 4095 - 858 4095 4095 - 858 4095 4095 - 858 4095 4095 - 858 4095 4095 - 858 4095 4095 - 858 4095 4095 - 858 4095 4095 - 858 4095 4095 - 858 4095 4095 - 858 4095 0 - 858 4095 36 - 858 4095 119 - 858 4095 242 - 858 4095 387 - 858 4095 543 - 858 4095 704 - 858 4095 858 - 858 4095 1006 - 858 4095 1152 - 858 4095 1303 - 858 4095 1469 - 858 4095 1656 - 858 4095 1865 - 858 4095 2102 - 858 4095 2375 - 858 4095 2677 - 858 4095 2991 - 858 4095 3295 - 858 4095 3588 - 858 4095 3852 - 858 4095 4057 - 858 4095 4095 - 858 4095 4095 - 858 4095 4095 - 858 4095 4095 - 858 4095 4095 - 858 4095 4095 - 858 4095 4095 - 858 4095 4095 - 858 4095 4095 - 858 4095 4095 - 858 4095 4095 - 858 4095 0 - 858 4095 36 - 858 4095 119 - 858 4095 242 - 858 4095 387 - 858 4095 543 - 858 4095 704 - 858 4095 858 - 858 4095 1006 - 858 4095 1152 - 858 4095 1303 - 858 4095 1469 - 858 4095 1656 - 858 4095 1865 - 858 4095 2102 - 858 4095 2375 - 858 4095 2677 - 858 4095 2991 - 858 4095 3295 - 858 4095 3588 - 858 4095 3852 - 858 4095 4057 - 858 4095 4095 - 858 4095 4095 - 858 4095 4095 - 858 4095 4095 - 858 4095 4095 - 858 4095 4095 - 858 4095 4095 - 858 4095 4095 - 858 4095 4095 - 858 4095 4095 - 858 4095 4095 - 858 4095 0 - 858 4095 36 - 858 4095 119 - 858 4095 242 - 858 4095 387 - 858 4095 543 - 858 4095 704 - 858 4095 858 - 858 4095 1006 - 858 4095 1152 - 858 4095 1303 - 858 4095 1469 - 858 4095 1656 - 858 4095 1865 - 858 4095 2102 - 858 4095 2375 - 858 4095 2677 - 858 4095 2991 - 858 4095 3295 - 858 4095 3588 - 858 4095 3852 - 858 4095 4057 - 858 4095 4095 - 858 4095 4095 - 858 4095 4095 - 858 4095 4095 - 858 4095 4095 - 858 4095 4095 - 858 4095 4095 - 858 4095 4095 - 858 4095 4095 - 858 4095 4095 - 858 4095 4095 - 858 4095 0 - 858 4095 36 - 858 4095 119 - 858 4095 242 - 858 4095 387 - 858 4095 543 - 858 4095 704 - 858 4095 858 - 858 4095 1006 - 858 4095 1152 - 858 4095 1303 - 858 4095 1469 - 858 4095 1656 - 858 4095 1865 - 858 4095 2102 - 858 4095 2375 - 858 4095 2677 - 858 4095 2991 - 858 4095 3295 - 858 4095 3588 - 858 4095 3852 - 858 4095 4057 - 858 4095 4095 - 858 4095 4095 - 858 4095 4095 - 858 4095 4095 - 858 4095 4095 - 858 4095 4095 - 858 4095 4095 - 858 4095 4095 - 858 4095 4095 - 858 4095 4095 - 858 4095 4095 - 858 4095 0 - 858 4095 36 - 858 4095 119 - 858 4095 242 - 858 4095 387 - 858 4095 543 - 858 4095 704 - 858 4095 858 - 858 4095 1006 - 858 4095 1152 - 858 4095 1303 - 858 4095 1469 - 858 4095 1656 - 858 4095 1865 - 858 4095 2102 - 858 4095 2375 - 858 4095 2677 - 858 4095 2991 - 858 4095 3295 - 858 4095 3588 - 858 4095 3852 - 858 4095 4057 - 858 4095 4095 - 858 4095 4095 - 858 4095 4095 - 858 4095 4095 - 858 4095 4095 - 858 4095 4095 - 858 4095 4095 - 858 4095 4095 - 858 4095 4095 - 858 4095 4095 - 858 4095 4095 - 858 4095 0 - 858 4095 36 - 858 4095 119 - 858 4095 242 - 858 4095 387 - 858 4095 543 - 858 4095 704 - 858 4095 858 - 858 4095 1006 - 858 4095 1152 - 858 4095 1303 - 858 4095 1469 - 858 4095 1656 - 858 4095 1865 - 858 4095 2102 - 858 4095 2375 - 858 4095 2677 - 858 4095 2991 - 858 4095 3295 - 858 4095 3588 - 858 4095 3852 - 858 4095 4057 - 858 4095 4095 - 858 4095 4095 - 858 4095 4095 - 858 4095 4095 - 858 4095 4095 - 858 4095 4095 - 858 4095 4095 - 858 4095 4095 - 858 4095 4095 - 858 4095 4095 - 858 4095 4095 - 858 4095 0 - 858 4095 36 - 858 4095 119 - 858 4095 242 - 858 4095 387 - 858 4095 543 - 858 4095 704 - 858 4095 858 - 858 4095 1006 - 858 4095 1152 - 858 4095 1303 - 858 4095 1469 - 858 4095 1656 - 858 4095 1865 - 858 4095 2102 - 858 4095 2375 - 858 4095 2677 - 858 4095 2991 - 858 4095 3295 - 858 4095 3588 - 858 4095 3852 - 858 4095 4057 - 858 4095 4095 - 858 4095 4095 - 858 4095 4095 - 858 4095 4095 - 858 4095 4095 - 858 4095 4095 - 858 4095 4095 - 858 4095 4095 - 858 4095 4095 - 858 4095 4095 - 858 4095 4095 - 858 4095 0 - 858 4095 36 - 858 4095 119 - 858 4095 242 - 858 4095 387 - 858 4095 543 - 858 4095 704 - 858 4095 858 - 858 4095 1006 - 858 4095 1152 - 858 4095 1303 - 858 4095 1469 - 858 4095 1656 - 858 4095 1865 - 858 4095 2102 - 858 4095 2375 - 858 4095 2677 - 858 4095 2991 - 858 4095 3295 - 858 4095 3588 - 858 4095 3852 - 858 4095 4057 - 858 4095 4095 - 858 4095 4095 - 858 4095 4095 - 858 4095 4095 - 858 4095 4095 - 858 4095 4095 - 858 4095 4095 - 858 4095 4095 - 858 4095 4095 - 858 4095 4095 - 858 4095 4095 - 773 1 1 - 774 1 95 - 776 1 190 - 781 1 289 - 788 0 390 - 797 1 494 - 807 1 603 - 819 1 715 - 832 2 832 - 847 1 953 - 862 1 1081 - 879 0 1228 - 898 1 1398 - 919 1 1594 - 940 2 1817 - 961 2 2072 - 979 2 2355 - 993 1 2664 - 1005 0 3004 - 1017 3 3377 - 1028 3 3780 - 1037 1 4087 - 1044 2 4095 - 1049 3 4095 - 1052 4 4095 - 1051 0 4095 - 1048 3 4095 - 1039 3 4095 - 1024 2 4095 - 1009 2 4095 - 1006 0 4095 - 1006 0 4095 - 1006 0 4095 - 781 95 0 - 782 96 95 - 784 96 192 - 789 96 291 - 795 97 393 - 804 98 499 - 814 99 608 - 825 101 721 - 838 102 837 - 852 104 959 - 867 106 1087 - 883 108 1234 - 902 110 1404 - 922 112 1599 - 943 114 1822 - 962 116 2076 - 980 118 2358 - 994 118 2666 - 1006 119 3006 - 1017 119 3379 - 1028 119 3782 - 1037 118 4087 - 1044 116 4095 - 1049 113 4095 - 1052 109 4095 - 1051 102 4095 - 1048 94 4095 - 1039 81 4095 - 1023 64 4095 - 1009 44 4095 - 1006 36 4095 - 1006 36 4095 - 1006 36 4095 - 805 198 1 - 805 198 98 - 807 198 198 - 811 199 300 - 817 201 404 - 825 202 512 - 834 204 623 - 844 207 737 - 856 210 855 - 868 212 977 - 881 215 1105 - 896 219 1253 - 913 223 1422 - 931 227 1616 - 950 231 1837 - 968 234 2088 - 983 237 2367 - 996 239 2674 - 1008 240 3012 - 1019 241 3384 - 1029 240 3785 - 1037 239 4087 - 1044 236 4095 - 1049 231 4095 - 1052 224 4095 - 1051 214 4095 - 1048 200 4095 - 1038 180 4095 - 1023 154 4095 - 1009 127 4095 - 1006 119 4095 - 1006 119 4095 - 1006 119 4095 - 840 311 1 - 841 311 103 - 843 312 206 - 846 313 312 - 851 315 420 - 857 317 531 - 864 319 645 - 873 322 762 - 883 326 882 - 893 329 1005 - 904 333 1134 - 917 338 1282 - 931 342 1450 - 946 347 1642 - 962 352 1860 - 976 357 2107 - 989 360 2381 - 1000 363 2686 - 1011 365 3023 - 1021 366 3393 - 1030 366 3792 - 1038 365 4087 - 1045 362 4095 - 1050 357 4095 - 1052 349 4095 - 1051 338 4095 - 1048 323 4095 - 1038 301 4095 - 1023 274 4095 - 1009 249 4095 - 1006 242 4095 - 1006 242 4095 - 1006 242 4095 - 882 437 0 - 883 437 107 - 884 438 216 - 886 439 326 - 890 441 439 - 895 443 554 - 900 445 672 - 907 448 792 - 914 452 914 - 922 456 1039 - 931 460 1169 - 941 464 1316 - 952 469 1483 - 963 474 1673 - 975 479 1887 - 985 483 2129 - 995 487 2400 - 1005 490 2703 - 1015 493 3038 - 1024 496 3405 - 1032 497 3801 - 1040 497 4086 - 1046 495 4095 - 1050 491 4095 - 1052 484 4095 - 1051 474 4095 - 1047 459 4095 - 1037 439 4095 - 1022 414 4095 - 1009 392 4095 - 1006 387 4095 - 1006 387 4095 - 1006 387 4095 - 923 573 2 - 924 573 112 - 925 574 225 - 926 575 340 - 929 577 458 - 932 578 577 - 936 581 699 - 941 584 821 - 946 587 946 - 952 590 1072 - 958 593 1203 - 964 597 1350 - 972 601 1516 - 979 606 1703 - 987 610 1913 - 995 614 2152 - 1003 618 2421 - 1011 622 2722 - 1019 625 3055 - 1027 629 3420 - 1035 631 3813 - 1042 632 4086 - 1047 632 4095 - 1050 629 4095 - 1052 624 4095 - 1051 616 4095 - 1047 605 4095 - 1037 587 4095 - 1021 566 4095 - 1008 547 4095 - 1006 543 4095 - 1006 543 4095 - 1006 543 4095 - 958 716 2 - 958 716 116 - 959 716 232 - 960 717 352 - 962 718 473 - 964 720 596 - 966 722 721 - 969 724 846 - 972 726 972 - 976 728 1099 - 979 731 1231 - 984 734 1377 - 988 737 1543 - 993 740 1728 - 998 744 1938 - 1004 748 2176 - 1011 752 2444 - 1018 756 2745 - 1024 761 3075 - 1031 765 3437 - 1038 768 3826 - 1044 770 4085 - 1048 772 4095 - 1051 771 4095 - 1052 768 4095 - 1051 763 4095 - 1046 754 4095 - 1035 739 4095 - 1020 721 4095 - 1008 706 4095 - 1006 704 4095 - 1006 704 4095 - 1006 704 4095 - 984 859 2 - 984 859 118 - 984 860 237 - 985 860 359 - 986 861 483 - 987 862 609 - 988 863 736 - 990 864 864 - 992 866 991 - 994 868 1120 - 996 869 1252 - 998 872 1399 - 1001 874 1565 - 1005 877 1751 - 1009 880 1961 - 1014 884 2199 - 1019 888 2468 - 1024 893 2768 - 1030 897 3097 - 1035 902 3455 - 1041 906 3840 - 1045 909 4085 - 1049 911 4095 - 1051 912 4095 - 1052 911 4095 - 1050 908 4095 - 1045 901 4095 - 1034 889 4095 - 1019 873 4095 - 1008 860 4095 - 1006 858 4095 - 1006 858 4095 - 1006 858 4095 - 1001 1001 2 - 1001 1001 119 - 1001 1001 239 - 1001 1002 363 - 1002 1002 489 - 1003 1003 617 - 1003 1004 747 - 1005 1005 876 - 1006 1006 1006 - 1007 1007 1136 - 1009 1009 1269 - 1011 1011 1418 - 1013 1013 1585 - 1015 1016 1772 - 1019 1019 1983 - 1022 1022 2222 - 1026 1026 2491 - 1030 1030 2791 - 1035 1035 3118 - 1039 1039 3474 - 1044 1044 3854 - 1047 1047 4084 - 1050 1050 4095 - 1052 1052 4095 - 1051 1052 4095 - 1050 1050 4095 - 1044 1044 4095 - 1032 1032 4095 - 1018 1018 4095 - 1007 1007 4095 - 1006 1006 4095 - 1006 1006 4095 - 1006 1006 4095 - 1014 1144 0 - 1014 1144 119 - 1014 1144 240 - 1014 1144 365 - 1015 1145 493 - 1015 1145 623 - 1016 1146 755 - 1017 1147 886 - 1018 1148 1018 - 1019 1149 1149 - 1020 1151 1284 - 1021 1152 1434 - 1023 1154 1602 - 1025 1156 1791 - 1027 1159 2003 - 1030 1162 2244 - 1033 1166 2514 - 1036 1170 2814 - 1039 1174 3140 - 1043 1178 3493 - 1046 1183 3867 - 1049 1187 4083 - 1051 1190 4095 - 1052 1192 4095 - 1051 1193 4095 - 1049 1192 4095 - 1042 1187 4095 - 1030 1176 4095 - 1016 1162 4095 - 1007 1153 4095 - 1006 1152 4095 - 1006 1152 4095 - 1006 1152 4095 - 1025 1291 1 - 1025 1291 119 - 1025 1292 240 - 1025 1292 366 - 1026 1292 496 - 1026 1293 628 - 1026 1293 761 - 1027 1294 895 - 1028 1295 1027 - 1028 1296 1160 - 1029 1297 1297 - 1030 1298 1448 - 1031 1300 1618 - 1033 1302 1808 - 1034 1304 2022 - 1036 1307 2264 - 1038 1311 2536 - 1041 1314 2837 - 1043 1318 3161 - 1046 1322 3511 - 1048 1327 3881 - 1050 1331 4082 - 1051 1334 4095 - 1052 1336 4095 - 1051 1338 4095 - 1048 1338 4095 - 1040 1333 4095 - 1028 1323 4095 - 1015 1310 4095 - 1006 1303 4095 - 1006 1303 4095 - 1006 1303 4095 - 1006 1303 4095 - 1034 1456 2 - 1034 1456 118 - 1035 1456 239 - 1035 1456 366 - 1035 1457 497 - 1035 1457 631 - 1035 1458 767 - 1036 1458 902 - 1036 1459 1036 - 1037 1460 1171 - 1037 1461 1309 - 1038 1462 1462 - 1039 1463 1633 - 1040 1465 1825 - 1041 1467 2041 - 1042 1470 2285 - 1044 1473 2559 - 1045 1476 2860 - 1047 1479 3184 - 1049 1483 3531 - 1050 1487 3894 - 1051 1491 4080 - 1052 1495 4095 - 1051 1498 4095 - 1050 1501 4095 - 1046 1500 4095 - 1038 1495 4095 - 1025 1486 4095 - 1013 1475 4095 - 1006 1470 4095 - 1006 1469 4095 - 1006 1469 4095 - 1006 1469 4095 - 1042 1641 2 - 1042 1641 116 - 1042 1641 237 - 1042 1641 364 - 1042 1642 496 - 1043 1642 632 - 1043 1642 770 - 1043 1643 907 - 1043 1644 1043 - 1044 1644 1179 - 1044 1645 1319 - 1044 1646 1474 - 1045 1647 1647 - 1045 1649 1841 - 1046 1650 2058 - 1047 1653 2305 - 1048 1655 2581 - 1049 1658 2884 - 1050 1661 3207 - 1051 1665 3550 - 1051 1668 3905 - 1052 1672 4079 - 1051 1676 4095 - 1051 1680 4095 - 1048 1683 4095 - 1043 1682 4095 - 1034 1677 4095 - 1022 1668 4095 - 1011 1659 4095 - 1006 1656 4095 - 1006 1656 4095 - 1006 1656 4095 - 1006 1656 4095 - 1048 1849 3 - 1048 1849 114 - 1048 1849 233 - 1048 1849 359 - 1048 1849 493 - 1048 1850 631 - 1048 1850 771 - 1048 1850 911 - 1048 1851 1048 - 1049 1852 1186 - 1049 1852 1327 - 1049 1853 1484 - 1049 1854 1659 - 1050 1855 1855 - 1050 1857 2075 - 1050 1858 2325 - 1051 1861 2604 - 1051 1863 2908 - 1051 1866 3229 - 1052 1869 3568 - 1052 1873 3916 - 1051 1877 4077 - 1051 1881 4095 - 1049 1885 4095 - 1046 1887 4095 - 1039 1886 4095 - 1030 1881 4095 - 1018 1873 4095 - 1009 1867 4095 - 1006 1865 4095 - 1006 1865 4095 - 1006 1865 4095 - 1006 1865 4095 - 1051 2084 0 - 1051 2084 110 - 1051 2084 226 - 1051 2084 353 - 1051 2084 487 - 1051 2084 627 - 1051 2084 770 - 1051 2085 912 - 1051 2085 1051 - 1051 2086 1191 - 1051 2086 1334 - 1051 2087 1492 - 1052 2088 1669 - 1052 2089 1867 - 1052 2090 2090 - 1052 2091 2343 - 1052 2093 2625 - 1052 2095 2931 - 1052 2098 3252 - 1051 2102 3587 - 1051 2105 3926 - 1050 2110 4074 - 1049 2114 4095 - 1046 2117 4095 - 1041 2118 4095 - 1034 2116 4095 - 1024 2111 4095 - 1014 2105 4095 - 1007 2102 4095 - 1006 2102 4095 - 1006 2102 4095 - 1006 2102 4095 - 1006 2102 4095 - 1051 2353 1 - 1051 2353 104 - 1051 2353 217 - 1051 2353 342 - 1051 2353 478 - 1051 2354 621 - 1051 2354 766 - 1051 2354 910 - 1051 2355 1051 - 1051 2355 1192 - 1051 2356 1337 - 1051 2356 1498 - 1051 2357 1677 - 1051 2358 1877 - 1051 2360 2103 - 1051 2361 2361 - 1051 2363 2647 - 1051 2365 2956 - 1050 2368 3275 - 1049 2371 3604 - 1048 2375 3925 - 1047 2378 4071 - 1044 2381 4095 - 1040 2383 4095 - 1034 2383 4095 - 1026 2382 4095 - 1018 2379 4095 - 1010 2376 4095 - 1006 2375 4095 - 1006 2375 4095 - 1006 2375 4095 - 1006 2375 4095 - 1006 2375 4095 - 1049 2659 2 - 1049 2659 96 - 1049 2659 204 - 1049 2659 328 - 1049 2659 465 - 1049 2659 611 - 1049 2660 759 - 1049 2660 906 - 1049 2660 1049 - 1049 2661 1192 - 1049 2661 1338 - 1049 2662 1501 - 1049 2662 1682 - 1048 2663 1885 - 1048 2664 2114 - 1048 2665 2376 - 1047 2667 2666 - 1046 2668 2977 - 1045 2670 3293 - 1044 2672 3614 - 1042 2675 3913 - 1039 2677 4068 - 1036 2678 4095 - 1031 2679 4095 - 1025 2679 4095 - 1018 2678 4095 - 1011 2677 4095 - 1007 2677 4095 - 1006 2677 4095 - 1006 2677 4095 - 1006 2677 4095 - 1006 2677 4095 - 1006 2677 4095 - 1042 2985 0 - 1042 2985 85 - 1042 2985 186 - 1042 2985 308 - 1042 2985 447 - 1041 2985 595 - 1041 2985 747 - 1041 2985 896 - 1041 2986 1041 - 1041 2986 1185 - 1041 2986 1333 - 1041 2986 1497 - 1040 2987 1681 - 1040 2987 1886 - 1039 2987 2117 - 1039 2988 2383 - 1038 2988 2677 - 1037 2989 2989 - 1035 2990 3301 - 1033 2990 3612 - 1031 2991 3894 - 1028 2991 4064 - 1024 2992 4095 - 1020 2991 4095 - 1015 2991 4095 - 1010 2991 4095 - 1007 2991 4095 - 1006 2991 4095 - 1006 2991 4095 - 1006 2991 4095 - 1006 2991 4095 - 1006 2991 4095 - 1006 2991 4095 - 1028 3300 1 - 1028 3300 69 - 1028 3300 161 - 1028 3300 282 - 1027 3300 422 - 1027 3300 574 - 1027 3300 729 - 1027 3300 881 - 1027 3300 1027 - 1027 3300 1172 - 1027 3300 1321 - 1026 3300 1486 - 1026 3300 1671 - 1025 3300 1878 - 1025 3300 2112 - 1024 3300 2381 - 1023 3299 2679 - 1022 3299 2991 - 1021 3299 3299 - 1019 3298 3600 - 1017 3298 3871 - 1015 3297 4060 - 1012 3296 4095 - 1010 3295 4095 - 1007 3295 4095 - 1006 3295 4095 - 1006 3295 4095 - 1006 3295 4095 - 1006 3295 4095 - 1006 3295 4095 - 1006 3295 4095 - 1006 3295 4095 - 1006 3295 4095 - 1012 3592 2 - 1012 3592 49 - 1012 3592 134 - 1012 3592 255 - 1012 3592 397 - 1012 3592 552 - 1012 3592 711 - 1012 3592 865 - 1012 3592 1012 - 1012 3592 1158 - 1011 3592 1307 - 1011 3592 1474 - 1011 3592 1660 - 1011 3591 1868 - 1011 3591 2104 - 1010 3591 2376 - 1010 3590 2677 - 1009 3590 2991 - 1009 3589 3295 - 1008 3589 3589 - 1007 3588 3854 - 1007 3588 4057 - 1006 3588 4095 - 1006 3588 4095 - 1006 3588 4095 - 1006 3588 4095 - 1006 3588 4095 - 1006 3588 4095 - 1006 3588 4095 - 1006 3588 4095 - 1006 3588 4095 - 1006 3588 4095 - 1006 3588 4095 - 1006 3852 0 - 1006 3852 36 - 1006 3852 120 - 1006 3852 242 - 1006 3852 387 - 1006 3852 543 - 1006 3852 704 - 1006 3852 858 - 1006 3852 1006 - 1006 3852 1152 - 1006 3852 1303 - 1006 3852 1469 - 1006 3852 1656 - 1006 3852 1865 - 1006 3852 2102 - 1006 3852 2375 - 1006 3852 2677 - 1006 3852 2991 - 1006 3852 3295 - 1006 3852 3588 - 1006 3852 3852 - 1006 3852 4057 - 1006 3852 4095 - 1006 3852 4095 - 1006 3852 4095 - 1006 3852 4095 - 1006 3852 4095 - 1006 3852 4095 - 1006 3852 4095 - 1006 3852 4095 - 1006 3852 4095 - 1006 3852 4095 - 1006 3852 4095 - 1006 4057 0 - 1006 4057 36 - 1006 4057 119 - 1006 4057 242 - 1006 4057 387 - 1006 4057 543 - 1006 4057 704 - 1006 4057 858 - 1006 4057 1006 - 1006 4057 1152 - 1006 4057 1303 - 1006 4057 1469 - 1006 4057 1656 - 1006 4057 1865 - 1006 4057 2102 - 1006 4057 2375 - 1006 4057 2677 - 1006 4057 2991 - 1006 4057 3295 - 1006 4057 3588 - 1006 4057 3852 - 1006 4057 4057 - 1006 4057 4095 - 1006 4057 4095 - 1006 4057 4095 - 1006 4057 4095 - 1006 4057 4095 - 1006 4057 4095 - 1006 4057 4095 - 1006 4057 4095 - 1006 4057 4095 - 1006 4057 4095 - 1006 4057 4095 - 1006 4095 0 - 1006 4095 36 - 1006 4095 119 - 1006 4095 242 - 1006 4095 387 - 1006 4095 543 - 1006 4095 704 - 1006 4095 858 - 1006 4095 1006 - 1006 4095 1152 - 1006 4095 1303 - 1006 4095 1469 - 1006 4095 1656 - 1006 4095 1865 - 1006 4095 2102 - 1006 4095 2375 - 1006 4095 2677 - 1006 4095 2991 - 1006 4095 3295 - 1006 4095 3588 - 1006 4095 3852 - 1006 4095 4057 - 1006 4095 4095 - 1006 4095 4095 - 1006 4095 4095 - 1006 4095 4095 - 1006 4095 4095 - 1006 4095 4095 - 1006 4095 4095 - 1006 4095 4095 - 1006 4095 4095 - 1006 4095 4095 - 1006 4095 4095 - 1006 4095 0 - 1006 4095 36 - 1006 4095 119 - 1006 4095 242 - 1006 4095 387 - 1006 4095 543 - 1006 4095 704 - 1006 4095 858 - 1006 4095 1006 - 1006 4095 1152 - 1006 4095 1303 - 1006 4095 1469 - 1006 4095 1656 - 1006 4095 1865 - 1006 4095 2102 - 1006 4095 2375 - 1006 4095 2677 - 1006 4095 2991 - 1006 4095 3295 - 1006 4095 3588 - 1006 4095 3852 - 1006 4095 4057 - 1006 4095 4095 - 1006 4095 4095 - 1006 4095 4095 - 1006 4095 4095 - 1006 4095 4095 - 1006 4095 4095 - 1006 4095 4095 - 1006 4095 4095 - 1006 4095 4095 - 1006 4095 4095 - 1006 4095 4095 - 1006 4095 0 - 1006 4095 36 - 1006 4095 119 - 1006 4095 242 - 1006 4095 387 - 1006 4095 543 - 1006 4095 704 - 1006 4095 858 - 1006 4095 1006 - 1006 4095 1152 - 1006 4095 1303 - 1006 4095 1469 - 1006 4095 1656 - 1006 4095 1865 - 1006 4095 2102 - 1006 4095 2375 - 1006 4095 2677 - 1006 4095 2991 - 1006 4095 3295 - 1006 4095 3588 - 1006 4095 3852 - 1006 4095 4057 - 1006 4095 4095 - 1006 4095 4095 - 1006 4095 4095 - 1006 4095 4095 - 1006 4095 4095 - 1006 4095 4095 - 1006 4095 4095 - 1006 4095 4095 - 1006 4095 4095 - 1006 4095 4095 - 1006 4095 4095 - 1006 4095 0 - 1006 4095 36 - 1006 4095 119 - 1006 4095 242 - 1006 4095 387 - 1006 4095 543 - 1006 4095 704 - 1006 4095 858 - 1006 4095 1006 - 1006 4095 1152 - 1006 4095 1303 - 1006 4095 1469 - 1006 4095 1656 - 1006 4095 1865 - 1006 4095 2102 - 1006 4095 2375 - 1006 4095 2677 - 1006 4095 2991 - 1006 4095 3295 - 1006 4095 3588 - 1006 4095 3852 - 1006 4095 4057 - 1006 4095 4095 - 1006 4095 4095 - 1006 4095 4095 - 1006 4095 4095 - 1006 4095 4095 - 1006 4095 4095 - 1006 4095 4095 - 1006 4095 4095 - 1006 4095 4095 - 1006 4095 4095 - 1006 4095 4095 - 1006 4095 0 - 1006 4095 36 - 1006 4095 119 - 1006 4095 242 - 1006 4095 387 - 1006 4095 543 - 1006 4095 704 - 1006 4095 858 - 1006 4095 1006 - 1006 4095 1152 - 1006 4095 1303 - 1006 4095 1469 - 1006 4095 1656 - 1006 4095 1865 - 1006 4095 2102 - 1006 4095 2375 - 1006 4095 2677 - 1006 4095 2991 - 1006 4095 3295 - 1006 4095 3588 - 1006 4095 3852 - 1006 4095 4057 - 1006 4095 4095 - 1006 4095 4095 - 1006 4095 4095 - 1006 4095 4095 - 1006 4095 4095 - 1006 4095 4095 - 1006 4095 4095 - 1006 4095 4095 - 1006 4095 4095 - 1006 4095 4095 - 1006 4095 4095 - 1006 4095 0 - 1006 4095 36 - 1006 4095 119 - 1006 4095 242 - 1006 4095 387 - 1006 4095 543 - 1006 4095 704 - 1006 4095 858 - 1006 4095 1006 - 1006 4095 1152 - 1006 4095 1303 - 1006 4095 1469 - 1006 4095 1656 - 1006 4095 1865 - 1006 4095 2102 - 1006 4095 2375 - 1006 4095 2677 - 1006 4095 2991 - 1006 4095 3295 - 1006 4095 3588 - 1006 4095 3852 - 1006 4095 4057 - 1006 4095 4095 - 1006 4095 4095 - 1006 4095 4095 - 1006 4095 4095 - 1006 4095 4095 - 1006 4095 4095 - 1006 4095 4095 - 1006 4095 4095 - 1006 4095 4095 - 1006 4095 4095 - 1006 4095 4095 - 1006 4095 0 - 1006 4095 36 - 1006 4095 119 - 1006 4095 242 - 1006 4095 387 - 1006 4095 543 - 1006 4095 704 - 1006 4095 858 - 1006 4095 1006 - 1006 4095 1152 - 1006 4095 1303 - 1006 4095 1469 - 1006 4095 1656 - 1006 4095 1865 - 1006 4095 2102 - 1006 4095 2375 - 1006 4095 2677 - 1006 4095 2991 - 1006 4095 3295 - 1006 4095 3588 - 1006 4095 3852 - 1006 4095 4057 - 1006 4095 4095 - 1006 4095 4095 - 1006 4095 4095 - 1006 4095 4095 - 1006 4095 4095 - 1006 4095 4095 - 1006 4095 4095 - 1006 4095 4095 - 1006 4095 4095 - 1006 4095 4095 - 1006 4095 4095 - 1006 4095 0 - 1006 4095 36 - 1006 4095 119 - 1006 4095 242 - 1006 4095 387 - 1006 4095 543 - 1006 4095 704 - 1006 4095 858 - 1006 4095 1006 - 1006 4095 1152 - 1006 4095 1303 - 1006 4095 1469 - 1006 4095 1656 - 1006 4095 1865 - 1006 4095 2102 - 1006 4095 2375 - 1006 4095 2677 - 1006 4095 2991 - 1006 4095 3295 - 1006 4095 3588 - 1006 4095 3852 - 1006 4095 4057 - 1006 4095 4095 - 1006 4095 4095 - 1006 4095 4095 - 1006 4095 4095 - 1006 4095 4095 - 1006 4095 4095 - 1006 4095 4095 - 1006 4095 4095 - 1006 4095 4095 - 1006 4095 4095 - 1006 4095 4095 - 1006 4095 0 - 1006 4095 36 - 1006 4095 119 - 1006 4095 242 - 1006 4095 387 - 1006 4095 543 - 1006 4095 704 - 1006 4095 858 - 1006 4095 1006 - 1006 4095 1152 - 1006 4095 1303 - 1006 4095 1469 - 1006 4095 1656 - 1006 4095 1865 - 1006 4095 2102 - 1006 4095 2375 - 1006 4095 2677 - 1006 4095 2991 - 1006 4095 3295 - 1006 4095 3588 - 1006 4095 3852 - 1006 4095 4057 - 1006 4095 4095 - 1006 4095 4095 - 1006 4095 4095 - 1006 4095 4095 - 1006 4095 4095 - 1006 4095 4095 - 1006 4095 4095 - 1006 4095 4095 - 1006 4095 4095 - 1006 4095 4095 - 1006 4095 4095 - 1006 4095 0 - 1006 4095 36 - 1006 4095 119 - 1006 4095 242 - 1006 4095 387 - 1006 4095 543 - 1006 4095 704 - 1006 4095 858 - 1006 4095 1006 - 1006 4095 1152 - 1006 4095 1303 - 1006 4095 1469 - 1006 4095 1656 - 1006 4095 1865 - 1006 4095 2102 - 1006 4095 2375 - 1006 4095 2677 - 1006 4095 2991 - 1006 4095 3295 - 1006 4095 3588 - 1006 4095 3852 - 1006 4095 4057 - 1006 4095 4095 - 1006 4095 4095 - 1006 4095 4095 - 1006 4095 4095 - 1006 4095 4095 - 1006 4095 4095 - 1006 4095 4095 - 1006 4095 4095 - 1006 4095 4095 - 1006 4095 4095 - 1006 4095 4095 - 1006 4095 0 - 1006 4095 36 - 1006 4095 119 - 1006 4095 242 - 1006 4095 387 - 1006 4095 543 - 1006 4095 704 - 1006 4095 858 - 1006 4095 1006 - 1006 4095 1152 - 1006 4095 1303 - 1006 4095 1469 - 1006 4095 1656 - 1006 4095 1865 - 1006 4095 2102 - 1006 4095 2375 - 1006 4095 2677 - 1006 4095 2991 - 1006 4095 3295 - 1006 4095 3588 - 1006 4095 3852 - 1006 4095 4057 - 1006 4095 4095 - 1006 4095 4095 - 1006 4095 4095 - 1006 4095 4095 - 1006 4095 4095 - 1006 4095 4095 - 1006 4095 4095 - 1006 4095 4095 - 1006 4095 4095 - 1006 4095 4095 - 1006 4095 4095 - 929 2 1 - 930 1 101 - 932 1 203 - 936 1 307 - 942 1 414 - 950 2 523 - 959 2 636 - 969 1 752 - 981 2 871 - 994 2 993 - 1007 1 1122 - 1023 0 1269 - 1040 1 1438 - 1059 1 1631 - 1078 2 1851 - 1096 0 2099 - 1112 3 2375 - 1125 2 2680 - 1138 0 3018 - 1151 3 3389 - 1162 3 3789 - 1172 2 4087 - 1181 3 4095 - 1187 2 4095 - 1191 2 4095 - 1193 0 4095 - 1191 3 4095 - 1183 0 4095 - 1169 3 4095 - 1155 2 4095 - 1152 0 4095 - 1152 0 4095 - 1152 0 4095 - 936 102 1 - 937 102 102 - 939 102 204 - 943 102 309 - 948 103 416 - 956 103 526 - 964 104 640 - 975 105 756 - 986 107 875 - 998 108 998 - 1012 109 1127 - 1027 111 1274 - 1043 112 1443 - 1061 114 1636 - 1080 116 1855 - 1098 117 2102 - 1113 118 2378 - 1126 119 2682 - 1139 119 3020 - 1151 119 3390 - 1162 119 3790 - 1172 117 4087 - 1181 116 4095 - 1187 112 4095 - 1191 108 4095 - 1193 102 4095 - 1191 93 4095 - 1183 81 4095 - 1168 64 4095 - 1155 43 4095 - 1152 36 4095 - 1152 36 4095 - 1152 36 4095 - 957 208 0 - 957 208 104 - 959 209 208 - 963 209 315 - 968 210 424 - 974 212 536 - 982 213 651 - 991 215 769 - 1002 217 889 - 1013 220 1012 - 1025 222 1142 - 1038 225 1289 - 1054 228 1457 - 1070 231 1649 - 1087 234 1866 - 1102 236 2112 - 1116 238 2385 - 1128 239 2689 - 1141 240 3026 - 1152 241 3395 - 1163 240 3794 - 1173 238 4087 - 1181 235 4095 - 1188 230 4095 - 1191 223 4095 - 1193 213 4095 - 1191 199 4095 - 1183 179 4095 - 1168 153 4095 - 1155 127 4095 - 1152 119 4095 - 1152 119 4095 - 1152 119 4095 - 988 324 1 - 989 324 107 - 990 325 215 - 993 326 325 - 997 327 437 - 1003 329 552 - 1009 331 669 - 1017 333 789 - 1026 336 910 - 1035 338 1035 - 1045 341 1165 - 1057 345 1312 - 1069 348 1480 - 1083 352 1670 - 1097 356 1885 - 1109 359 2127 - 1121 362 2397 - 1132 364 2700 - 1144 365 3036 - 1155 366 3403 - 1165 366 3800 - 1174 365 4086 - 1182 362 4095 - 1188 357 4095 - 1191 349 4095 - 1193 337 4095 - 1191 322 4095 - 1182 300 4095 - 1168 273 4095 - 1155 248 4095 - 1152 242 4095 - 1152 242 4095 - 1152 242 4095 - 1025 450 1 - 1026 450 111 - 1027 451 222 - 1029 452 336 - 1033 453 452 - 1037 455 570 - 1042 457 690 - 1048 459 812 - 1055 462 936 - 1062 465 1062 - 1070 468 1192 - 1078 471 1339 - 1088 475 1506 - 1098 479 1694 - 1108 483 1905 - 1118 486 2144 - 1128 489 2414 - 1138 492 2716 - 1148 494 3049 - 1158 496 3415 - 1167 497 3809 - 1176 497 4086 - 1183 494 4095 - 1189 490 4095 - 1192 483 4095 - 1193 473 4095 - 1191 458 4095 - 1182 438 4095 - 1167 413 4095 - 1155 391 4095 - 1152 387 4095 - 1152 387 4095 - 1152 387 4095 - 1063 585 1 - 1063 585 114 - 1064 586 229 - 1065 586 347 - 1068 588 466 - 1071 589 588 - 1074 591 711 - 1078 593 836 - 1083 595 961 - 1088 598 1088 - 1093 601 1219 - 1099 603 1366 - 1106 606 1531 - 1112 610 1717 - 1120 613 1927 - 1127 616 2164 - 1136 620 2433 - 1144 623 2734 - 1153 627 3066 - 1162 629 3429 - 1170 631 3819 - 1178 632 4086 - 1185 632 4095 - 1189 629 4095 - 1192 624 4095 - 1193 616 4095 - 1190 604 4095 - 1181 586 4095 - 1167 565 4095 - 1154 547 4095 - 1152 543 4095 - 1152 543 4095 - 1152 543 4095 - 1094 725 1 - 1094 725 117 - 1094 725 235 - 1095 726 355 - 1097 727 478 - 1099 728 602 - 1101 729 728 - 1103 731 855 - 1106 732 981 - 1109 734 1109 - 1113 736 1241 - 1116 738 1388 - 1121 741 1553 - 1126 744 1738 - 1131 747 1948 - 1137 751 2186 - 1144 754 2454 - 1151 758 2754 - 1159 762 3084 - 1166 766 3445 - 1174 769 3832 - 1180 771 4085 - 1186 772 4095 - 1190 771 4095 - 1192 767 4095 - 1193 762 4095 - 1189 753 4095 - 1180 739 4095 - 1166 721 4095 - 1154 706 4095 - 1152 704 4095 - 1152 704 4095 - 1152 704 4095 - 1117 865 1 - 1117 865 118 - 1117 865 238 - 1118 866 361 - 1118 866 486 - 1119 867 612 - 1121 868 740 - 1122 869 869 - 1124 871 997 - 1126 872 1126 - 1128 874 1259 - 1131 875 1406 - 1134 878 1572 - 1138 880 1759 - 1142 883 1969 - 1147 887 2208 - 1152 891 2477 - 1158 895 2776 - 1164 899 3104 - 1171 903 3462 - 1177 907 3845 - 1183 910 4084 - 1187 912 4095 - 1191 912 4095 - 1192 911 4095 - 1193 907 4095 - 1189 900 4095 - 1178 888 4095 - 1164 872 4095 - 1154 860 4095 - 1152 858 4095 - 1152 858 4095 - 1152 858 4095 - 1133 1005 2 - 1133 1006 119 - 1134 1006 240 - 1134 1006 364 - 1135 1007 491 - 1135 1007 619 - 1136 1008 750 - 1137 1009 880 - 1139 1010 1010 - 1140 1011 1140 - 1142 1013 1274 - 1144 1014 1423 - 1146 1016 1590 - 1149 1019 1778 - 1152 1022 1989 - 1156 1025 2229 - 1160 1028 2499 - 1165 1032 2798 - 1170 1036 3125 - 1175 1041 3480 - 1180 1045 3858 - 1185 1048 4084 - 1189 1051 4095 - 1191 1052 4095 - 1193 1051 4095 - 1192 1050 4095 - 1187 1043 4095 - 1177 1032 4095 - 1163 1017 4095 - 1153 1007 4095 - 1152 1006 4095 - 1152 1006 4095 - 1152 1006 4095 - 1147 1148 1 - 1147 1148 119 - 1147 1148 240 - 1148 1148 366 - 1148 1148 494 - 1149 1149 625 - 1149 1150 757 - 1150 1150 889 - 1151 1151 1020 - 1152 1152 1152 - 1153 1154 1288 - 1155 1155 1438 - 1157 1157 1607 - 1159 1159 1796 - 1161 1162 2008 - 1164 1165 2249 - 1168 1168 2520 - 1171 1172 2820 - 1175 1175 3146 - 1179 1180 3498 - 1184 1184 3871 - 1187 1187 4083 - 1190 1190 4095 - 1192 1192 4095 - 1193 1193 4095 - 1192 1192 4095 - 1186 1186 4095 - 1175 1175 4095 - 1162 1162 4095 - 1153 1153 4095 - 1152 1152 4095 - 1152 1152 4095 - 1152 1152 4095 - 1159 1294 2 - 1159 1294 119 - 1159 1295 240 - 1160 1295 366 - 1160 1295 496 - 1160 1296 629 - 1161 1296 763 - 1161 1297 896 - 1162 1298 1030 - 1163 1299 1163 - 1164 1300 1300 - 1165 1301 1452 - 1166 1303 1622 - 1168 1304 1812 - 1170 1307 2026 - 1172 1309 2269 - 1174 1312 2541 - 1177 1316 2842 - 1180 1319 3166 - 1183 1323 3516 - 1186 1327 3884 - 1189 1331 4082 - 1191 1334 4095 - 1192 1337 4095 - 1193 1338 4095 - 1191 1338 4095 - 1184 1332 4095 - 1173 1322 4095 - 1160 1310 4095 - 1153 1303 4095 - 1152 1303 4095 - 1152 1303 4095 - 1152 1303 4095 - 1170 1459 3 - 1170 1459 118 - 1170 1459 239 - 1170 1459 366 - 1170 1459 497 - 1170 1460 631 - 1171 1460 767 - 1171 1461 903 - 1172 1461 1038 - 1172 1462 1172 - 1173 1463 1311 - 1174 1464 1464 - 1175 1466 1636 - 1176 1467 1828 - 1177 1469 2044 - 1179 1471 2289 - 1181 1474 2563 - 1183 1477 2864 - 1185 1481 3188 - 1187 1484 3534 - 1189 1488 3896 - 1191 1492 4080 - 1192 1495 4095 - 1193 1498 4095 - 1192 1501 4095 - 1189 1500 4095 - 1182 1495 4095 - 1170 1485 4095 - 1158 1475 4095 - 1152 1470 4095 - 1152 1469 4095 - 1152 1469 4095 - 1152 1469 4095 - 1179 1643 2 - 1179 1643 116 - 1179 1643 236 - 1179 1644 363 - 1179 1644 496 - 1179 1644 632 - 1179 1645 770 - 1180 1645 908 - 1180 1646 1044 - 1180 1646 1180 - 1181 1647 1320 - 1181 1648 1475 - 1182 1649 1649 - 1183 1650 1843 - 1184 1652 2061 - 1185 1654 2308 - 1186 1656 2585 - 1187 1659 2887 - 1188 1662 3210 - 1190 1666 3552 - 1191 1669 3907 - 1192 1673 4078 - 1193 1677 4095 - 1193 1680 4095 - 1191 1683 4095 - 1187 1682 4095 - 1179 1677 4095 - 1167 1668 4095 - 1156 1659 4095 - 1152 1656 4095 - 1152 1656 4095 - 1152 1656 4095 - 1152 1656 4095 - 1186 1851 1 - 1186 1851 113 - 1186 1851 232 - 1186 1851 359 - 1186 1851 492 - 1186 1851 631 - 1186 1852 771 - 1186 1852 911 - 1187 1853 1049 - 1187 1853 1187 - 1187 1854 1328 - 1187 1855 1485 - 1188 1856 1660 - 1188 1857 1856 - 1189 1858 2077 - 1189 1860 2327 - 1190 1862 2606 - 1190 1864 2910 - 1191 1867 3232 - 1192 1870 3570 - 1192 1873 3917 - 1193 1877 4076 - 1193 1882 4095 - 1192 1885 4095 - 1189 1887 4095 - 1183 1886 4095 - 1174 1880 4095 - 1163 1873 4095 - 1155 1866 4095 - 1152 1865 4095 - 1152 1865 4095 - 1152 1865 4095 - 1152 1865 4095 - 1191 2085 2 - 1191 2085 109 - 1191 2085 225 - 1191 2085 352 - 1191 2085 487 - 1191 2085 627 - 1191 2086 770 - 1191 2086 912 - 1191 2086 1051 - 1191 2087 1191 - 1191 2087 1334 - 1191 2088 1493 - 1191 2089 1670 - 1191 2090 1868 - 1192 2091 2091 - 1192 2092 2345 - 1192 2094 2627 - 1192 2096 2934 - 1192 2099 3254 - 1193 2103 3589 - 1193 2106 3927 - 1193 2110 4074 - 1192 2114 4095 - 1189 2117 4095 - 1185 2118 4095 - 1178 2116 4095 - 1169 2111 4095 - 1159 2105 4095 - 1153 2102 4095 - 1152 2102 4095 - 1152 2102 4095 - 1152 2102 4095 - 1152 2102 4095 - 1192 2355 3 - 1192 2355 103 - 1192 2355 216 - 1192 2355 341 - 1192 2355 477 - 1192 2355 620 - 1192 2355 766 - 1192 2356 910 - 1192 2356 1051 - 1192 2357 1192 - 1193 2357 1337 - 1193 2358 1498 - 1193 2359 1677 - 1193 2360 1878 - 1193 2361 2104 - 1193 2362 2362 - 1193 2364 2649 - 1193 2367 2958 - 1192 2369 3277 - 1192 2372 3605 - 1191 2375 3925 - 1190 2379 4071 - 1187 2381 4095 - 1184 2383 4095 - 1178 2383 4095 - 1171 2382 4095 - 1163 2379 4095 - 1156 2376 4095 - 1152 2375 4095 - 1152 2375 4095 - 1152 2375 4095 - 1152 2375 4095 - 1152 2375 4095 - 1192 2660 2 - 1192 2660 95 - 1192 2660 203 - 1192 2660 327 - 1192 2660 464 - 1192 2660 610 - 1192 2661 759 - 1192 2661 906 - 1192 2661 1049 - 1192 2662 1192 - 1192 2662 1338 - 1191 2663 1501 - 1191 2663 1682 - 1191 2664 1886 - 1191 2665 2115 - 1191 2666 2377 - 1190 2668 2667 - 1190 2669 2978 - 1189 2671 3294 - 1187 2673 3614 - 1186 2675 3913 - 1183 2677 4067 - 1180 2678 4095 - 1176 2679 4095 - 1170 2679 4095 - 1163 2678 4095 - 1157 2677 4095 - 1153 2677 4095 - 1152 2677 4095 - 1152 2677 4095 - 1152 2677 4095 - 1152 2677 4095 - 1152 2677 4095 - 1186 2986 0 - 1186 2986 84 - 1186 2986 185 - 1185 2986 307 - 1185 2986 446 - 1185 2986 594 - 1185 2986 746 - 1185 2986 896 - 1185 2986 1041 - 1185 2986 1185 - 1185 2986 1333 - 1184 2987 1497 - 1184 2987 1681 - 1184 2987 1886 - 1183 2988 2117 - 1183 2988 2383 - 1182 2989 2677 - 1181 2989 2989 - 1179 2990 3301 - 1178 2991 3611 - 1176 2991 3893 - 1173 2991 4064 - 1169 2992 4095 - 1165 2991 4095 - 1161 2991 4095 - 1156 2991 4095 - 1153 2991 4095 - 1152 2991 4095 - 1152 2991 4095 - 1152 2991 4095 - 1152 2991 4095 - 1152 2991 4095 - 1152 2991 4095 - 1172 3300 0 - 1172 3300 68 - 1172 3300 160 - 1172 3300 281 - 1172 3300 422 - 1172 3300 573 - 1172 3300 729 - 1172 3300 880 - 1172 3300 1026 - 1172 3300 1172 - 1171 3300 1321 - 1171 3300 1486 - 1171 3300 1671 - 1170 3300 1878 - 1170 3300 2112 - 1169 3300 2381 - 1168 3299 2679 - 1167 3299 2991 - 1166 3299 3299 - 1165 3298 3599 - 1163 3297 3870 - 1161 3297 4060 - 1158 3296 4095 - 1156 3295 4095 - 1154 3295 4095 - 1153 3295 4095 - 1152 3295 4095 - 1152 3295 4095 - 1152 3295 4095 - 1152 3295 4095 - 1152 3295 4095 - 1152 3295 4095 - 1152 3295 4095 - 1158 3592 1 - 1158 3592 48 - 1158 3592 133 - 1158 3592 254 - 1158 3592 397 - 1158 3592 552 - 1158 3592 711 - 1158 3592 864 - 1157 3592 1011 - 1157 3592 1157 - 1157 3592 1307 - 1157 3591 1474 - 1157 3591 1660 - 1157 3591 1868 - 1156 3591 2104 - 1156 3590 2376 - 1156 3590 2677 - 1155 3590 2991 - 1155 3589 3295 - 1154 3589 3589 - 1153 3588 3854 - 1153 3588 4057 - 1152 3588 4095 - 1152 3588 4095 - 1152 3588 4095 - 1152 3588 4095 - 1152 3588 4095 - 1152 3588 4095 - 1152 3588 4095 - 1152 3588 4095 - 1152 3588 4095 - 1152 3588 4095 - 1152 3588 4095 - 1152 3852 0 - 1152 3852 36 - 1152 3852 120 - 1152 3852 242 - 1152 3852 387 - 1152 3852 543 - 1152 3852 704 - 1152 3852 858 - 1152 3852 1006 - 1152 3852 1152 - 1152 3852 1303 - 1152 3852 1469 - 1152 3852 1656 - 1152 3852 1865 - 1152 3852 2102 - 1152 3852 2375 - 1152 3852 2677 - 1152 3852 2991 - 1152 3852 3295 - 1152 3852 3588 - 1152 3852 3852 - 1152 3852 4057 - 1152 3852 4095 - 1152 3852 4095 - 1152 3852 4095 - 1152 3852 4095 - 1152 3852 4095 - 1152 3852 4095 - 1152 3852 4095 - 1152 3852 4095 - 1152 3852 4095 - 1152 3852 4095 - 1152 3852 4095 - 1152 4057 0 - 1152 4057 36 - 1152 4057 119 - 1152 4057 242 - 1152 4057 387 - 1152 4057 543 - 1152 4057 704 - 1152 4057 858 - 1152 4057 1006 - 1152 4057 1152 - 1152 4057 1303 - 1152 4057 1469 - 1152 4057 1656 - 1152 4057 1865 - 1152 4057 2102 - 1152 4057 2375 - 1152 4057 2677 - 1152 4057 2991 - 1152 4057 3295 - 1152 4057 3588 - 1152 4057 3852 - 1152 4057 4057 - 1152 4057 4095 - 1152 4057 4095 - 1152 4057 4095 - 1152 4057 4095 - 1152 4057 4095 - 1152 4057 4095 - 1152 4057 4095 - 1152 4057 4095 - 1152 4057 4095 - 1152 4057 4095 - 1152 4057 4095 - 1152 4095 0 - 1152 4095 36 - 1152 4095 119 - 1152 4095 242 - 1152 4095 387 - 1152 4095 543 - 1152 4095 704 - 1152 4095 858 - 1152 4095 1006 - 1152 4095 1152 - 1152 4095 1303 - 1152 4095 1469 - 1152 4095 1656 - 1152 4095 1865 - 1152 4095 2102 - 1152 4095 2375 - 1152 4095 2677 - 1152 4095 2991 - 1152 4095 3295 - 1152 4095 3588 - 1152 4095 3852 - 1152 4095 4057 - 1152 4095 4095 - 1152 4095 4095 - 1152 4095 4095 - 1152 4095 4095 - 1152 4095 4095 - 1152 4095 4095 - 1152 4095 4095 - 1152 4095 4095 - 1152 4095 4095 - 1152 4095 4095 - 1152 4095 4095 - 1152 4095 0 - 1152 4095 36 - 1152 4095 119 - 1152 4095 242 - 1152 4095 387 - 1152 4095 543 - 1152 4095 704 - 1152 4095 858 - 1152 4095 1006 - 1152 4095 1152 - 1152 4095 1303 - 1152 4095 1469 - 1152 4095 1656 - 1152 4095 1865 - 1152 4095 2102 - 1152 4095 2375 - 1152 4095 2677 - 1152 4095 2991 - 1152 4095 3295 - 1152 4095 3588 - 1152 4095 3852 - 1152 4095 4057 - 1152 4095 4095 - 1152 4095 4095 - 1152 4095 4095 - 1152 4095 4095 - 1152 4095 4095 - 1152 4095 4095 - 1152 4095 4095 - 1152 4095 4095 - 1152 4095 4095 - 1152 4095 4095 - 1152 4095 4095 - 1152 4095 0 - 1152 4095 36 - 1152 4095 119 - 1152 4095 242 - 1152 4095 387 - 1152 4095 543 - 1152 4095 704 - 1152 4095 858 - 1152 4095 1006 - 1152 4095 1152 - 1152 4095 1303 - 1152 4095 1469 - 1152 4095 1656 - 1152 4095 1865 - 1152 4095 2102 - 1152 4095 2375 - 1152 4095 2677 - 1152 4095 2991 - 1152 4095 3295 - 1152 4095 3588 - 1152 4095 3852 - 1152 4095 4057 - 1152 4095 4095 - 1152 4095 4095 - 1152 4095 4095 - 1152 4095 4095 - 1152 4095 4095 - 1152 4095 4095 - 1152 4095 4095 - 1152 4095 4095 - 1152 4095 4095 - 1152 4095 4095 - 1152 4095 4095 - 1152 4095 0 - 1152 4095 36 - 1152 4095 119 - 1152 4095 242 - 1152 4095 387 - 1152 4095 543 - 1152 4095 704 - 1152 4095 858 - 1152 4095 1006 - 1152 4095 1152 - 1152 4095 1303 - 1152 4095 1469 - 1152 4095 1656 - 1152 4095 1865 - 1152 4095 2102 - 1152 4095 2375 - 1152 4095 2677 - 1152 4095 2991 - 1152 4095 3295 - 1152 4095 3588 - 1152 4095 3852 - 1152 4095 4057 - 1152 4095 4095 - 1152 4095 4095 - 1152 4095 4095 - 1152 4095 4095 - 1152 4095 4095 - 1152 4095 4095 - 1152 4095 4095 - 1152 4095 4095 - 1152 4095 4095 - 1152 4095 4095 - 1152 4095 4095 - 1152 4095 0 - 1152 4095 36 - 1152 4095 119 - 1152 4095 242 - 1152 4095 387 - 1152 4095 543 - 1152 4095 704 - 1152 4095 858 - 1152 4095 1006 - 1152 4095 1152 - 1152 4095 1303 - 1152 4095 1469 - 1152 4095 1656 - 1152 4095 1865 - 1152 4095 2102 - 1152 4095 2375 - 1152 4095 2677 - 1152 4095 2991 - 1152 4095 3295 - 1152 4095 3588 - 1152 4095 3852 - 1152 4095 4057 - 1152 4095 4095 - 1152 4095 4095 - 1152 4095 4095 - 1152 4095 4095 - 1152 4095 4095 - 1152 4095 4095 - 1152 4095 4095 - 1152 4095 4095 - 1152 4095 4095 - 1152 4095 4095 - 1152 4095 4095 - 1152 4095 0 - 1152 4095 36 - 1152 4095 119 - 1152 4095 242 - 1152 4095 387 - 1152 4095 543 - 1152 4095 704 - 1152 4095 858 - 1152 4095 1006 - 1152 4095 1152 - 1152 4095 1303 - 1152 4095 1469 - 1152 4095 1656 - 1152 4095 1865 - 1152 4095 2102 - 1152 4095 2375 - 1152 4095 2677 - 1152 4095 2991 - 1152 4095 3295 - 1152 4095 3588 - 1152 4095 3852 - 1152 4095 4057 - 1152 4095 4095 - 1152 4095 4095 - 1152 4095 4095 - 1152 4095 4095 - 1152 4095 4095 - 1152 4095 4095 - 1152 4095 4095 - 1152 4095 4095 - 1152 4095 4095 - 1152 4095 4095 - 1152 4095 4095 - 1152 4095 0 - 1152 4095 36 - 1152 4095 119 - 1152 4095 242 - 1152 4095 387 - 1152 4095 543 - 1152 4095 704 - 1152 4095 858 - 1152 4095 1006 - 1152 4095 1152 - 1152 4095 1303 - 1152 4095 1469 - 1152 4095 1656 - 1152 4095 1865 - 1152 4095 2102 - 1152 4095 2375 - 1152 4095 2677 - 1152 4095 2991 - 1152 4095 3295 - 1152 4095 3588 - 1152 4095 3852 - 1152 4095 4057 - 1152 4095 4095 - 1152 4095 4095 - 1152 4095 4095 - 1152 4095 4095 - 1152 4095 4095 - 1152 4095 4095 - 1152 4095 4095 - 1152 4095 4095 - 1152 4095 4095 - 1152 4095 4095 - 1152 4095 4095 - 1152 4095 0 - 1152 4095 36 - 1152 4095 119 - 1152 4095 242 - 1152 4095 387 - 1152 4095 543 - 1152 4095 704 - 1152 4095 858 - 1152 4095 1006 - 1152 4095 1152 - 1152 4095 1303 - 1152 4095 1469 - 1152 4095 1656 - 1152 4095 1865 - 1152 4095 2102 - 1152 4095 2375 - 1152 4095 2677 - 1152 4095 2991 - 1152 4095 3295 - 1152 4095 3588 - 1152 4095 3852 - 1152 4095 4057 - 1152 4095 4095 - 1152 4095 4095 - 1152 4095 4095 - 1152 4095 4095 - 1152 4095 4095 - 1152 4095 4095 - 1152 4095 4095 - 1152 4095 4095 - 1152 4095 4095 - 1152 4095 4095 - 1152 4095 4095 - 1152 4095 0 - 1152 4095 36 - 1152 4095 119 - 1152 4095 242 - 1152 4095 387 - 1152 4095 543 - 1152 4095 704 - 1152 4095 858 - 1152 4095 1006 - 1152 4095 1152 - 1152 4095 1303 - 1152 4095 1469 - 1152 4095 1656 - 1152 4095 1865 - 1152 4095 2102 - 1152 4095 2375 - 1152 4095 2677 - 1152 4095 2991 - 1152 4095 3295 - 1152 4095 3588 - 1152 4095 3852 - 1152 4095 4057 - 1152 4095 4095 - 1152 4095 4095 - 1152 4095 4095 - 1152 4095 4095 - 1152 4095 4095 - 1152 4095 4095 - 1152 4095 4095 - 1152 4095 4095 - 1152 4095 4095 - 1152 4095 4095 - 1152 4095 4095 - 1152 4095 0 - 1152 4095 36 - 1152 4095 119 - 1152 4095 242 - 1152 4095 387 - 1152 4095 543 - 1152 4095 704 - 1152 4095 858 - 1152 4095 1006 - 1152 4095 1152 - 1152 4095 1303 - 1152 4095 1469 - 1152 4095 1656 - 1152 4095 1865 - 1152 4095 2102 - 1152 4095 2375 - 1152 4095 2677 - 1152 4095 2991 - 1152 4095 3295 - 1152 4095 3588 - 1152 4095 3852 - 1152 4095 4057 - 1152 4095 4095 - 1152 4095 4095 - 1152 4095 4095 - 1152 4095 4095 - 1152 4095 4095 - 1152 4095 4095 - 1152 4095 4095 - 1152 4095 4095 - 1152 4095 4095 - 1152 4095 4095 - 1152 4095 4095 - 1152 4095 0 - 1152 4095 36 - 1152 4095 119 - 1152 4095 242 - 1152 4095 387 - 1152 4095 543 - 1152 4095 704 - 1152 4095 858 - 1152 4095 1006 - 1152 4095 1152 - 1152 4095 1303 - 1152 4095 1469 - 1152 4095 1656 - 1152 4095 1865 - 1152 4095 2102 - 1152 4095 2375 - 1152 4095 2677 - 1152 4095 2991 - 1152 4095 3295 - 1152 4095 3588 - 1152 4095 3852 - 1152 4095 4057 - 1152 4095 4095 - 1152 4095 4095 - 1152 4095 4095 - 1152 4095 4095 - 1152 4095 4095 - 1152 4095 4095 - 1152 4095 4095 - 1152 4095 4095 - 1152 4095 4095 - 1152 4095 4095 - 1152 4095 4095 - 1094 0 2 - 1095 0 106 - 1096 0 214 - 1100 0 323 - 1105 0 435 - 1111 0 549 - 1119 0 666 - 1128 0 785 - 1138 1 906 - 1149 1 1030 - 1160 1 1160 - 1174 0 1307 - 1189 0 1475 - 1205 1 1665 - 1221 1 1881 - 1236 1 2124 - 1249 2 2395 - 1262 2 2698 - 1275 0 3033 - 1288 2 3402 - 1301 3 3799 - 1312 2 4086 - 1322 2 4095 - 1329 0 4095 - 1335 4 4095 - 1338 2 4095 - 1338 1 4095 - 1331 0 4095 - 1317 1 4095 - 1305 2 4095 - 1303 0 4095 - 1303 0 4095 - 1303 0 4095 - 1100 107 2 - 1100 107 107 - 1102 107 215 - 1105 107 324 - 1110 108 437 - 1116 108 551 - 1124 109 668 - 1132 110 788 - 1142 110 909 - 1153 111 1034 - 1164 112 1164 - 1177 113 1311 - 1191 115 1479 - 1207 116 1669 - 1223 117 1884 - 1237 118 2126 - 1250 119 2397 - 1263 119 2700 - 1276 119 3035 - 1289 119 3403 - 1301 118 3800 - 1312 117 4086 - 1322 115 4095 - 1330 112 4095 - 1335 108 4095 - 1338 101 4095 - 1338 93 4095 - 1331 80 4095 - 1317 63 4095 - 1305 43 4095 - 1303 36 4095 - 1303 36 4095 - 1303 36 4095 - 1117 217 1 - 1117 218 108 - 1119 218 218 - 1122 218 329 - 1126 219 443 - 1132 220 559 - 1139 221 677 - 1147 223 798 - 1156 224 920 - 1165 226 1045 - 1175 228 1175 - 1187 230 1322 - 1200 232 1490 - 1214 234 1679 - 1228 236 1893 - 1241 238 2133 - 1253 239 2403 - 1265 240 2706 - 1278 240 3040 - 1290 240 3407 - 1302 240 3803 - 1313 238 4086 - 1322 235 4095 - 1330 230 4095 - 1335 222 4095 - 1338 212 4095 - 1338 198 4095 - 1330 178 4095 - 1317 152 4095 - 1305 126 4095 - 1303 119 4095 - 1303 119 4095 - 1303 119 4095 - 1144 336 2 - 1144 336 111 - 1146 336 222 - 1148 337 336 - 1152 338 452 - 1157 339 571 - 1162 341 691 - 1169 342 813 - 1176 344 937 - 1184 346 1062 - 1193 349 1193 - 1203 351 1340 - 1214 354 1506 - 1225 357 1694 - 1236 359 1906 - 1247 361 2145 - 1258 363 2414 - 1270 365 2716 - 1281 366 3049 - 1293 366 3415 - 1304 366 3809 - 1314 364 4086 - 1323 361 4095 - 1330 356 4095 - 1335 348 4095 - 1338 336 4095 - 1338 321 4095 - 1330 299 4095 - 1317 272 4095 - 1305 248 4095 - 1303 242 4095 - 1303 242 4095 - 1303 242 4095 - 1176 462 1 - 1176 462 113 - 1178 463 228 - 1179 463 345 - 1182 464 464 - 1186 466 585 - 1190 467 707 - 1195 469 831 - 1201 471 956 - 1207 473 1083 - 1214 475 1214 - 1221 478 1360 - 1229 480 1526 - 1237 483 1712 - 1246 486 1922 - 1255 488 2160 - 1265 491 2429 - 1275 493 2730 - 1286 495 3062 - 1296 496 3425 - 1307 497 3817 - 1316 496 4086 - 1324 494 4095 - 1331 489 4095 - 1335 482 4095 - 1338 472 4095 - 1337 457 4095 - 1330 437 4095 - 1316 412 4095 - 1305 391 4095 - 1303 387 4095 - 1303 387 4095 - 1303 387 4095 - 1208 596 1 - 1208 596 116 - 1209 596 233 - 1210 597 353 - 1212 597 474 - 1214 599 598 - 1218 600 723 - 1221 601 848 - 1225 603 975 - 1229 605 1102 - 1233 607 1233 - 1238 609 1380 - 1244 611 1545 - 1250 614 1730 - 1257 616 1940 - 1265 619 2178 - 1273 622 2446 - 1282 625 2746 - 1291 628 3077 - 1301 630 3439 - 1310 632 3827 - 1318 632 4085 - 1326 631 4095 - 1332 628 4095 - 1336 623 4095 - 1338 615 4095 - 1337 603 4095 - 1329 586 4095 - 1315 564 4095 - 1304 547 4095 - 1303 543 4095 - 1303 543 4095 - 1303 543 4095 - 1234 732 1 - 1234 733 118 - 1235 733 237 - 1235 733 358 - 1237 734 482 - 1238 735 608 - 1240 736 735 - 1242 737 863 - 1245 738 990 - 1247 740 1118 - 1250 741 1250 - 1254 743 1397 - 1258 745 1563 - 1263 747 1749 - 1268 750 1959 - 1275 753 2197 - 1282 757 2466 - 1289 760 2765 - 1297 763 3094 - 1305 767 3454 - 1313 769 3838 - 1321 771 4085 - 1328 772 4095 - 1333 770 4095 - 1336 767 4095 - 1339 762 4095 - 1336 753 4095 - 1328 738 4095 - 1315 720 4095 - 1304 706 4095 - 1303 704 4095 - 1303 704 4095 - 1303 704 4095 - 1254 871 2 - 1254 871 119 - 1254 871 239 - 1255 871 362 - 1256 872 488 - 1257 872 616 - 1258 873 745 - 1259 874 874 - 1261 875 1003 - 1263 876 1132 - 1265 878 1265 - 1268 880 1414 - 1271 882 1580 - 1275 884 1767 - 1280 887 1978 - 1285 890 2217 - 1290 893 2486 - 1297 897 2786 - 1303 900 3113 - 1310 904 3470 - 1317 907 3850 - 1324 910 4084 - 1330 912 4095 - 1334 912 4095 - 1337 910 4095 - 1339 907 4095 - 1336 900 4095 - 1327 887 4095 - 1313 871 4095 - 1304 860 4095 - 1303 858 4095 - 1303 858 4095 - 1303 858 4095 - 1271 1010 2 - 1271 1010 119 - 1271 1010 240 - 1271 1011 365 - 1272 1011 492 - 1273 1012 622 - 1274 1012 752 - 1275 1013 883 - 1276 1014 1014 - 1278 1015 1145 - 1279 1016 1279 - 1281 1018 1429 - 1284 1020 1597 - 1287 1022 1785 - 1290 1024 1996 - 1294 1027 2237 - 1299 1031 2507 - 1304 1034 2806 - 1309 1038 3133 - 1315 1042 3487 - 1321 1045 3863 - 1327 1049 4083 - 1331 1051 4095 - 1335 1052 4095 - 1338 1051 4095 - 1338 1049 4095 - 1335 1043 4095 - 1325 1031 4095 - 1312 1017 4095 - 1303 1007 4095 - 1303 1006 4095 - 1303 1006 4095 - 1303 1006 4095 - 1285 1151 2 - 1285 1151 119 - 1285 1152 240 - 1286 1152 366 - 1286 1152 495 - 1287 1153 626 - 1287 1153 759 - 1288 1154 891 - 1289 1155 1023 - 1290 1156 1156 - 1292 1157 1292 - 1293 1158 1442 - 1295 1160 1612 - 1297 1162 1801 - 1300 1164 2014 - 1303 1167 2256 - 1307 1170 2527 - 1311 1173 2827 - 1315 1177 3152 - 1320 1181 3504 - 1325 1185 3875 - 1329 1188 4082 - 1333 1191 4095 - 1336 1192 4095 - 1338 1193 4095 - 1338 1191 4095 - 1334 1186 4095 - 1324 1175 4095 - 1311 1161 4095 - 1303 1153 4095 - 1303 1152 4095 - 1303 1152 4095 - 1303 1152 4095 - 1298 1298 2 - 1298 1298 119 - 1298 1298 240 - 1298 1298 366 - 1298 1298 496 - 1299 1299 629 - 1299 1299 764 - 1300 1300 898 - 1301 1301 1032 - 1302 1302 1165 - 1303 1303 1302 - 1304 1304 1455 - 1305 1305 1625 - 1307 1307 1816 - 1309 1309 2031 - 1311 1312 2274 - 1314 1314 2547 - 1317 1318 2847 - 1321 1321 3172 - 1325 1325 3520 - 1328 1328 3887 - 1332 1332 4081 - 1335 1335 4095 - 1337 1337 4095 - 1338 1338 4095 - 1338 1338 4095 - 1332 1332 4095 - 1322 1322 4095 - 1309 1309 4095 - 1303 1303 4095 - 1303 1303 4095 - 1303 1303 4095 - 1303 1303 4095 - 1309 1461 1 - 1309 1462 118 - 1309 1462 239 - 1309 1462 365 - 1310 1462 497 - 1310 1462 632 - 1310 1463 768 - 1311 1463 904 - 1311 1464 1039 - 1312 1465 1174 - 1313 1466 1313 - 1314 1467 1466 - 1315 1468 1639 - 1316 1469 1831 - 1317 1471 2047 - 1319 1473 2293 - 1321 1476 2567 - 1324 1479 2869 - 1326 1482 3192 - 1329 1486 3538 - 1332 1489 3898 - 1334 1492 4080 - 1336 1496 4095 - 1338 1499 4095 - 1338 1501 4095 - 1336 1500 4095 - 1330 1495 4095 - 1319 1485 4095 - 1308 1474 4095 - 1303 1470 4095 - 1303 1469 4095 - 1303 1469 4095 - 1303 1469 4095 - 1319 1646 1 - 1319 1646 116 - 1319 1646 236 - 1319 1646 363 - 1320 1646 495 - 1320 1646 632 - 1320 1647 771 - 1320 1647 909 - 1321 1648 1045 - 1321 1648 1182 - 1322 1649 1322 - 1322 1650 1477 - 1323 1651 1651 - 1324 1652 1845 - 1325 1654 2064 - 1326 1656 2311 - 1328 1658 2588 - 1329 1661 2891 - 1331 1664 3213 - 1333 1667 3555 - 1334 1670 3909 - 1336 1673 4078 - 1337 1677 4095 - 1338 1681 4095 - 1338 1683 4095 - 1334 1682 4095 - 1327 1676 4095 - 1316 1668 4095 - 1306 1659 4095 - 1303 1656 4095 - 1303 1656 4095 - 1303 1656 4095 - 1303 1656 4095 - 1328 1853 2 - 1328 1853 113 - 1328 1853 231 - 1328 1853 358 - 1328 1853 492 - 1328 1853 630 - 1328 1854 771 - 1328 1854 911 - 1328 1854 1049 - 1329 1855 1187 - 1329 1856 1329 - 1329 1856 1486 - 1330 1857 1662 - 1330 1858 1858 - 1331 1860 2079 - 1332 1861 2329 - 1333 1863 2609 - 1333 1865 2913 - 1334 1868 3235 - 1335 1871 3572 - 1336 1874 3918 - 1338 1878 4076 - 1338 1882 4095 - 1338 1886 4095 - 1336 1887 4095 - 1331 1885 4095 - 1323 1880 4095 - 1313 1872 4095 - 1304 1866 4095 - 1303 1865 4095 - 1303 1865 4095 - 1303 1865 4095 - 1303 1865 4095 - 1334 2086 3 - 1334 2087 109 - 1334 2087 225 - 1334 2087 351 - 1334 2087 486 - 1334 2087 626 - 1334 2087 770 - 1334 2088 912 - 1334 2088 1052 - 1334 2088 1191 - 1334 2089 1334 - 1334 2089 1493 - 1335 2090 1671 - 1335 2091 1869 - 1335 2092 2092 - 1336 2094 2346 - 1336 2096 2629 - 1337 2098 2936 - 1337 2100 3257 - 1338 2104 3590 - 1338 2107 3928 - 1339 2111 4074 - 1338 2115 4095 - 1336 2117 4095 - 1333 2118 4095 - 1326 2116 4095 - 1318 2111 4095 - 1309 2105 4095 - 1303 2102 4095 - 1303 2102 4095 - 1303 2102 4095 - 1303 2102 4095 - 1303 2102 4095 - 1337 2356 2 - 1337 2356 103 - 1337 2356 215 - 1337 2356 340 - 1337 2356 476 - 1337 2357 619 - 1337 2357 765 - 1337 2357 910 - 1337 2358 1051 - 1337 2358 1193 - 1337 2359 1337 - 1338 2359 1498 - 1338 2360 1678 - 1338 2361 1879 - 1338 2362 2105 - 1338 2364 2363 - 1338 2366 2651 - 1338 2368 2960 - 1338 2370 3278 - 1338 2373 3606 - 1338 2376 3924 - 1337 2379 4071 - 1335 2382 4095 - 1332 2383 4095 - 1327 2383 4095 - 1320 2381 4095 - 1312 2378 4095 - 1305 2376 4095 - 1303 2375 4095 - 1303 2375 4095 - 1303 2375 4095 - 1303 2375 4095 - 1303 2375 4095 - 1338 2661 3 - 1338 2661 95 - 1338 2661 202 - 1338 2661 326 - 1338 2662 463 - 1338 2662 609 - 1338 2662 758 - 1338 2662 905 - 1338 2662 1048 - 1338 2663 1191 - 1338 2663 1338 - 1338 2664 1501 - 1338 2664 1683 - 1338 2665 1886 - 1338 2666 2115 - 1337 2667 2377 - 1337 2668 2668 - 1337 2670 2979 - 1336 2672 3295 - 1335 2674 3614 - 1333 2675 3912 - 1331 2677 4067 - 1328 2678 4095 - 1324 2679 4095 - 1319 2679 4095 - 1312 2678 4095 - 1307 2677 4095 - 1303 2677 4095 - 1303 2677 4095 - 1303 2677 4095 - 1303 2677 4095 - 1303 2677 4095 - 1303 2677 4095 - 1333 2986 0 - 1333 2986 84 - 1333 2986 184 - 1333 2986 306 - 1333 2986 445 - 1333 2986 593 - 1333 2986 746 - 1333 2987 895 - 1333 2987 1040 - 1332 2987 1184 - 1332 2987 1332 - 1332 2987 1497 - 1332 2987 1680 - 1332 2988 1885 - 1331 2988 2117 - 1331 2989 2383 - 1330 2989 2678 - 1329 2990 2990 - 1328 2990 3301 - 1326 2991 3611 - 1324 2991 3892 - 1321 2991 4063 - 1318 2991 4095 - 1314 2991 4095 - 1310 2991 4095 - 1306 2991 4095 - 1303 2991 4095 - 1303 2991 4095 - 1303 2991 4095 - 1303 2991 4095 - 1303 2991 4095 - 1303 2991 4095 - 1303 2991 4095 - 1321 3300 0 - 1321 3300 68 - 1321 3300 159 - 1321 3300 280 - 1321 3300 420 - 1321 3300 572 - 1321 3300 728 - 1321 3300 880 - 1320 3300 1026 - 1320 3300 1171 - 1320 3300 1320 - 1320 3300 1485 - 1319 3300 1670 - 1319 3300 1877 - 1319 3300 2111 - 1318 3299 2381 - 1317 3299 2678 - 1316 3299 2991 - 1315 3298 3299 - 1314 3298 3599 - 1312 3297 3870 - 1310 3297 4060 - 1308 3296 4095 - 1306 3295 4095 - 1304 3295 4095 - 1303 3295 4095 - 1303 3295 4095 - 1303 3295 4095 - 1303 3295 4095 - 1303 3295 4095 - 1303 3295 4095 - 1303 3295 4095 - 1303 3295 4095 - 1307 3592 0 - 1307 3592 48 - 1307 3592 132 - 1307 3592 253 - 1307 3592 396 - 1307 3592 551 - 1307 3592 710 - 1307 3592 864 - 1307 3591 1011 - 1307 3591 1157 - 1307 3591 1307 - 1307 3591 1473 - 1307 3591 1659 - 1306 3591 1868 - 1306 3590 2103 - 1306 3590 2376 - 1305 3590 2677 - 1305 3589 2991 - 1304 3589 3295 - 1304 3589 3589 - 1303 3588 3854 - 1303 3588 4057 - 1303 3588 4095 - 1303 3588 4095 - 1303 3588 4095 - 1303 3588 4095 - 1303 3588 4095 - 1303 3588 4095 - 1303 3588 4095 - 1303 3588 4095 - 1303 3588 4095 - 1303 3588 4095 - 1303 3588 4095 - 1303 3852 0 - 1303 3852 36 - 1303 3852 119 - 1303 3852 242 - 1303 3852 387 - 1303 3852 543 - 1303 3852 704 - 1303 3852 858 - 1303 3852 1006 - 1303 3852 1152 - 1303 3852 1303 - 1303 3852 1469 - 1303 3852 1656 - 1303 3852 1865 - 1303 3852 2102 - 1303 3852 2375 - 1303 3852 2677 - 1303 3852 2991 - 1303 3852 3295 - 1303 3852 3588 - 1303 3852 3852 - 1303 3852 4057 - 1303 3852 4095 - 1303 3852 4095 - 1303 3852 4095 - 1303 3852 4095 - 1303 3852 4095 - 1303 3852 4095 - 1303 3852 4095 - 1303 3852 4095 - 1303 3852 4095 - 1303 3852 4095 - 1303 3852 4095 - 1303 4057 0 - 1303 4057 36 - 1303 4057 119 - 1303 4057 242 - 1303 4057 387 - 1303 4057 543 - 1303 4057 704 - 1303 4057 858 - 1303 4057 1006 - 1303 4057 1152 - 1303 4057 1303 - 1303 4057 1469 - 1303 4057 1656 - 1303 4057 1865 - 1303 4057 2102 - 1303 4057 2375 - 1303 4057 2677 - 1303 4057 2991 - 1303 4057 3295 - 1303 4057 3588 - 1303 4057 3852 - 1303 4057 4057 - 1303 4057 4095 - 1303 4057 4095 - 1303 4057 4095 - 1303 4057 4095 - 1303 4057 4095 - 1303 4057 4095 - 1303 4057 4095 - 1303 4057 4095 - 1303 4057 4095 - 1303 4057 4095 - 1303 4057 4095 - 1303 4095 0 - 1303 4095 36 - 1303 4095 119 - 1303 4095 242 - 1303 4095 387 - 1303 4095 543 - 1303 4095 704 - 1303 4095 858 - 1303 4095 1006 - 1303 4095 1152 - 1303 4095 1303 - 1303 4095 1469 - 1303 4095 1656 - 1303 4095 1865 - 1303 4095 2102 - 1303 4095 2375 - 1303 4095 2677 - 1303 4095 2991 - 1303 4095 3295 - 1303 4095 3588 - 1303 4095 3852 - 1303 4095 4057 - 1303 4095 4095 - 1303 4095 4095 - 1303 4095 4095 - 1303 4095 4095 - 1303 4095 4095 - 1303 4095 4095 - 1303 4095 4095 - 1303 4095 4095 - 1303 4095 4095 - 1303 4095 4095 - 1303 4095 4095 - 1303 4095 0 - 1303 4095 36 - 1303 4095 119 - 1303 4095 242 - 1303 4095 387 - 1303 4095 543 - 1303 4095 704 - 1303 4095 858 - 1303 4095 1006 - 1303 4095 1152 - 1303 4095 1303 - 1303 4095 1469 - 1303 4095 1656 - 1303 4095 1865 - 1303 4095 2102 - 1303 4095 2375 - 1303 4095 2677 - 1303 4095 2991 - 1303 4095 3295 - 1303 4095 3588 - 1303 4095 3852 - 1303 4095 4057 - 1303 4095 4095 - 1303 4095 4095 - 1303 4095 4095 - 1303 4095 4095 - 1303 4095 4095 - 1303 4095 4095 - 1303 4095 4095 - 1303 4095 4095 - 1303 4095 4095 - 1303 4095 4095 - 1303 4095 4095 - 1303 4095 0 - 1303 4095 36 - 1303 4095 119 - 1303 4095 242 - 1303 4095 387 - 1303 4095 543 - 1303 4095 704 - 1303 4095 858 - 1303 4095 1006 - 1303 4095 1152 - 1303 4095 1303 - 1303 4095 1469 - 1303 4095 1656 - 1303 4095 1865 - 1303 4095 2102 - 1303 4095 2375 - 1303 4095 2677 - 1303 4095 2991 - 1303 4095 3295 - 1303 4095 3588 - 1303 4095 3852 - 1303 4095 4057 - 1303 4095 4095 - 1303 4095 4095 - 1303 4095 4095 - 1303 4095 4095 - 1303 4095 4095 - 1303 4095 4095 - 1303 4095 4095 - 1303 4095 4095 - 1303 4095 4095 - 1303 4095 4095 - 1303 4095 4095 - 1303 4095 0 - 1303 4095 36 - 1303 4095 119 - 1303 4095 242 - 1303 4095 387 - 1303 4095 543 - 1303 4095 704 - 1303 4095 858 - 1303 4095 1006 - 1303 4095 1152 - 1303 4095 1303 - 1303 4095 1469 - 1303 4095 1656 - 1303 4095 1865 - 1303 4095 2102 - 1303 4095 2375 - 1303 4095 2677 - 1303 4095 2991 - 1303 4095 3295 - 1303 4095 3588 - 1303 4095 3852 - 1303 4095 4057 - 1303 4095 4095 - 1303 4095 4095 - 1303 4095 4095 - 1303 4095 4095 - 1303 4095 4095 - 1303 4095 4095 - 1303 4095 4095 - 1303 4095 4095 - 1303 4095 4095 - 1303 4095 4095 - 1303 4095 4095 - 1303 4095 0 - 1303 4095 36 - 1303 4095 119 - 1303 4095 242 - 1303 4095 387 - 1303 4095 543 - 1303 4095 704 - 1303 4095 858 - 1303 4095 1006 - 1303 4095 1152 - 1303 4095 1303 - 1303 4095 1469 - 1303 4095 1656 - 1303 4095 1865 - 1303 4095 2102 - 1303 4095 2375 - 1303 4095 2677 - 1303 4095 2991 - 1303 4095 3295 - 1303 4095 3588 - 1303 4095 3852 - 1303 4095 4057 - 1303 4095 4095 - 1303 4095 4095 - 1303 4095 4095 - 1303 4095 4095 - 1303 4095 4095 - 1303 4095 4095 - 1303 4095 4095 - 1303 4095 4095 - 1303 4095 4095 - 1303 4095 4095 - 1303 4095 4095 - 1303 4095 0 - 1303 4095 36 - 1303 4095 119 - 1303 4095 242 - 1303 4095 387 - 1303 4095 543 - 1303 4095 704 - 1303 4095 858 - 1303 4095 1006 - 1303 4095 1152 - 1303 4095 1303 - 1303 4095 1469 - 1303 4095 1656 - 1303 4095 1865 - 1303 4095 2102 - 1303 4095 2375 - 1303 4095 2677 - 1303 4095 2991 - 1303 4095 3295 - 1303 4095 3588 - 1303 4095 3852 - 1303 4095 4057 - 1303 4095 4095 - 1303 4095 4095 - 1303 4095 4095 - 1303 4095 4095 - 1303 4095 4095 - 1303 4095 4095 - 1303 4095 4095 - 1303 4095 4095 - 1303 4095 4095 - 1303 4095 4095 - 1303 4095 4095 - 1303 4095 0 - 1303 4095 36 - 1303 4095 119 - 1303 4095 242 - 1303 4095 387 - 1303 4095 543 - 1303 4095 704 - 1303 4095 858 - 1303 4095 1006 - 1303 4095 1152 - 1303 4095 1303 - 1303 4095 1469 - 1303 4095 1656 - 1303 4095 1865 - 1303 4095 2102 - 1303 4095 2375 - 1303 4095 2677 - 1303 4095 2991 - 1303 4095 3295 - 1303 4095 3588 - 1303 4095 3852 - 1303 4095 4057 - 1303 4095 4095 - 1303 4095 4095 - 1303 4095 4095 - 1303 4095 4095 - 1303 4095 4095 - 1303 4095 4095 - 1303 4095 4095 - 1303 4095 4095 - 1303 4095 4095 - 1303 4095 4095 - 1303 4095 4095 - 1303 4095 0 - 1303 4095 36 - 1303 4095 119 - 1303 4095 242 - 1303 4095 387 - 1303 4095 543 - 1303 4095 704 - 1303 4095 858 - 1303 4095 1006 - 1303 4095 1152 - 1303 4095 1303 - 1303 4095 1469 - 1303 4095 1656 - 1303 4095 1865 - 1303 4095 2102 - 1303 4095 2375 - 1303 4095 2677 - 1303 4095 2991 - 1303 4095 3295 - 1303 4095 3588 - 1303 4095 3852 - 1303 4095 4057 - 1303 4095 4095 - 1303 4095 4095 - 1303 4095 4095 - 1303 4095 4095 - 1303 4095 4095 - 1303 4095 4095 - 1303 4095 4095 - 1303 4095 4095 - 1303 4095 4095 - 1303 4095 4095 - 1303 4095 4095 - 1303 4095 0 - 1303 4095 36 - 1303 4095 119 - 1303 4095 242 - 1303 4095 387 - 1303 4095 543 - 1303 4095 704 - 1303 4095 858 - 1303 4095 1006 - 1303 4095 1152 - 1303 4095 1303 - 1303 4095 1469 - 1303 4095 1656 - 1303 4095 1865 - 1303 4095 2102 - 1303 4095 2375 - 1303 4095 2677 - 1303 4095 2991 - 1303 4095 3295 - 1303 4095 3588 - 1303 4095 3852 - 1303 4095 4057 - 1303 4095 4095 - 1303 4095 4095 - 1303 4095 4095 - 1303 4095 4095 - 1303 4095 4095 - 1303 4095 4095 - 1303 4095 4095 - 1303 4095 4095 - 1303 4095 4095 - 1303 4095 4095 - 1303 4095 4095 - 1303 4095 0 - 1303 4095 36 - 1303 4095 119 - 1303 4095 242 - 1303 4095 387 - 1303 4095 543 - 1303 4095 704 - 1303 4095 858 - 1303 4095 1006 - 1303 4095 1152 - 1303 4095 1303 - 1303 4095 1469 - 1303 4095 1656 - 1303 4095 1865 - 1303 4095 2102 - 1303 4095 2375 - 1303 4095 2677 - 1303 4095 2991 - 1303 4095 3295 - 1303 4095 3588 - 1303 4095 3852 - 1303 4095 4057 - 1303 4095 4095 - 1303 4095 4095 - 1303 4095 4095 - 1303 4095 4095 - 1303 4095 4095 - 1303 4095 4095 - 1303 4095 4095 - 1303 4095 4095 - 1303 4095 4095 - 1303 4095 4095 - 1303 4095 4095 - 1303 4095 0 - 1303 4095 36 - 1303 4095 119 - 1303 4095 242 - 1303 4095 387 - 1303 4095 543 - 1303 4095 704 - 1303 4095 858 - 1303 4095 1006 - 1303 4095 1152 - 1303 4095 1303 - 1303 4095 1469 - 1303 4095 1656 - 1303 4095 1865 - 1303 4095 2102 - 1303 4095 2375 - 1303 4095 2677 - 1303 4095 2991 - 1303 4095 3295 - 1303 4095 3588 - 1303 4095 3852 - 1303 4095 4057 - 1303 4095 4095 - 1303 4095 4095 - 1303 4095 4095 - 1303 4095 4095 - 1303 4095 4095 - 1303 4095 4095 - 1303 4095 4095 - 1303 4095 4095 - 1303 4095 4095 - 1303 4095 4095 - 1303 4095 4095 - 1279 0 2 - 1279 0 111 - 1281 0 223 - 1283 1 337 - 1287 1 454 - 1292 0 572 - 1299 0 693 - 1306 0 815 - 1314 1 939 - 1323 3 1065 - 1332 3 1195 - 1343 0 1343 - 1354 1 1509 - 1367 1 1697 - 1379 3 1908 - 1391 2 2146 - 1403 0 2415 - 1416 2 2717 - 1429 1 3050 - 1443 3 3416 - 1455 3 3810 - 1468 2 4086 - 1478 2 4095 - 1487 0 4095 - 1494 0 4095 - 1499 5 4095 - 1501 4 4095 - 1495 0 4095 - 1483 3 4095 - 1472 1 4095 - 1469 0 4095 - 1469 0 4095 - 1469 0 4095 - 1283 111 1 - 1284 111 111 - 1285 111 224 - 1288 112 338 - 1292 112 455 - 1297 112 574 - 1303 113 695 - 1310 113 817 - 1317 114 941 - 1326 115 1067 - 1335 115 1198 - 1345 116 1345 - 1357 117 1511 - 1369 117 1699 - 1380 118 1910 - 1392 118 2148 - 1404 119 2417 - 1417 119 2719 - 1430 119 3052 - 1443 119 3417 - 1456 118 3811 - 1468 117 4086 - 1479 115 4095 - 1488 111 4095 - 1494 107 4095 - 1499 101 4095 - 1501 92 4095 - 1495 79 4095 - 1482 62 4095 - 1471 42 4095 - 1469 36 4095 - 1469 36 4095 - 1469 36 4095 - 1297 226 1 - 1298 226 112 - 1299 226 226 - 1301 227 342 - 1305 227 460 - 1309 228 580 - 1315 229 701 - 1321 230 824 - 1328 231 949 - 1336 232 1075 - 1344 233 1206 - 1353 234 1353 - 1363 236 1519 - 1374 237 1706 - 1385 238 1916 - 1395 239 2154 - 1407 240 2423 - 1419 240 2724 - 1432 241 3057 - 1445 240 3421 - 1457 239 3814 - 1469 237 4086 - 1479 234 4095 - 1488 229 4095 - 1494 221 4095 - 1499 211 4095 - 1501 196 4095 - 1495 176 4095 - 1482 151 4095 - 1471 126 4095 - 1469 119 4095 - 1469 119 4095 - 1469 119 4095 - 1319 346 1 - 1319 346 114 - 1320 347 229 - 1322 347 347 - 1325 348 466 - 1329 349 588 - 1334 350 711 - 1339 351 835 - 1345 352 961 - 1351 354 1087 - 1358 355 1219 - 1366 357 1365 - 1374 358 1531 - 1382 360 1716 - 1391 361 1926 - 1401 363 2164 - 1412 364 2432 - 1423 365 2733 - 1435 366 3065 - 1447 366 3428 - 1459 366 3819 - 1470 364 4086 - 1480 360 4095 - 1489 355 4095 - 1495 346 4095 - 1500 335 4095 - 1501 319 4095 - 1494 298 4095 - 1482 271 4095 - 1471 247 4095 - 1469 242 4095 - 1469 242 4095 - 1469 242 4095 - 1345 473 2 - 1345 473 116 - 1346 473 233 - 1347 474 352 - 1349 474 474 - 1352 475 597 - 1356 476 722 - 1360 478 848 - 1364 479 974 - 1369 480 1101 - 1374 482 1233 - 1379 483 1379 - 1386 485 1544 - 1393 487 1730 - 1400 488 1939 - 1409 490 2177 - 1419 492 2445 - 1429 494 2746 - 1440 496 3076 - 1451 497 3438 - 1462 497 3826 - 1472 496 4085 - 1482 493 4095 - 1489 488 4095 - 1495 481 4095 - 1500 471 4095 - 1500 456 4095 - 1494 436 4095 - 1481 411 4095 - 1471 390 4095 - 1469 387 4095 - 1469 387 4095 - 1469 387 4095 - 1369 605 2 - 1369 605 117 - 1370 605 236 - 1371 605 357 - 1372 606 481 - 1374 607 606 - 1377 607 733 - 1379 609 860 - 1382 610 987 - 1386 611 1115 - 1389 612 1247 - 1394 614 1393 - 1399 615 1559 - 1404 617 1744 - 1411 619 1954 - 1418 622 2192 - 1427 624 2461 - 1436 627 2761 - 1445 629 3090 - 1455 631 3450 - 1465 632 3835 - 1475 632 4085 - 1483 631 4095 - 1491 628 4095 - 1496 622 4095 - 1500 614 4095 - 1500 602 4095 - 1493 584 4095 - 1481 563 4095 - 1471 546 4095 - 1469 543 4095 - 1469 543 4095 - 1469 543 4095 - 1390 740 2 - 1390 740 118 - 1391 740 238 - 1391 740 361 - 1392 741 486 - 1394 741 613 - 1395 742 741 - 1397 743 870 - 1399 744 998 - 1402 745 1127 - 1405 746 1260 - 1408 748 1408 - 1412 749 1574 - 1417 751 1760 - 1422 754 1971 - 1428 756 2210 - 1436 759 2478 - 1443 762 2778 - 1452 765 3106 - 1460 768 3464 - 1469 770 3846 - 1478 771 4084 - 1485 772 4095 - 1492 770 4095 - 1497 767 4095 - 1500 761 4095 - 1500 752 4095 - 1492 737 4095 - 1480 719 4095 - 1471 706 4095 - 1469 704 4095 - 1469 704 4095 - 1469 704 4095 - 1408 876 2 - 1408 876 119 - 1408 877 240 - 1409 877 364 - 1410 877 490 - 1411 878 619 - 1412 879 749 - 1413 879 879 - 1415 880 1009 - 1417 881 1139 - 1419 883 1273 - 1422 884 1422 - 1425 886 1589 - 1429 888 1777 - 1434 890 1988 - 1439 893 2227 - 1445 896 2497 - 1451 899 2797 - 1458 902 3124 - 1466 905 3479 - 1473 908 3857 - 1481 911 4084 - 1488 912 4095 - 1493 912 4095 - 1498 910 4095 - 1501 907 4095 - 1499 899 4095 - 1491 886 4095 - 1479 871 4095 - 1470 860 4095 - 1469 858 4095 - 1469 858 4095 - 1469 858 4095 - 1424 1015 3 - 1425 1015 119 - 1425 1015 240 - 1425 1016 365 - 1426 1016 493 - 1427 1016 624 - 1427 1017 755 - 1429 1018 887 - 1430 1019 1018 - 1431 1020 1150 - 1433 1021 1285 - 1435 1022 1435 - 1438 1024 1604 - 1441 1026 1792 - 1445 1028 2005 - 1449 1030 2245 - 1454 1033 2516 - 1459 1036 2816 - 1465 1040 3142 - 1471 1043 3494 - 1478 1046 3868 - 1484 1049 4083 - 1490 1051 4095 - 1494 1052 4095 - 1499 1051 4095 - 1501 1049 4095 - 1498 1042 4095 - 1490 1030 4095 - 1478 1016 4095 - 1470 1007 4095 - 1469 1006 4095 - 1469 1006 4095 - 1469 1006 4095 - 1439 1156 1 - 1439 1156 119 - 1439 1156 240 - 1440 1156 366 - 1440 1157 496 - 1441 1157 628 - 1441 1158 761 - 1442 1158 894 - 1443 1159 1027 - 1445 1160 1160 - 1446 1161 1296 - 1448 1162 1447 - 1450 1164 1617 - 1452 1165 1807 - 1455 1167 2021 - 1458 1170 2263 - 1462 1172 2535 - 1467 1176 2835 - 1471 1179 3160 - 1477 1182 3510 - 1482 1186 3880 - 1487 1189 4082 - 1492 1191 4095 - 1496 1192 4095 - 1500 1193 4095 - 1501 1191 4095 - 1497 1185 4095 - 1488 1174 4095 - 1477 1161 4095 - 1470 1153 4095 - 1469 1152 4095 - 1469 1152 4095 - 1469 1152 4095 - 1452 1302 1 - 1452 1302 118 - 1452 1302 240 - 1453 1302 366 - 1453 1302 497 - 1453 1303 630 - 1454 1303 765 - 1455 1304 900 - 1456 1304 1034 - 1456 1305 1168 - 1457 1306 1306 - 1459 1307 1459 - 1460 1308 1630 - 1462 1310 1821 - 1464 1312 2036 - 1467 1314 2280 - 1470 1317 2553 - 1474 1320 2854 - 1478 1323 3178 - 1482 1326 3526 - 1486 1329 3891 - 1490 1333 4081 - 1494 1335 4095 - 1497 1337 4095 - 1500 1339 4095 - 1501 1337 4095 - 1496 1331 4095 - 1486 1321 4095 - 1475 1309 4095 - 1470 1303 4095 - 1469 1303 4095 - 1469 1303 4095 - 1469 1303 4095 - 1465 1465 3 - 1465 1465 117 - 1465 1465 238 - 1465 1465 365 - 1465 1465 497 - 1465 1466 632 - 1466 1466 769 - 1466 1467 905 - 1467 1467 1041 - 1468 1468 1176 - 1468 1469 1315 - 1469 1470 1469 - 1471 1471 1642 - 1472 1472 1835 - 1474 1474 2052 - 1476 1476 2298 - 1478 1478 2573 - 1481 1481 2875 - 1484 1484 3198 - 1487 1487 3542 - 1490 1490 3901 - 1493 1493 4079 - 1496 1496 4095 - 1499 1499 4095 - 1501 1501 4095 - 1500 1500 4095 - 1494 1494 4095 - 1484 1484 4095 - 1474 1474 4095 - 1470 1470 4095 - 1469 1469 4095 - 1469 1469 4095 - 1469 1469 4095 - 1476 1648 1 - 1476 1648 115 - 1476 1648 235 - 1476 1649 362 - 1476 1649 495 - 1476 1649 632 - 1477 1649 771 - 1477 1650 909 - 1477 1650 1046 - 1478 1651 1183 - 1478 1652 1323 - 1479 1652 1479 - 1480 1653 1653 - 1481 1655 1848 - 1482 1656 2067 - 1484 1658 2315 - 1485 1660 2593 - 1487 1662 2896 - 1489 1665 3218 - 1491 1668 3559 - 1494 1671 3911 - 1496 1674 4078 - 1498 1678 4095 - 1500 1681 4095 - 1501 1683 4095 - 1498 1682 4095 - 1491 1676 4095 - 1481 1667 4095 - 1472 1659 4095 - 1469 1656 4095 - 1469 1656 4095 - 1469 1656 4095 - 1469 1656 4095 - 1485 1855 2 - 1485 1855 112 - 1485 1855 230 - 1485 1855 357 - 1486 1855 491 - 1486 1856 630 - 1486 1856 771 - 1486 1856 912 - 1486 1857 1050 - 1487 1857 1188 - 1487 1858 1330 - 1487 1858 1487 - 1488 1859 1663 - 1489 1860 1860 - 1489 1861 2081 - 1490 1863 2332 - 1491 1865 2612 - 1492 1867 2917 - 1494 1869 3238 - 1495 1872 3575 - 1497 1875 3920 - 1499 1879 4076 - 1500 1883 4095 - 1501 1886 4095 - 1499 1887 4095 - 1495 1885 4095 - 1488 1880 4095 - 1478 1872 4095 - 1471 1866 4095 - 1469 1865 4095 - 1469 1865 4095 - 1469 1865 4095 - 1469 1865 4095 - 1493 2088 1 - 1493 2088 108 - 1493 2088 224 - 1493 2089 350 - 1493 2089 485 - 1493 2089 626 - 1493 2089 769 - 1493 2089 912 - 1493 2090 1052 - 1493 2090 1191 - 1494 2091 1335 - 1494 2091 1494 - 1494 2092 1672 - 1494 2093 1870 - 1495 2094 2094 - 1495 2095 2349 - 1496 2097 2632 - 1497 2099 2939 - 1498 2102 3260 - 1499 2105 3593 - 1500 2108 3929 - 1501 2112 4073 - 1501 2115 4095 - 1500 2117 4095 - 1496 2118 4095 - 1491 2115 4095 - 1483 2110 4095 - 1475 2105 4095 - 1470 2102 4095 - 1469 2102 4095 - 1469 2102 4095 - 1469 2102 4095 - 1469 2102 4095 - 1498 2358 2 - 1498 2358 102 - 1498 2358 214 - 1498 2358 339 - 1498 2358 475 - 1498 2359 618 - 1498 2359 765 - 1498 2359 909 - 1498 2360 1051 - 1498 2360 1193 - 1499 2360 1338 - 1499 2361 1499 - 1499 2362 1679 - 1499 2363 1880 - 1499 2364 2106 - 1500 2365 2365 - 1500 2367 2653 - 1500 2369 2962 - 1501 2372 3280 - 1501 2374 3607 - 1501 2377 3923 - 1500 2380 4070 - 1498 2382 4095 - 1496 2383 4095 - 1491 2383 4095 - 1485 2381 4095 - 1478 2378 4095 - 1472 2376 4095 - 1469 2375 4095 - 1469 2375 4095 - 1469 2375 4095 - 1469 2375 4095 - 1469 2375 4095 - 1501 2663 2 - 1501 2663 94 - 1501 2663 201 - 1501 2663 325 - 1501 2663 462 - 1501 2663 608 - 1501 2663 757 - 1501 2664 905 - 1501 2664 1048 - 1501 2664 1191 - 1501 2665 1338 - 1501 2665 1501 - 1501 2666 1683 - 1501 2666 1886 - 1501 2667 2116 - 1500 2668 2378 - 1500 2670 2669 - 1500 2671 2980 - 1499 2673 3296 - 1498 2674 3614 - 1497 2676 3910 - 1495 2678 4067 - 1492 2679 4095 - 1489 2679 4095 - 1484 2679 4095 - 1478 2678 4095 - 1473 2677 4095 - 1470 2677 4095 - 1469 2677 4095 - 1469 2677 4095 - 1469 2677 4095 - 1469 2677 4095 - 1469 2677 4095 - 1497 2987 0 - 1497 2987 83 - 1497 2987 182 - 1497 2987 305 - 1497 2987 443 - 1497 2987 592 - 1497 2987 745 - 1497 2987 894 - 1497 2987 1039 - 1496 2987 1184 - 1496 2988 1332 - 1496 2988 1496 - 1496 2988 1680 - 1496 2988 1885 - 1495 2989 2117 - 1495 2989 2383 - 1494 2990 2678 - 1493 2990 2990 - 1492 2990 3301 - 1490 2991 3610 - 1489 2991 3891 - 1486 2992 4063 - 1483 2991 4095 - 1480 2991 4095 - 1476 2991 4095 - 1472 2991 4095 - 1470 2991 4095 - 1469 2991 4095 - 1469 2991 4095 - 1469 2991 4095 - 1469 2991 4095 - 1469 2991 4095 - 1469 2991 4095 - 1486 3300 1 - 1486 3300 67 - 1486 3300 158 - 1486 3300 279 - 1486 3300 419 - 1486 3300 571 - 1486 3300 727 - 1485 3300 879 - 1485 3300 1025 - 1485 3300 1170 - 1485 3300 1319 - 1485 3300 1485 - 1484 3300 1670 - 1484 3299 1877 - 1484 3299 2111 - 1483 3299 2380 - 1482 3299 2678 - 1481 3299 2991 - 1480 3298 3298 - 1479 3298 3598 - 1478 3297 3868 - 1476 3296 4060 - 1474 3296 4095 - 1472 3295 4095 - 1470 3295 4095 - 1470 3295 4095 - 1469 3295 4095 - 1469 3295 4095 - 1469 3295 4095 - 1469 3295 4095 - 1469 3295 4095 - 1469 3295 4095 - 1469 3295 4095 - 1473 3591 1 - 1473 3591 47 - 1473 3591 131 - 1473 3591 252 - 1473 3591 395 - 1473 3591 551 - 1473 3591 710 - 1473 3591 864 - 1473 3591 1011 - 1473 3591 1157 - 1473 3591 1306 - 1473 3591 1473 - 1473 3591 1659 - 1473 3590 1867 - 1472 3590 2103 - 1472 3590 2376 - 1472 3590 2677 - 1471 3589 2991 - 1471 3589 3295 - 1471 3588 3589 - 1470 3588 3853 - 1470 3588 4057 - 1470 3588 4095 - 1469 3588 4095 - 1469 3588 4095 - 1469 3588 4095 - 1469 3588 4095 - 1469 3588 4095 - 1469 3588 4095 - 1469 3588 4095 - 1469 3588 4095 - 1469 3588 4095 - 1469 3588 4095 - 1469 3852 0 - 1469 3852 36 - 1469 3852 119 - 1469 3852 242 - 1469 3852 387 - 1469 3852 543 - 1469 3852 704 - 1469 3852 858 - 1469 3852 1006 - 1469 3852 1152 - 1469 3852 1303 - 1469 3852 1469 - 1469 3852 1656 - 1469 3852 1865 - 1469 3852 2102 - 1469 3852 2375 - 1469 3852 2677 - 1469 3852 2991 - 1469 3852 3295 - 1469 3852 3588 - 1469 3852 3852 - 1469 3852 4057 - 1469 3852 4095 - 1469 3852 4095 - 1469 3852 4095 - 1469 3852 4095 - 1469 3852 4095 - 1469 3852 4095 - 1469 3852 4095 - 1469 3852 4095 - 1469 3852 4095 - 1469 3852 4095 - 1469 3852 4095 - 1469 4057 0 - 1469 4057 36 - 1469 4057 119 - 1469 4057 242 - 1469 4057 387 - 1469 4057 543 - 1469 4057 704 - 1469 4057 858 - 1469 4057 1006 - 1469 4057 1152 - 1469 4057 1303 - 1469 4057 1469 - 1469 4057 1656 - 1469 4057 1865 - 1469 4057 2102 - 1469 4057 2375 - 1469 4057 2677 - 1469 4057 2991 - 1469 4057 3295 - 1469 4057 3588 - 1469 4057 3852 - 1469 4057 4057 - 1469 4057 4095 - 1469 4057 4095 - 1469 4057 4095 - 1469 4057 4095 - 1469 4057 4095 - 1469 4057 4095 - 1469 4057 4095 - 1469 4057 4095 - 1469 4057 4095 - 1469 4057 4095 - 1469 4057 4095 - 1469 4095 0 - 1469 4095 36 - 1469 4095 119 - 1469 4095 242 - 1469 4095 387 - 1469 4095 543 - 1469 4095 704 - 1469 4095 858 - 1469 4095 1006 - 1469 4095 1152 - 1469 4095 1303 - 1469 4095 1469 - 1469 4095 1656 - 1469 4095 1865 - 1469 4095 2102 - 1469 4095 2375 - 1469 4095 2677 - 1469 4095 2991 - 1469 4095 3295 - 1469 4095 3588 - 1469 4095 3852 - 1469 4095 4057 - 1469 4095 4095 - 1469 4095 4095 - 1469 4095 4095 - 1469 4095 4095 - 1469 4095 4095 - 1469 4095 4095 - 1469 4095 4095 - 1469 4095 4095 - 1469 4095 4095 - 1469 4095 4095 - 1469 4095 4095 - 1469 4095 0 - 1469 4095 36 - 1469 4095 119 - 1469 4095 242 - 1469 4095 387 - 1469 4095 543 - 1469 4095 704 - 1469 4095 858 - 1469 4095 1006 - 1469 4095 1152 - 1469 4095 1303 - 1469 4095 1469 - 1469 4095 1656 - 1469 4095 1865 - 1469 4095 2102 - 1469 4095 2375 - 1469 4095 2677 - 1469 4095 2991 - 1469 4095 3295 - 1469 4095 3588 - 1469 4095 3852 - 1469 4095 4057 - 1469 4095 4095 - 1469 4095 4095 - 1469 4095 4095 - 1469 4095 4095 - 1469 4095 4095 - 1469 4095 4095 - 1469 4095 4095 - 1469 4095 4095 - 1469 4095 4095 - 1469 4095 4095 - 1469 4095 4095 - 1469 4095 0 - 1469 4095 36 - 1469 4095 119 - 1469 4095 242 - 1469 4095 387 - 1469 4095 543 - 1469 4095 704 - 1469 4095 858 - 1469 4095 1006 - 1469 4095 1152 - 1469 4095 1303 - 1469 4095 1469 - 1469 4095 1656 - 1469 4095 1865 - 1469 4095 2102 - 1469 4095 2375 - 1469 4095 2677 - 1469 4095 2991 - 1469 4095 3295 - 1469 4095 3588 - 1469 4095 3852 - 1469 4095 4057 - 1469 4095 4095 - 1469 4095 4095 - 1469 4095 4095 - 1469 4095 4095 - 1469 4095 4095 - 1469 4095 4095 - 1469 4095 4095 - 1469 4095 4095 - 1469 4095 4095 - 1469 4095 4095 - 1469 4095 4095 - 1469 4095 0 - 1469 4095 36 - 1469 4095 119 - 1469 4095 242 - 1469 4095 387 - 1469 4095 543 - 1469 4095 704 - 1469 4095 858 - 1469 4095 1006 - 1469 4095 1152 - 1469 4095 1303 - 1469 4095 1469 - 1469 4095 1656 - 1469 4095 1865 - 1469 4095 2102 - 1469 4095 2375 - 1469 4095 2677 - 1469 4095 2991 - 1469 4095 3295 - 1469 4095 3588 - 1469 4095 3852 - 1469 4095 4057 - 1469 4095 4095 - 1469 4095 4095 - 1469 4095 4095 - 1469 4095 4095 - 1469 4095 4095 - 1469 4095 4095 - 1469 4095 4095 - 1469 4095 4095 - 1469 4095 4095 - 1469 4095 4095 - 1469 4095 4095 - 1469 4095 0 - 1469 4095 36 - 1469 4095 119 - 1469 4095 242 - 1469 4095 387 - 1469 4095 543 - 1469 4095 704 - 1469 4095 858 - 1469 4095 1006 - 1469 4095 1152 - 1469 4095 1303 - 1469 4095 1469 - 1469 4095 1656 - 1469 4095 1865 - 1469 4095 2102 - 1469 4095 2375 - 1469 4095 2677 - 1469 4095 2991 - 1469 4095 3295 - 1469 4095 3588 - 1469 4095 3852 - 1469 4095 4057 - 1469 4095 4095 - 1469 4095 4095 - 1469 4095 4095 - 1469 4095 4095 - 1469 4095 4095 - 1469 4095 4095 - 1469 4095 4095 - 1469 4095 4095 - 1469 4095 4095 - 1469 4095 4095 - 1469 4095 4095 - 1469 4095 0 - 1469 4095 36 - 1469 4095 119 - 1469 4095 242 - 1469 4095 387 - 1469 4095 543 - 1469 4095 704 - 1469 4095 858 - 1469 4095 1006 - 1469 4095 1152 - 1469 4095 1303 - 1469 4095 1469 - 1469 4095 1656 - 1469 4095 1865 - 1469 4095 2102 - 1469 4095 2375 - 1469 4095 2677 - 1469 4095 2991 - 1469 4095 3295 - 1469 4095 3588 - 1469 4095 3852 - 1469 4095 4057 - 1469 4095 4095 - 1469 4095 4095 - 1469 4095 4095 - 1469 4095 4095 - 1469 4095 4095 - 1469 4095 4095 - 1469 4095 4095 - 1469 4095 4095 - 1469 4095 4095 - 1469 4095 4095 - 1469 4095 4095 - 1469 4095 0 - 1469 4095 36 - 1469 4095 119 - 1469 4095 242 - 1469 4095 387 - 1469 4095 543 - 1469 4095 704 - 1469 4095 858 - 1469 4095 1006 - 1469 4095 1152 - 1469 4095 1303 - 1469 4095 1469 - 1469 4095 1656 - 1469 4095 1865 - 1469 4095 2102 - 1469 4095 2375 - 1469 4095 2677 - 1469 4095 2991 - 1469 4095 3295 - 1469 4095 3588 - 1469 4095 3852 - 1469 4095 4057 - 1469 4095 4095 - 1469 4095 4095 - 1469 4095 4095 - 1469 4095 4095 - 1469 4095 4095 - 1469 4095 4095 - 1469 4095 4095 - 1469 4095 4095 - 1469 4095 4095 - 1469 4095 4095 - 1469 4095 4095 - 1469 4095 0 - 1469 4095 36 - 1469 4095 119 - 1469 4095 242 - 1469 4095 387 - 1469 4095 543 - 1469 4095 704 - 1469 4095 858 - 1469 4095 1006 - 1469 4095 1152 - 1469 4095 1303 - 1469 4095 1469 - 1469 4095 1656 - 1469 4095 1865 - 1469 4095 2102 - 1469 4095 2375 - 1469 4095 2677 - 1469 4095 2991 - 1469 4095 3295 - 1469 4095 3588 - 1469 4095 3852 - 1469 4095 4057 - 1469 4095 4095 - 1469 4095 4095 - 1469 4095 4095 - 1469 4095 4095 - 1469 4095 4095 - 1469 4095 4095 - 1469 4095 4095 - 1469 4095 4095 - 1469 4095 4095 - 1469 4095 4095 - 1469 4095 4095 - 1469 4095 0 - 1469 4095 36 - 1469 4095 119 - 1469 4095 242 - 1469 4095 387 - 1469 4095 543 - 1469 4095 704 - 1469 4095 858 - 1469 4095 1006 - 1469 4095 1152 - 1469 4095 1303 - 1469 4095 1469 - 1469 4095 1656 - 1469 4095 1865 - 1469 4095 2102 - 1469 4095 2375 - 1469 4095 2677 - 1469 4095 2991 - 1469 4095 3295 - 1469 4095 3588 - 1469 4095 3852 - 1469 4095 4057 - 1469 4095 4095 - 1469 4095 4095 - 1469 4095 4095 - 1469 4095 4095 - 1469 4095 4095 - 1469 4095 4095 - 1469 4095 4095 - 1469 4095 4095 - 1469 4095 4095 - 1469 4095 4095 - 1469 4095 4095 - 1469 4095 0 - 1469 4095 36 - 1469 4095 119 - 1469 4095 242 - 1469 4095 387 - 1469 4095 543 - 1469 4095 704 - 1469 4095 858 - 1469 4095 1006 - 1469 4095 1152 - 1469 4095 1303 - 1469 4095 1469 - 1469 4095 1656 - 1469 4095 1865 - 1469 4095 2102 - 1469 4095 2375 - 1469 4095 2677 - 1469 4095 2991 - 1469 4095 3295 - 1469 4095 3588 - 1469 4095 3852 - 1469 4095 4057 - 1469 4095 4095 - 1469 4095 4095 - 1469 4095 4095 - 1469 4095 4095 - 1469 4095 4095 - 1469 4095 4095 - 1469 4095 4095 - 1469 4095 4095 - 1469 4095 4095 - 1469 4095 4095 - 1469 4095 4095 - 1469 4095 0 - 1469 4095 36 - 1469 4095 119 - 1469 4095 242 - 1469 4095 387 - 1469 4095 543 - 1469 4095 704 - 1469 4095 858 - 1469 4095 1006 - 1469 4095 1152 - 1469 4095 1303 - 1469 4095 1469 - 1469 4095 1656 - 1469 4095 1865 - 1469 4095 2102 - 1469 4095 2375 - 1469 4095 2677 - 1469 4095 2991 - 1469 4095 3295 - 1469 4095 3588 - 1469 4095 3852 - 1469 4095 4057 - 1469 4095 4095 - 1469 4095 4095 - 1469 4095 4095 - 1469 4095 4095 - 1469 4095 4095 - 1469 4095 4095 - 1469 4095 4095 - 1469 4095 4095 - 1469 4095 4095 - 1469 4095 4095 - 1469 4095 4095 - 1483 0 1 - 1483 1 115 - 1484 1 231 - 1486 2 349 - 1489 1 470 - 1493 1 592 - 1498 0 716 - 1503 0 841 - 1509 1 967 - 1515 1 1094 - 1522 1 1225 - 1529 1 1372 - 1537 2 1537 - 1546 0 1722 - 1555 2 1932 - 1566 2 2169 - 1578 2 2438 - 1590 1 2739 - 1603 3 3070 - 1616 0 3432 - 1630 3 3822 - 1643 2 4085 - 1654 2 4095 - 1665 0 4095 - 1673 2 4095 - 1680 4 4095 - 1683 3 4095 - 1678 2 4095 - 1667 3 4095 - 1658 1 4095 - 1656 0 4095 - 1656 0 4095 - 1656 0 4095 - 1486 115 2 - 1487 115 115 - 1488 115 231 - 1490 115 350 - 1492 115 471 - 1496 116 593 - 1500 116 718 - 1505 116 843 - 1511 117 969 - 1517 117 1096 - 1524 117 1227 - 1531 118 1374 - 1539 118 1538 - 1547 118 1724 - 1557 119 1933 - 1567 119 2171 - 1578 119 2440 - 1591 119 2740 - 1604 119 3071 - 1617 118 3434 - 1630 118 3823 - 1643 116 4085 - 1655 114 4095 - 1665 111 4095 - 1673 106 4095 - 1680 100 4095 - 1683 91 4095 - 1678 78 4095 - 1667 61 4095 - 1658 41 4095 - 1656 36 4095 - 1656 36 4095 - 1656 36 4095 - 1496 233 1 - 1497 233 116 - 1498 233 233 - 1499 233 352 - 1502 233 473 - 1505 234 597 - 1509 234 722 - 1514 235 847 - 1519 235 973 - 1524 236 1101 - 1530 237 1232 - 1536 237 1378 - 1543 238 1543 - 1551 239 1729 - 1560 239 1938 - 1570 240 2176 - 1581 240 2444 - 1593 241 2745 - 1606 240 3075 - 1618 240 3437 - 1631 239 3826 - 1644 236 4085 - 1655 233 4095 - 1665 227 4095 - 1673 220 4095 - 1680 209 4095 - 1683 195 4095 - 1678 175 4095 - 1667 149 4095 - 1658 125 4095 - 1656 119 4095 - 1656 119 4095 - 1656 119 4095 - 1512 355 2 - 1512 355 117 - 1513 355 235 - 1515 355 355 - 1517 356 477 - 1519 356 602 - 1523 357 728 - 1526 357 854 - 1530 358 981 - 1535 359 1108 - 1540 360 1240 - 1545 360 1386 - 1551 361 1551 - 1558 362 1737 - 1567 363 1946 - 1576 364 2184 - 1586 365 2452 - 1597 366 2752 - 1609 366 3083 - 1621 366 3443 - 1633 365 3830 - 1645 363 4085 - 1656 359 4095 - 1666 353 4095 - 1674 345 4095 - 1680 333 4095 - 1683 317 4095 - 1678 296 4095 - 1667 269 4095 - 1657 246 4095 - 1656 242 4095 - 1656 242 4095 - 1656 242 4095 - 1530 481 2 - 1530 481 118 - 1531 482 237 - 1532 482 358 - 1534 482 482 - 1536 483 607 - 1538 483 734 - 1541 484 861 - 1544 485 989 - 1548 486 1117 - 1551 486 1249 - 1556 487 1396 - 1561 488 1561 - 1568 490 1747 - 1575 491 1957 - 1583 493 2195 - 1593 494 2464 - 1603 495 2763 - 1614 496 3093 - 1625 497 3452 - 1636 497 3837 - 1647 495 4085 - 1658 492 4095 - 1667 487 4095 - 1674 480 4095 - 1681 469 4095 - 1683 454 4095 - 1677 434 4095 - 1666 409 4095 - 1657 390 4095 - 1656 387 4095 - 1656 387 4095 - 1656 387 4095 - 1548 612 2 - 1548 612 118 - 1549 612 238 - 1549 612 361 - 1551 613 486 - 1552 613 613 - 1554 614 741 - 1556 614 869 - 1559 615 998 - 1562 616 1127 - 1565 617 1259 - 1569 618 1407 - 1573 619 1573 - 1579 621 1760 - 1585 623 1970 - 1592 624 2209 - 1600 626 2477 - 1609 628 2777 - 1619 630 3105 - 1629 631 3463 - 1640 632 3845 - 1650 632 4084 - 1660 630 4095 - 1668 627 4095 - 1675 621 4095 - 1681 613 4095 - 1683 600 4095 - 1677 583 4095 - 1666 562 4095 - 1657 546 4095 - 1656 543 4095 - 1656 543 4095 - 1656 543 4095 - 1565 746 2 - 1566 746 119 - 1566 746 239 - 1566 746 363 - 1567 747 489 - 1569 747 618 - 1570 748 747 - 1572 748 877 - 1574 749 1007 - 1576 750 1136 - 1579 751 1270 - 1582 752 1419 - 1586 754 1586 - 1591 755 1773 - 1596 757 1984 - 1602 759 2224 - 1609 762 2493 - 1617 764 2792 - 1626 767 3120 - 1635 769 3475 - 1644 771 3855 - 1653 772 4084 - 1662 771 4095 - 1670 769 4095 - 1676 766 4095 - 1682 760 4095 - 1682 750 4095 - 1676 736 4095 - 1665 718 4095 - 1657 705 4095 - 1656 704 4095 - 1656 704 4095 - 1656 704 4095 - 1582 882 2 - 1582 883 119 - 1583 883 240 - 1583 883 365 - 1584 883 492 - 1585 884 622 - 1586 884 753 - 1587 885 885 - 1589 886 1015 - 1591 887 1146 - 1593 888 1281 - 1596 889 1431 - 1599 890 1599 - 1603 892 1787 - 1607 894 1999 - 1612 896 2239 - 1618 899 2510 - 1625 901 2809 - 1633 904 3136 - 1641 907 3489 - 1649 909 3865 - 1657 911 4083 - 1665 912 4095 - 1671 911 4095 - 1678 910 4095 - 1682 906 4095 - 1682 898 4095 - 1675 885 4095 - 1664 870 4095 - 1657 859 4095 - 1656 858 4095 - 1656 858 4095 - 1656 858 4095 - 1598 1021 3 - 1598 1021 119 - 1598 1021 240 - 1599 1021 366 - 1599 1021 495 - 1600 1022 626 - 1601 1022 759 - 1602 1023 891 - 1604 1024 1023 - 1605 1024 1156 - 1607 1025 1291 - 1609 1027 1442 - 1612 1028 1611 - 1615 1030 1801 - 1618 1031 2014 - 1623 1034 2256 - 1628 1036 2527 - 1633 1039 2827 - 1640 1042 3152 - 1646 1045 3503 - 1654 1048 3875 - 1661 1050 4082 - 1667 1051 4095 - 1673 1052 4095 - 1679 1051 4095 - 1683 1048 4095 - 1681 1041 4095 - 1674 1029 4095 - 1663 1015 4095 - 1657 1006 4095 - 1656 1006 4095 - 1656 1006 4095 - 1656 1006 4095 - 1613 1161 2 - 1613 1161 119 - 1613 1161 240 - 1613 1161 366 - 1614 1161 496 - 1614 1162 629 - 1615 1162 763 - 1616 1163 897 - 1617 1163 1031 - 1618 1164 1164 - 1620 1165 1301 - 1621 1166 1453 - 1623 1167 1623 - 1626 1169 1814 - 1629 1171 2028 - 1633 1173 2272 - 1637 1175 2544 - 1641 1178 2844 - 1647 1181 3169 - 1652 1184 3518 - 1658 1187 3885 - 1664 1189 4081 - 1670 1191 4095 - 1675 1192 4095 - 1680 1193 4095 - 1683 1191 4095 - 1681 1184 4095 - 1672 1173 4095 - 1662 1160 4095 - 1656 1153 4095 - 1656 1152 4095 - 1656 1152 4095 - 1656 1152 4095 - 1626 1306 1 - 1626 1306 118 - 1627 1306 239 - 1627 1306 366 - 1627 1307 497 - 1628 1307 631 - 1628 1307 767 - 1629 1308 902 - 1630 1308 1037 - 1631 1309 1172 - 1632 1310 1310 - 1633 1311 1463 - 1635 1312 1635 - 1637 1313 1827 - 1639 1315 2042 - 1642 1317 2287 - 1645 1319 2561 - 1649 1322 2862 - 1653 1325 3186 - 1658 1328 3533 - 1663 1331 3895 - 1668 1333 4080 - 1672 1336 4095 - 1677 1338 4095 - 1682 1339 4095 - 1683 1337 4095 - 1679 1331 4095 - 1671 1320 4095 - 1661 1308 4095 - 1656 1303 4095 - 1656 1303 4095 - 1656 1303 4095 - 1656 1303 4095 - 1639 1469 2 - 1639 1469 117 - 1639 1469 237 - 1640 1469 364 - 1640 1469 496 - 1640 1469 632 - 1641 1470 770 - 1641 1470 907 - 1642 1471 1043 - 1643 1471 1179 - 1643 1472 1318 - 1644 1473 1473 - 1646 1474 1646 - 1647 1475 1839 - 1649 1477 2057 - 1651 1478 2303 - 1654 1481 2579 - 1657 1483 2881 - 1660 1486 3204 - 1664 1488 3548 - 1668 1491 3904 - 1671 1494 4079 - 1675 1497 4095 - 1680 1500 4095 - 1683 1501 4095 - 1682 1499 4095 - 1678 1493 4095 - 1669 1483 4095 - 1660 1473 4095 - 1656 1469 4095 - 1656 1469 4095 - 1656 1469 4095 - 1656 1469 4095 - 1651 1652 2 - 1651 1652 115 - 1651 1652 234 - 1652 1652 361 - 1652 1652 494 - 1652 1652 632 - 1652 1653 771 - 1653 1653 910 - 1653 1653 1047 - 1654 1654 1184 - 1654 1655 1325 - 1655 1655 1481 - 1656 1656 1656 - 1657 1657 1851 - 1658 1659 2071 - 1660 1660 2320 - 1662 1662 2598 - 1664 1664 2901 - 1667 1667 3223 - 1669 1669 3563 - 1672 1672 3913 - 1675 1675 4077 - 1679 1679 4095 - 1682 1682 4095 - 1683 1683 4095 - 1681 1681 4095 - 1675 1675 4095 - 1666 1666 4095 - 1658 1658 4095 - 1656 1656 4095 - 1656 1656 4095 - 1656 1656 4095 - 1656 1656 4095 - 1662 1858 2 - 1662 1858 112 - 1662 1858 229 - 1662 1858 356 - 1662 1858 490 - 1663 1858 629 - 1663 1858 771 - 1663 1859 912 - 1663 1859 1050 - 1664 1860 1189 - 1664 1860 1331 - 1665 1861 1489 - 1665 1862 1665 - 1666 1862 1862 - 1667 1864 2084 - 1668 1865 2336 - 1669 1867 2616 - 1671 1869 2921 - 1672 1871 3242 - 1674 1874 3579 - 1677 1877 3922 - 1679 1880 4075 - 1682 1884 4095 - 1683 1886 4095 - 1682 1887 4095 - 1679 1885 4095 - 1672 1879 4095 - 1663 1871 4095 - 1657 1866 4095 - 1656 1865 4095 - 1656 1865 4095 - 1656 1865 4095 - 1656 1865 4095 - 1671 2091 3 - 1671 2091 107 - 1671 2091 222 - 1671 2091 348 - 1671 2091 483 - 1671 2091 625 - 1671 2091 769 - 1671 2092 911 - 1672 2092 1052 - 1672 2092 1192 - 1672 2093 1335 - 1672 2093 1495 - 1673 2094 1673 - 1673 2095 1872 - 1674 2096 2096 - 1675 2097 2351 - 1676 2099 2636 - 1677 2101 2943 - 1678 2104 3263 - 1680 2107 3596 - 1681 2110 3929 - 1682 2113 4073 - 1683 2116 4095 - 1682 2118 4095 - 1680 2117 4095 - 1675 2115 4095 - 1668 2110 4095 - 1660 2104 4095 - 1656 2102 4095 - 1656 2102 4095 - 1656 2102 4095 - 1656 2102 4095 - 1656 2102 4095 - 1678 2360 2 - 1678 2360 101 - 1678 2360 212 - 1678 2361 338 - 1678 2361 474 - 1678 2361 617 - 1678 2361 764 - 1679 2361 909 - 1679 2362 1051 - 1679 2362 1193 - 1679 2363 1338 - 1679 2363 1499 - 1679 2364 1679 - 1680 2365 1881 - 1680 2366 2108 - 1681 2367 2367 - 1681 2369 2655 - 1682 2371 2965 - 1682 2373 3283 - 1683 2376 3609 - 1683 2378 3922 - 1682 2381 4070 - 1681 2382 4095 - 1679 2383 4095 - 1675 2383 4095 - 1669 2381 4095 - 1663 2378 4095 - 1658 2376 4095 - 1656 2375 4095 - 1656 2375 4095 - 1656 2375 4095 - 1656 2375 4095 - 1656 2375 4095 - 1683 2665 1 - 1683 2665 93 - 1683 2665 199 - 1683 2665 323 - 1683 2665 460 - 1683 2665 607 - 1683 2665 756 - 1683 2665 904 - 1683 2666 1047 - 1683 2666 1191 - 1683 2666 1338 - 1683 2667 1501 - 1683 2667 1683 - 1683 2668 1886 - 1683 2669 2116 - 1683 2670 2379 - 1683 2671 2671 - 1682 2672 2982 - 1682 2674 3297 - 1681 2675 3614 - 1680 2677 3909 - 1679 2678 4066 - 1676 2679 4095 - 1673 2679 4095 - 1668 2679 4095 - 1663 2678 4095 - 1659 2677 4095 - 1656 2677 4095 - 1656 2677 4095 - 1656 2677 4095 - 1656 2677 4095 - 1656 2677 4095 - 1656 2677 4095 - 1680 2988 1 - 1680 2988 82 - 1680 2988 181 - 1680 2988 303 - 1680 2988 441 - 1680 2988 591 - 1680 2988 743 - 1680 2988 893 - 1680 2988 1038 - 1680 2988 1183 - 1680 2988 1331 - 1679 2988 1495 - 1679 2989 1679 - 1679 2989 1885 - 1679 2989 2117 - 1678 2990 2383 - 1678 2990 2678 - 1677 2990 2990 - 1676 2991 3301 - 1674 2991 3609 - 1673 2991 3889 - 1671 2992 4063 - 1668 2991 4095 - 1665 2991 4095 - 1661 2991 4095 - 1658 2991 4095 - 1656 2991 4095 - 1656 2991 4095 - 1656 2991 4095 - 1656 2991 4095 - 1656 2991 4095 - 1656 2991 4095 - 1656 2991 4095 - 1670 3300 2 - 1670 3300 65 - 1670 3300 156 - 1670 3300 277 - 1670 3300 417 - 1670 3300 570 - 1670 3300 726 - 1670 3300 878 - 1670 3300 1024 - 1670 3300 1169 - 1669 3299 1318 - 1669 3299 1484 - 1669 3299 1669 - 1669 3299 1876 - 1668 3299 2110 - 1668 3299 2380 - 1667 3299 2678 - 1666 3298 2991 - 1665 3298 3298 - 1664 3297 3597 - 1663 3297 3867 - 1661 3296 4059 - 1660 3296 4095 - 1658 3295 4095 - 1657 3295 4095 - 1656 3295 4095 - 1656 3295 4095 - 1656 3295 4095 - 1656 3295 4095 - 1656 3295 4095 - 1656 3295 4095 - 1656 3295 4095 - 1656 3295 4095 - 1659 3591 2 - 1659 3591 46 - 1659 3591 130 - 1659 3591 251 - 1659 3591 394 - 1659 3591 550 - 1659 3591 709 - 1659 3591 863 - 1659 3591 1010 - 1659 3590 1156 - 1659 3590 1306 - 1659 3590 1472 - 1659 3590 1659 - 1658 3590 1867 - 1658 3590 2103 - 1658 3590 2376 - 1658 3589 2677 - 1658 3589 2991 - 1657 3589 3295 - 1657 3588 3588 - 1657 3588 3853 - 1656 3588 4057 - 1656 3588 4095 - 1656 3588 4095 - 1656 3588 4095 - 1656 3588 4095 - 1656 3588 4095 - 1656 3588 4095 - 1656 3588 4095 - 1656 3588 4095 - 1656 3588 4095 - 1656 3588 4095 - 1656 3588 4095 - 1656 3852 0 - 1656 3852 36 - 1656 3852 119 - 1656 3852 242 - 1656 3852 387 - 1656 3852 543 - 1656 3852 704 - 1656 3852 858 - 1656 3852 1006 - 1656 3852 1152 - 1656 3852 1303 - 1656 3852 1469 - 1656 3852 1656 - 1656 3852 1865 - 1656 3852 2102 - 1656 3852 2375 - 1656 3852 2677 - 1656 3852 2991 - 1656 3852 3295 - 1656 3852 3588 - 1656 3852 3852 - 1656 3852 4057 - 1656 3852 4095 - 1656 3852 4095 - 1656 3852 4095 - 1656 3852 4095 - 1656 3852 4095 - 1656 3852 4095 - 1656 3852 4095 - 1656 3852 4095 - 1656 3852 4095 - 1656 3852 4095 - 1656 3852 4095 - 1656 4057 0 - 1656 4057 36 - 1656 4057 119 - 1656 4057 242 - 1656 4057 387 - 1656 4057 543 - 1656 4057 704 - 1656 4057 858 - 1656 4057 1006 - 1656 4057 1152 - 1656 4057 1303 - 1656 4057 1469 - 1656 4057 1656 - 1656 4057 1865 - 1656 4057 2102 - 1656 4057 2375 - 1656 4057 2677 - 1656 4057 2991 - 1656 4057 3295 - 1656 4057 3588 - 1656 4057 3852 - 1656 4057 4057 - 1656 4057 4095 - 1656 4057 4095 - 1656 4057 4095 - 1656 4057 4095 - 1656 4057 4095 - 1656 4057 4095 - 1656 4057 4095 - 1656 4057 4095 - 1656 4057 4095 - 1656 4057 4095 - 1656 4057 4095 - 1656 4095 0 - 1656 4095 36 - 1656 4095 119 - 1656 4095 242 - 1656 4095 387 - 1656 4095 543 - 1656 4095 704 - 1656 4095 858 - 1656 4095 1006 - 1656 4095 1152 - 1656 4095 1303 - 1656 4095 1469 - 1656 4095 1656 - 1656 4095 1865 - 1656 4095 2102 - 1656 4095 2375 - 1656 4095 2677 - 1656 4095 2991 - 1656 4095 3295 - 1656 4095 3588 - 1656 4095 3852 - 1656 4095 4057 - 1656 4095 4095 - 1656 4095 4095 - 1656 4095 4095 - 1656 4095 4095 - 1656 4095 4095 - 1656 4095 4095 - 1656 4095 4095 - 1656 4095 4095 - 1656 4095 4095 - 1656 4095 4095 - 1656 4095 4095 - 1656 4095 0 - 1656 4095 36 - 1656 4095 119 - 1656 4095 242 - 1656 4095 387 - 1656 4095 543 - 1656 4095 704 - 1656 4095 858 - 1656 4095 1006 - 1656 4095 1152 - 1656 4095 1303 - 1656 4095 1469 - 1656 4095 1656 - 1656 4095 1865 - 1656 4095 2102 - 1656 4095 2375 - 1656 4095 2677 - 1656 4095 2991 - 1656 4095 3295 - 1656 4095 3588 - 1656 4095 3852 - 1656 4095 4057 - 1656 4095 4095 - 1656 4095 4095 - 1656 4095 4095 - 1656 4095 4095 - 1656 4095 4095 - 1656 4095 4095 - 1656 4095 4095 - 1656 4095 4095 - 1656 4095 4095 - 1656 4095 4095 - 1656 4095 4095 - 1656 4095 0 - 1656 4095 36 - 1656 4095 119 - 1656 4095 242 - 1656 4095 387 - 1656 4095 543 - 1656 4095 704 - 1656 4095 858 - 1656 4095 1006 - 1656 4095 1152 - 1656 4095 1303 - 1656 4095 1469 - 1656 4095 1656 - 1656 4095 1865 - 1656 4095 2102 - 1656 4095 2375 - 1656 4095 2677 - 1656 4095 2991 - 1656 4095 3295 - 1656 4095 3588 - 1656 4095 3852 - 1656 4095 4057 - 1656 4095 4095 - 1656 4095 4095 - 1656 4095 4095 - 1656 4095 4095 - 1656 4095 4095 - 1656 4095 4095 - 1656 4095 4095 - 1656 4095 4095 - 1656 4095 4095 - 1656 4095 4095 - 1656 4095 4095 - 1656 4095 0 - 1656 4095 36 - 1656 4095 119 - 1656 4095 242 - 1656 4095 387 - 1656 4095 543 - 1656 4095 704 - 1656 4095 858 - 1656 4095 1006 - 1656 4095 1152 - 1656 4095 1303 - 1656 4095 1469 - 1656 4095 1656 - 1656 4095 1865 - 1656 4095 2102 - 1656 4095 2375 - 1656 4095 2677 - 1656 4095 2991 - 1656 4095 3295 - 1656 4095 3588 - 1656 4095 3852 - 1656 4095 4057 - 1656 4095 4095 - 1656 4095 4095 - 1656 4095 4095 - 1656 4095 4095 - 1656 4095 4095 - 1656 4095 4095 - 1656 4095 4095 - 1656 4095 4095 - 1656 4095 4095 - 1656 4095 4095 - 1656 4095 4095 - 1656 4095 0 - 1656 4095 36 - 1656 4095 119 - 1656 4095 242 - 1656 4095 387 - 1656 4095 543 - 1656 4095 704 - 1656 4095 858 - 1656 4095 1006 - 1656 4095 1152 - 1656 4095 1303 - 1656 4095 1469 - 1656 4095 1656 - 1656 4095 1865 - 1656 4095 2102 - 1656 4095 2375 - 1656 4095 2677 - 1656 4095 2991 - 1656 4095 3295 - 1656 4095 3588 - 1656 4095 3852 - 1656 4095 4057 - 1656 4095 4095 - 1656 4095 4095 - 1656 4095 4095 - 1656 4095 4095 - 1656 4095 4095 - 1656 4095 4095 - 1656 4095 4095 - 1656 4095 4095 - 1656 4095 4095 - 1656 4095 4095 - 1656 4095 4095 - 1656 4095 0 - 1656 4095 36 - 1656 4095 119 - 1656 4095 242 - 1656 4095 387 - 1656 4095 543 - 1656 4095 704 - 1656 4095 858 - 1656 4095 1006 - 1656 4095 1152 - 1656 4095 1303 - 1656 4095 1469 - 1656 4095 1656 - 1656 4095 1865 - 1656 4095 2102 - 1656 4095 2375 - 1656 4095 2677 - 1656 4095 2991 - 1656 4095 3295 - 1656 4095 3588 - 1656 4095 3852 - 1656 4095 4057 - 1656 4095 4095 - 1656 4095 4095 - 1656 4095 4095 - 1656 4095 4095 - 1656 4095 4095 - 1656 4095 4095 - 1656 4095 4095 - 1656 4095 4095 - 1656 4095 4095 - 1656 4095 4095 - 1656 4095 4095 - 1656 4095 0 - 1656 4095 36 - 1656 4095 119 - 1656 4095 242 - 1656 4095 387 - 1656 4095 543 - 1656 4095 704 - 1656 4095 858 - 1656 4095 1006 - 1656 4095 1152 - 1656 4095 1303 - 1656 4095 1469 - 1656 4095 1656 - 1656 4095 1865 - 1656 4095 2102 - 1656 4095 2375 - 1656 4095 2677 - 1656 4095 2991 - 1656 4095 3295 - 1656 4095 3588 - 1656 4095 3852 - 1656 4095 4057 - 1656 4095 4095 - 1656 4095 4095 - 1656 4095 4095 - 1656 4095 4095 - 1656 4095 4095 - 1656 4095 4095 - 1656 4095 4095 - 1656 4095 4095 - 1656 4095 4095 - 1656 4095 4095 - 1656 4095 4095 - 1656 4095 0 - 1656 4095 36 - 1656 4095 119 - 1656 4095 242 - 1656 4095 387 - 1656 4095 543 - 1656 4095 704 - 1656 4095 858 - 1656 4095 1006 - 1656 4095 1152 - 1656 4095 1303 - 1656 4095 1469 - 1656 4095 1656 - 1656 4095 1865 - 1656 4095 2102 - 1656 4095 2375 - 1656 4095 2677 - 1656 4095 2991 - 1656 4095 3295 - 1656 4095 3588 - 1656 4095 3852 - 1656 4095 4057 - 1656 4095 4095 - 1656 4095 4095 - 1656 4095 4095 - 1656 4095 4095 - 1656 4095 4095 - 1656 4095 4095 - 1656 4095 4095 - 1656 4095 4095 - 1656 4095 4095 - 1656 4095 4095 - 1656 4095 4095 - 1656 4095 0 - 1656 4095 36 - 1656 4095 119 - 1656 4095 242 - 1656 4095 387 - 1656 4095 543 - 1656 4095 704 - 1656 4095 858 - 1656 4095 1006 - 1656 4095 1152 - 1656 4095 1303 - 1656 4095 1469 - 1656 4095 1656 - 1656 4095 1865 - 1656 4095 2102 - 1656 4095 2375 - 1656 4095 2677 - 1656 4095 2991 - 1656 4095 3295 - 1656 4095 3588 - 1656 4095 3852 - 1656 4095 4057 - 1656 4095 4095 - 1656 4095 4095 - 1656 4095 4095 - 1656 4095 4095 - 1656 4095 4095 - 1656 4095 4095 - 1656 4095 4095 - 1656 4095 4095 - 1656 4095 4095 - 1656 4095 4095 - 1656 4095 4095 - 1656 4095 0 - 1656 4095 36 - 1656 4095 119 - 1656 4095 242 - 1656 4095 387 - 1656 4095 543 - 1656 4095 704 - 1656 4095 858 - 1656 4095 1006 - 1656 4095 1152 - 1656 4095 1303 - 1656 4095 1469 - 1656 4095 1656 - 1656 4095 1865 - 1656 4095 2102 - 1656 4095 2375 - 1656 4095 2677 - 1656 4095 2991 - 1656 4095 3295 - 1656 4095 3588 - 1656 4095 3852 - 1656 4095 4057 - 1656 4095 4095 - 1656 4095 4095 - 1656 4095 4095 - 1656 4095 4095 - 1656 4095 4095 - 1656 4095 4095 - 1656 4095 4095 - 1656 4095 4095 - 1656 4095 4095 - 1656 4095 4095 - 1656 4095 4095 - 1656 4095 0 - 1656 4095 36 - 1656 4095 119 - 1656 4095 242 - 1656 4095 387 - 1656 4095 543 - 1656 4095 704 - 1656 4095 858 - 1656 4095 1006 - 1656 4095 1152 - 1656 4095 1303 - 1656 4095 1469 - 1656 4095 1656 - 1656 4095 1865 - 1656 4095 2102 - 1656 4095 2375 - 1656 4095 2677 - 1656 4095 2991 - 1656 4095 3295 - 1656 4095 3588 - 1656 4095 3852 - 1656 4095 4057 - 1656 4095 4095 - 1656 4095 4095 - 1656 4095 4095 - 1656 4095 4095 - 1656 4095 4095 - 1656 4095 4095 - 1656 4095 4095 - 1656 4095 4095 - 1656 4095 4095 - 1656 4095 4095 - 1656 4095 4095 - 1703 0 2 - 1703 2 118 - 1703 2 236 - 1705 1 358 - 1706 2 481 - 1709 2 607 - 1712 1 733 - 1715 2 860 - 1719 1 988 - 1723 1 1116 - 1727 3 1248 - 1732 2 1395 - 1739 2 1560 - 1746 1 1746 - 1754 1 1955 - 1764 3 2194 - 1775 2 2462 - 1786 2 2762 - 1799 3 3091 - 1812 2 3451 - 1826 3 3836 - 1839 3 4085 - 1852 3 4095 - 1863 1 4095 - 1873 3 4095 - 1882 0 4095 - 1887 3 4095 - 1884 3 4095 - 1874 3 4095 - 1866 2 4095 - 1865 0 4095 - 1865 0 4095 - 1865 0 4095 - 1705 118 2 - 1705 118 118 - 1705 118 237 - 1707 118 358 - 1708 118 482 - 1711 118 607 - 1713 118 734 - 1717 118 861 - 1720 118 989 - 1724 118 1117 - 1729 118 1249 - 1734 119 1396 - 1740 119 1561 - 1747 119 1747 - 1755 119 1957 - 1765 119 2195 - 1775 119 2463 - 1787 119 2763 - 1800 119 3092 - 1813 118 3452 - 1826 117 3837 - 1839 115 4085 - 1852 113 4095 - 1863 110 4095 - 1873 105 4095 - 1882 98 4095 - 1887 89 4095 - 1884 77 4095 - 1874 59 4095 - 1866 41 4095 - 1865 36 4095 - 1865 36 4095 - 1865 36 4095 - 1711 237 2 - 1711 237 118 - 1712 237 237 - 1713 237 359 - 1714 237 483 - 1717 238 609 - 1719 238 736 - 1722 238 864 - 1725 238 991 - 1729 239 1120 - 1733 239 1252 - 1738 239 1399 - 1744 239 1564 - 1751 240 1751 - 1759 240 1960 - 1768 240 2199 - 1778 241 2467 - 1789 240 2767 - 1802 240 3096 - 1814 239 3455 - 1827 238 3839 - 1840 235 4085 - 1853 231 4095 - 1864 226 4095 - 1874 218 4095 - 1883 207 4095 - 1887 193 4095 - 1883 172 4095 - 1874 147 4095 - 1866 124 4095 - 1865 119 4095 - 1865 119 4095 - 1865 119 4095 - 1721 360 2 - 1721 360 118 - 1722 360 238 - 1723 361 360 - 1724 361 485 - 1726 361 612 - 1728 361 740 - 1731 362 868 - 1734 362 996 - 1737 362 1124 - 1741 363 1257 - 1745 363 1405 - 1751 364 1570 - 1757 364 1757 - 1764 365 1967 - 1773 366 2206 - 1783 366 2474 - 1793 366 2774 - 1805 366 3102 - 1817 366 3460 - 1830 364 3843 - 1842 362 4084 - 1854 358 4095 - 1865 352 4095 - 1874 343 4095 - 1883 331 4095 - 1887 315 4095 - 1883 293 4095 - 1873 267 4095 - 1866 245 4095 - 1865 242 4095 - 1865 242 4095 - 1865 242 4095 - 1734 487 2 - 1734 487 119 - 1734 487 239 - 1735 488 362 - 1736 488 487 - 1738 488 615 - 1740 488 744 - 1742 489 873 - 1745 489 1001 - 1748 490 1131 - 1751 490 1264 - 1755 491 1412 - 1760 492 1578 - 1766 493 1765 - 1772 494 1976 - 1780 495 2215 - 1789 495 2484 - 1799 496 2783 - 1809 497 3111 - 1821 497 3468 - 1833 496 3849 - 1844 494 4084 - 1856 491 4095 - 1866 486 4095 - 1875 478 4095 - 1884 467 4095 - 1887 452 4095 - 1883 432 4095 - 1873 408 4095 - 1866 389 4095 - 1865 387 4095 - 1865 387 4095 - 1865 387 4095 - 1748 618 2 - 1748 618 119 - 1749 618 240 - 1749 618 363 - 1750 619 490 - 1752 619 619 - 1753 619 748 - 1755 620 878 - 1757 620 1008 - 1760 621 1138 - 1763 622 1272 - 1766 623 1421 - 1771 623 1588 - 1776 625 1775 - 1782 626 1987 - 1789 627 2226 - 1796 629 2496 - 1805 630 2795 - 1815 631 3122 - 1826 632 3478 - 1837 632 3856 - 1847 632 4084 - 1858 630 4095 - 1867 626 4095 - 1876 620 4095 - 1884 611 4095 - 1887 599 4095 - 1882 581 4095 - 1873 560 4095 - 1866 545 4095 - 1865 543 4095 - 1865 543 4095 - 1865 543 4095 - 1763 752 2 - 1764 752 119 - 1764 752 240 - 1764 753 365 - 1765 753 492 - 1766 753 622 - 1768 754 753 - 1769 754 884 - 1771 755 1015 - 1773 755 1146 - 1776 756 1281 - 1779 757 1431 - 1783 758 1598 - 1787 760 1787 - 1792 761 1999 - 1798 763 2239 - 1805 764 2509 - 1813 766 2809 - 1822 768 3135 - 1831 770 3489 - 1841 771 3864 - 1851 772 4083 - 1861 771 4095 - 1869 769 4095 - 1878 765 4095 - 1885 759 4095 - 1887 749 4095 - 1882 734 4095 - 1872 717 4095 - 1865 705 4095 - 1865 704 4095 - 1865 704 4095 - 1865 704 4095 - 1779 889 2 - 1779 889 119 - 1779 889 240 - 1780 889 366 - 1781 889 494 - 1782 890 625 - 1783 890 758 - 1784 891 890 - 1786 891 1022 - 1787 892 1154 - 1789 893 1290 - 1792 894 1440 - 1795 895 1609 - 1799 896 1799 - 1803 898 2011 - 1808 900 2253 - 1814 902 2524 - 1821 904 2824 - 1829 906 3149 - 1837 908 3501 - 1846 910 3873 - 1855 912 4082 - 1863 912 4095 - 1871 911 4095 - 1879 909 4095 - 1886 905 4095 - 1887 897 4095 - 1881 884 4095 - 1871 869 4095 - 1865 859 4095 - 1865 858 4095 - 1865 858 4095 - 1865 858 4095 - 1794 1026 2 - 1794 1026 119 - 1795 1027 240 - 1795 1027 366 - 1796 1027 496 - 1796 1027 628 - 1797 1028 762 - 1798 1028 896 - 1800 1029 1029 - 1801 1030 1162 - 1803 1030 1298 - 1805 1031 1450 - 1807 1032 1620 - 1811 1034 1810 - 1814 1035 2024 - 1819 1037 2267 - 1824 1039 2539 - 1830 1042 2839 - 1836 1044 3164 - 1843 1047 3514 - 1851 1049 3882 - 1859 1051 4082 - 1866 1052 4095 - 1874 1052 4095 - 1881 1051 4095 - 1886 1048 4095 - 1886 1040 4095 - 1880 1028 4095 - 1870 1014 4095 - 1865 1006 4095 - 1865 1006 4095 - 1865 1006 4095 - 1865 1006 4095 - 1809 1166 3 - 1809 1166 118 - 1809 1166 240 - 1809 1166 366 - 1810 1167 497 - 1810 1167 630 - 1811 1167 766 - 1812 1168 901 - 1813 1168 1035 - 1814 1169 1169 - 1816 1170 1306 - 1817 1171 1459 - 1819 1172 1630 - 1822 1173 1822 - 1825 1175 2037 - 1829 1176 2281 - 1833 1178 2554 - 1838 1181 2856 - 1844 1183 3180 - 1850 1186 3527 - 1856 1188 3891 - 1863 1190 4081 - 1870 1192 4095 - 1876 1193 4095 - 1883 1193 4095 - 1887 1190 4095 - 1885 1183 4095 - 1878 1171 4095 - 1869 1159 4095 - 1865 1153 4095 - 1865 1152 4095 - 1865 1152 4095 - 1865 1152 4095 - 1822 1311 1 - 1822 1311 117 - 1823 1311 238 - 1823 1311 365 - 1823 1311 497 - 1824 1312 632 - 1824 1312 768 - 1825 1312 905 - 1826 1313 1040 - 1827 1313 1175 - 1828 1314 1314 - 1829 1315 1468 - 1831 1316 1640 - 1833 1317 1833 - 1836 1319 2050 - 1839 1320 2295 - 1842 1322 2570 - 1846 1324 2872 - 1851 1327 3195 - 1856 1329 3540 - 1861 1332 3900 - 1867 1334 4080 - 1873 1336 4095 - 1879 1338 4095 - 1885 1339 4095 - 1887 1336 4095 - 1884 1329 4095 - 1877 1319 4095 - 1869 1308 4095 - 1865 1303 4095 - 1865 1303 4095 - 1865 1303 4095 - 1865 1303 4095 - 1836 1473 2 - 1836 1473 116 - 1836 1473 236 - 1836 1473 363 - 1836 1473 496 - 1837 1473 632 - 1837 1474 771 - 1838 1474 908 - 1839 1475 1045 - 1839 1475 1181 - 1840 1476 1321 - 1841 1476 1476 - 1843 1477 1650 - 1844 1479 1844 - 1846 1480 2062 - 1849 1481 2310 - 1851 1483 2587 - 1855 1485 2889 - 1858 1488 3212 - 1862 1490 3554 - 1867 1493 3908 - 1871 1495 4078 - 1877 1498 4095 - 1882 1500 4095 - 1886 1501 4095 - 1887 1499 4095 - 1883 1492 4095 - 1875 1482 4095 - 1867 1473 4095 - 1865 1469 4095 - 1865 1469 4095 - 1865 1469 4095 - 1865 1469 4095 - 1849 1655 2 - 1849 1655 114 - 1849 1655 233 - 1849 1655 360 - 1849 1656 493 - 1849 1656 631 - 1850 1656 771 - 1850 1656 911 - 1851 1657 1048 - 1851 1657 1186 - 1852 1658 1327 - 1853 1659 1484 - 1854 1659 1659 - 1855 1660 1855 - 1856 1662 2075 - 1858 1663 2325 - 1860 1665 2604 - 1863 1667 2908 - 1866 1669 3229 - 1869 1671 3568 - 1872 1674 3916 - 1876 1677 4077 - 1881 1680 4095 - 1885 1682 4095 - 1887 1683 4095 - 1886 1680 4095 - 1881 1674 4095 - 1873 1665 4095 - 1866 1658 4095 - 1865 1656 4095 - 1865 1656 4095 - 1865 1656 4095 - 1865 1656 4095 - 1860 1861 2 - 1860 1861 111 - 1861 1861 228 - 1861 1861 354 - 1861 1861 489 - 1861 1861 628 - 1861 1861 771 - 1862 1862 912 - 1862 1862 1051 - 1862 1863 1190 - 1863 1863 1332 - 1863 1864 1491 - 1864 1864 1667 - 1865 1865 1865 - 1866 1866 2087 - 1867 1867 2340 - 1869 1869 2621 - 1870 1871 2927 - 1873 1873 3247 - 1875 1875 3583 - 1878 1879 3924 - 1882 1882 4075 - 1885 1885 4095 - 1887 1887 4095 - 1887 1887 4095 - 1884 1884 4095 - 1878 1878 4095 - 1871 1871 4095 - 1866 1866 4095 - 1865 1865 4095 - 1865 1865 4095 - 1865 1865 4095 - 1865 1865 4095 - 1871 2093 0 - 1871 2093 106 - 1871 2093 220 - 1871 2093 346 - 1871 2094 482 - 1871 2094 623 - 1871 2094 768 - 1871 2094 911 - 1872 2095 1052 - 1872 2095 1192 - 1872 2095 1336 - 1873 2096 1496 - 1873 2097 1674 - 1874 2097 1874 - 1875 2099 2099 - 1876 2100 2355 - 1877 2102 2640 - 1878 2104 2948 - 1880 2106 3267 - 1882 2109 3599 - 1884 2111 3928 - 1886 2114 4072 - 1887 2117 4095 - 1887 2118 4095 - 1885 2117 4095 - 1880 2114 4095 - 1874 2109 4095 - 1868 2104 4095 - 1865 2102 4095 - 1865 2102 4095 - 1865 2102 4095 - 1865 2102 4095 - 1865 2102 4095 - 1880 2363 2 - 1880 2363 100 - 1880 2363 210 - 1880 2363 335 - 1880 2364 472 - 1880 2364 616 - 1880 2364 763 - 1881 2364 908 - 1881 2365 1051 - 1881 2365 1193 - 1881 2365 1338 - 1881 2366 1500 - 1882 2367 1680 - 1882 2367 1882 - 1883 2369 2110 - 1883 2370 2369 - 1884 2371 2658 - 1885 2373 2968 - 1886 2375 3286 - 1886 2377 3610 - 1887 2379 3920 - 1887 2381 4069 - 1886 2383 4095 - 1884 2383 4095 - 1881 2383 4095 - 1876 2380 4095 - 1870 2377 4095 - 1866 2376 4095 - 1865 2375 4095 - 1865 2375 4095 - 1865 2375 4095 - 1865 2375 4095 - 1865 2375 4095 - 1886 2667 1 - 1886 2667 92 - 1886 2667 197 - 1886 2667 321 - 1886 2667 458 - 1886 2667 605 - 1886 2667 755 - 1886 2668 903 - 1886 2668 1047 - 1886 2668 1190 - 1887 2668 1337 - 1887 2669 1500 - 1887 2669 1683 - 1887 2670 1887 - 1887 2671 2117 - 1887 2671 2380 - 1887 2672 2672 - 1887 2674 2983 - 1887 2675 3298 - 1886 2676 3614 - 1885 2677 3906 - 1884 2678 4066 - 1882 2679 4095 - 1879 2679 4095 - 1875 2678 4095 - 1871 2677 4095 - 1867 2677 4095 - 1865 2677 4095 - 1865 2677 4095 - 1865 2677 4095 - 1865 2677 4095 - 1865 2677 4095 - 1865 2677 4095 - 1885 2988 3 - 1885 2988 80 - 1885 2988 178 - 1885 2989 300 - 1885 2989 439 - 1885 2989 589 - 1885 2989 742 - 1885 2989 892 - 1885 2989 1037 - 1885 2989 1182 - 1885 2989 1330 - 1884 2989 1494 - 1884 2989 1678 - 1884 2990 1884 - 1884 2990 2116 - 1883 2990 2383 - 1883 2990 2679 - 1882 2991 2991 - 1881 2991 3301 - 1880 2991 3608 - 1879 2991 3887 - 1877 2991 4062 - 1874 2991 4095 - 1872 2991 4095 - 1869 2991 4095 - 1866 2991 4095 - 1865 2991 4095 - 1865 2991 4095 - 1865 2991 4095 - 1865 2991 4095 - 1865 2991 4095 - 1865 2991 4095 - 1865 2991 4095 - 1877 3299 2 - 1877 3299 64 - 1877 3299 154 - 1877 3299 275 - 1876 3299 415 - 1876 3299 568 - 1876 3299 724 - 1876 3299 876 - 1876 3299 1023 - 1876 3299 1168 - 1876 3299 1317 - 1876 3299 1483 - 1875 3299 1668 - 1875 3299 1875 - 1875 3299 2110 - 1874 3298 2380 - 1874 3298 2678 - 1873 3298 2991 - 1872 3297 3298 - 1871 3297 3596 - 1870 3296 3866 - 1869 3296 4059 - 1867 3295 4095 - 1866 3295 4095 - 1865 3295 4095 - 1865 3295 4095 - 1865 3295 4095 - 1865 3295 4095 - 1865 3295 4095 - 1865 3295 4095 - 1865 3295 4095 - 1865 3295 4095 - 1865 3295 4095 - 1867 3590 1 - 1867 3590 44 - 1867 3590 128 - 1867 3590 250 - 1867 3590 393 - 1867 3590 549 - 1867 3590 708 - 1867 3590 862 - 1867 3590 1009 - 1867 3590 1156 - 1867 3590 1305 - 1867 3590 1472 - 1867 3590 1658 - 1867 3590 1867 - 1866 3589 2103 - 1866 3589 2376 - 1866 3589 2677 - 1866 3589 2991 - 1866 3588 3295 - 1865 3588 3588 - 1865 3588 3853 - 1865 3588 4057 - 1865 3588 4095 - 1865 3588 4095 - 1865 3588 4095 - 1865 3588 4095 - 1865 3588 4095 - 1865 3588 4095 - 1865 3588 4095 - 1865 3588 4095 - 1865 3588 4095 - 1865 3588 4095 - 1865 3588 4095 - 1865 3852 0 - 1865 3852 36 - 1865 3852 119 - 1865 3852 242 - 1865 3852 387 - 1865 3852 543 - 1865 3852 704 - 1865 3852 858 - 1865 3852 1006 - 1865 3852 1152 - 1865 3852 1303 - 1865 3852 1469 - 1865 3852 1656 - 1865 3852 1865 - 1865 3852 2102 - 1865 3852 2375 - 1865 3852 2677 - 1865 3852 2991 - 1865 3852 3295 - 1865 3852 3588 - 1865 3852 3852 - 1865 3852 4057 - 1865 3852 4095 - 1865 3852 4095 - 1865 3852 4095 - 1865 3852 4095 - 1865 3852 4095 - 1865 3852 4095 - 1865 3852 4095 - 1865 3852 4095 - 1865 3852 4095 - 1865 3852 4095 - 1865 3852 4095 - 1865 4057 0 - 1865 4057 36 - 1865 4057 119 - 1865 4057 242 - 1865 4057 387 - 1865 4057 543 - 1865 4057 704 - 1865 4057 858 - 1865 4057 1006 - 1865 4057 1152 - 1865 4057 1303 - 1865 4057 1469 - 1865 4057 1656 - 1865 4057 1865 - 1865 4057 2102 - 1865 4057 2375 - 1865 4057 2677 - 1865 4057 2991 - 1865 4057 3295 - 1865 4057 3588 - 1865 4057 3852 - 1865 4057 4057 - 1865 4057 4095 - 1865 4057 4095 - 1865 4057 4095 - 1865 4057 4095 - 1865 4057 4095 - 1865 4057 4095 - 1865 4057 4095 - 1865 4057 4095 - 1865 4057 4095 - 1865 4057 4095 - 1865 4057 4095 - 1865 4095 0 - 1865 4095 36 - 1865 4095 119 - 1865 4095 242 - 1865 4095 387 - 1865 4095 543 - 1865 4095 704 - 1865 4095 858 - 1865 4095 1006 - 1865 4095 1152 - 1865 4095 1303 - 1865 4095 1469 - 1865 4095 1656 - 1865 4095 1865 - 1865 4095 2102 - 1865 4095 2375 - 1865 4095 2677 - 1865 4095 2991 - 1865 4095 3295 - 1865 4095 3588 - 1865 4095 3852 - 1865 4095 4057 - 1865 4095 4095 - 1865 4095 4095 - 1865 4095 4095 - 1865 4095 4095 - 1865 4095 4095 - 1865 4095 4095 - 1865 4095 4095 - 1865 4095 4095 - 1865 4095 4095 - 1865 4095 4095 - 1865 4095 4095 - 1865 4095 0 - 1865 4095 36 - 1865 4095 119 - 1865 4095 242 - 1865 4095 387 - 1865 4095 543 - 1865 4095 704 - 1865 4095 858 - 1865 4095 1006 - 1865 4095 1152 - 1865 4095 1303 - 1865 4095 1469 - 1865 4095 1656 - 1865 4095 1865 - 1865 4095 2102 - 1865 4095 2375 - 1865 4095 2677 - 1865 4095 2991 - 1865 4095 3295 - 1865 4095 3588 - 1865 4095 3852 - 1865 4095 4057 - 1865 4095 4095 - 1865 4095 4095 - 1865 4095 4095 - 1865 4095 4095 - 1865 4095 4095 - 1865 4095 4095 - 1865 4095 4095 - 1865 4095 4095 - 1865 4095 4095 - 1865 4095 4095 - 1865 4095 4095 - 1865 4095 0 - 1865 4095 36 - 1865 4095 119 - 1865 4095 242 - 1865 4095 387 - 1865 4095 543 - 1865 4095 704 - 1865 4095 858 - 1865 4095 1006 - 1865 4095 1152 - 1865 4095 1303 - 1865 4095 1469 - 1865 4095 1656 - 1865 4095 1865 - 1865 4095 2102 - 1865 4095 2375 - 1865 4095 2677 - 1865 4095 2991 - 1865 4095 3295 - 1865 4095 3588 - 1865 4095 3852 - 1865 4095 4057 - 1865 4095 4095 - 1865 4095 4095 - 1865 4095 4095 - 1865 4095 4095 - 1865 4095 4095 - 1865 4095 4095 - 1865 4095 4095 - 1865 4095 4095 - 1865 4095 4095 - 1865 4095 4095 - 1865 4095 4095 - 1865 4095 0 - 1865 4095 36 - 1865 4095 119 - 1865 4095 242 - 1865 4095 387 - 1865 4095 543 - 1865 4095 704 - 1865 4095 858 - 1865 4095 1006 - 1865 4095 1152 - 1865 4095 1303 - 1865 4095 1469 - 1865 4095 1656 - 1865 4095 1865 - 1865 4095 2102 - 1865 4095 2375 - 1865 4095 2677 - 1865 4095 2991 - 1865 4095 3295 - 1865 4095 3588 - 1865 4095 3852 - 1865 4095 4057 - 1865 4095 4095 - 1865 4095 4095 - 1865 4095 4095 - 1865 4095 4095 - 1865 4095 4095 - 1865 4095 4095 - 1865 4095 4095 - 1865 4095 4095 - 1865 4095 4095 - 1865 4095 4095 - 1865 4095 4095 - 1865 4095 0 - 1865 4095 36 - 1865 4095 119 - 1865 4095 242 - 1865 4095 387 - 1865 4095 543 - 1865 4095 704 - 1865 4095 858 - 1865 4095 1006 - 1865 4095 1152 - 1865 4095 1303 - 1865 4095 1469 - 1865 4095 1656 - 1865 4095 1865 - 1865 4095 2102 - 1865 4095 2375 - 1865 4095 2677 - 1865 4095 2991 - 1865 4095 3295 - 1865 4095 3588 - 1865 4095 3852 - 1865 4095 4057 - 1865 4095 4095 - 1865 4095 4095 - 1865 4095 4095 - 1865 4095 4095 - 1865 4095 4095 - 1865 4095 4095 - 1865 4095 4095 - 1865 4095 4095 - 1865 4095 4095 - 1865 4095 4095 - 1865 4095 4095 - 1865 4095 0 - 1865 4095 36 - 1865 4095 119 - 1865 4095 242 - 1865 4095 387 - 1865 4095 543 - 1865 4095 704 - 1865 4095 858 - 1865 4095 1006 - 1865 4095 1152 - 1865 4095 1303 - 1865 4095 1469 - 1865 4095 1656 - 1865 4095 1865 - 1865 4095 2102 - 1865 4095 2375 - 1865 4095 2677 - 1865 4095 2991 - 1865 4095 3295 - 1865 4095 3588 - 1865 4095 3852 - 1865 4095 4057 - 1865 4095 4095 - 1865 4095 4095 - 1865 4095 4095 - 1865 4095 4095 - 1865 4095 4095 - 1865 4095 4095 - 1865 4095 4095 - 1865 4095 4095 - 1865 4095 4095 - 1865 4095 4095 - 1865 4095 4095 - 1865 4095 0 - 1865 4095 36 - 1865 4095 119 - 1865 4095 242 - 1865 4095 387 - 1865 4095 543 - 1865 4095 704 - 1865 4095 858 - 1865 4095 1006 - 1865 4095 1152 - 1865 4095 1303 - 1865 4095 1469 - 1865 4095 1656 - 1865 4095 1865 - 1865 4095 2102 - 1865 4095 2375 - 1865 4095 2677 - 1865 4095 2991 - 1865 4095 3295 - 1865 4095 3588 - 1865 4095 3852 - 1865 4095 4057 - 1865 4095 4095 - 1865 4095 4095 - 1865 4095 4095 - 1865 4095 4095 - 1865 4095 4095 - 1865 4095 4095 - 1865 4095 4095 - 1865 4095 4095 - 1865 4095 4095 - 1865 4095 4095 - 1865 4095 4095 - 1865 4095 0 - 1865 4095 36 - 1865 4095 119 - 1865 4095 242 - 1865 4095 387 - 1865 4095 543 - 1865 4095 704 - 1865 4095 858 - 1865 4095 1006 - 1865 4095 1152 - 1865 4095 1303 - 1865 4095 1469 - 1865 4095 1656 - 1865 4095 1865 - 1865 4095 2102 - 1865 4095 2375 - 1865 4095 2677 - 1865 4095 2991 - 1865 4095 3295 - 1865 4095 3588 - 1865 4095 3852 - 1865 4095 4057 - 1865 4095 4095 - 1865 4095 4095 - 1865 4095 4095 - 1865 4095 4095 - 1865 4095 4095 - 1865 4095 4095 - 1865 4095 4095 - 1865 4095 4095 - 1865 4095 4095 - 1865 4095 4095 - 1865 4095 4095 - 1865 4095 0 - 1865 4095 36 - 1865 4095 119 - 1865 4095 242 - 1865 4095 387 - 1865 4095 543 - 1865 4095 704 - 1865 4095 858 - 1865 4095 1006 - 1865 4095 1152 - 1865 4095 1303 - 1865 4095 1469 - 1865 4095 1656 - 1865 4095 1865 - 1865 4095 2102 - 1865 4095 2375 - 1865 4095 2677 - 1865 4095 2991 - 1865 4095 3295 - 1865 4095 3588 - 1865 4095 3852 - 1865 4095 4057 - 1865 4095 4095 - 1865 4095 4095 - 1865 4095 4095 - 1865 4095 4095 - 1865 4095 4095 - 1865 4095 4095 - 1865 4095 4095 - 1865 4095 4095 - 1865 4095 4095 - 1865 4095 4095 - 1865 4095 4095 - 1865 4095 0 - 1865 4095 36 - 1865 4095 119 - 1865 4095 242 - 1865 4095 387 - 1865 4095 543 - 1865 4095 704 - 1865 4095 858 - 1865 4095 1006 - 1865 4095 1152 - 1865 4095 1303 - 1865 4095 1469 - 1865 4095 1656 - 1865 4095 1865 - 1865 4095 2102 - 1865 4095 2375 - 1865 4095 2677 - 1865 4095 2991 - 1865 4095 3295 - 1865 4095 3588 - 1865 4095 3852 - 1865 4095 4057 - 1865 4095 4095 - 1865 4095 4095 - 1865 4095 4095 - 1865 4095 4095 - 1865 4095 4095 - 1865 4095 4095 - 1865 4095 4095 - 1865 4095 4095 - 1865 4095 4095 - 1865 4095 4095 - 1865 4095 4095 - 1865 4095 0 - 1865 4095 36 - 1865 4095 119 - 1865 4095 242 - 1865 4095 387 - 1865 4095 543 - 1865 4095 704 - 1865 4095 858 - 1865 4095 1006 - 1865 4095 1152 - 1865 4095 1303 - 1865 4095 1469 - 1865 4095 1656 - 1865 4095 1865 - 1865 4095 2102 - 1865 4095 2375 - 1865 4095 2677 - 1865 4095 2991 - 1865 4095 3295 - 1865 4095 3588 - 1865 4095 3852 - 1865 4095 4057 - 1865 4095 4095 - 1865 4095 4095 - 1865 4095 4095 - 1865 4095 4095 - 1865 4095 4095 - 1865 4095 4095 - 1865 4095 4095 - 1865 4095 4095 - 1865 4095 4095 - 1865 4095 4095 - 1865 4095 4095 - 1937 2 0 - 1937 1 119 - 1938 2 239 - 1939 1 363 - 1940 2 488 - 1942 3 616 - 1944 3 745 - 1946 2 875 - 1949 0 1004 - 1952 0 1133 - 1956 0 1267 - 1960 1 1415 - 1966 3 1582 - 1972 0 1769 - 1979 0 1979 - 1988 3 2218 - 1998 2 2487 - 2009 0 2787 - 2021 3 3115 - 2034 3 3471 - 2048 3 3851 - 2061 4 4084 - 2075 2 4095 - 2088 0 4095 - 2100 4 4095 - 2111 3 4095 - 2117 1 4095 - 2116 1 4095 - 2108 1 4095 - 2102 2 4095 - 2102 0 4095 - 2102 0 4095 - 2102 0 4095 - 1939 119 0 - 1939 119 119 - 1939 119 239 - 1940 119 363 - 1941 119 489 - 1943 119 617 - 1945 119 746 - 1948 119 875 - 1950 119 1004 - 1953 119 1134 - 1957 119 1267 - 1961 119 1416 - 1967 119 1582 - 1973 119 1769 - 1980 119 1980 - 1989 119 2219 - 1998 119 2488 - 2009 119 2788 - 2021 118 3115 - 2034 117 3472 - 2048 116 3852 - 2062 114 4084 - 2075 112 4095 - 2088 108 4095 - 2100 104 4095 - 2111 97 4095 - 2117 88 4095 - 2116 75 4095 - 2108 57 4095 - 2102 40 4095 - 2102 36 4095 - 2102 36 4095 - 2102 36 4095 - 1943 239 2 - 1943 239 119 - 1944 240 239 - 1945 240 363 - 1946 240 489 - 1947 240 618 - 1949 240 747 - 1952 240 877 - 1954 240 1006 - 1957 240 1136 - 1961 240 1270 - 1965 240 1418 - 1970 240 1585 - 1976 241 1772 - 1983 241 1983 - 1991 241 2223 - 2001 240 2492 - 2012 240 2791 - 2023 239 3119 - 2036 238 3474 - 2049 236 3854 - 2063 233 4084 - 2076 229 4095 - 2088 224 4095 - 2100 216 4095 - 2111 205 4095 - 2117 190 4095 - 2116 170 4095 - 2108 144 4095 - 2102 123 4095 - 2102 119 4095 - 2102 119 4095 - 2102 119 4095 - 1951 364 1 - 1951 364 119 - 1952 364 240 - 1952 364 364 - 1953 364 490 - 1955 364 619 - 1957 364 749 - 1959 364 879 - 1961 365 1009 - 1964 365 1139 - 1967 365 1273 - 1971 365 1422 - 1976 366 1590 - 1982 366 1777 - 1988 366 1988 - 1996 366 2228 - 2005 366 2497 - 2015 366 2797 - 2027 366 3124 - 2039 365 3479 - 2051 363 3857 - 2064 360 4084 - 2077 356 4095 - 2089 349 4095 - 2101 340 4095 - 2112 329 4095 - 2118 312 4095 - 2115 290 4095 - 2108 264 4095 - 2102 244 4095 - 2102 242 4095 - 2102 242 4095 - 2102 242 4095 - 1961 492 2 - 1961 492 119 - 1962 492 240 - 1963 492 365 - 1964 492 492 - 1965 492 621 - 1966 492 752 - 1968 493 883 - 1971 493 1013 - 1973 493 1144 - 1976 494 1279 - 1980 494 1428 - 1984 494 1596 - 1989 495 1784 - 1995 496 1995 - 2003 496 2236 - 2011 497 2505 - 2021 497 2805 - 2031 497 3132 - 2043 496 3486 - 2055 495 3862 - 2067 493 4083 - 2079 489 4095 - 2091 483 4095 - 2102 476 4095 - 2113 465 4095 - 2118 449 4095 - 2115 429 4095 - 2107 405 4095 - 2102 388 4095 - 2102 387 4095 - 2102 387 4095 - 2102 387 4095 - 1974 623 3 - 1974 623 119 - 1974 624 240 - 1975 624 365 - 1976 624 493 - 1977 624 624 - 1978 624 755 - 1980 625 887 - 1982 625 1018 - 1984 625 1150 - 1987 626 1285 - 1990 626 1435 - 1994 627 1603 - 1999 628 1792 - 2004 629 2004 - 2011 630 2245 - 2018 630 2515 - 2027 631 2815 - 2037 632 3141 - 2047 632 3494 - 2059 632 3868 - 2070 631 4083 - 2082 628 4095 - 2092 624 4095 - 2104 618 4095 - 2113 609 4095 - 2118 596 4095 - 2115 578 4095 - 2107 558 4095 - 2102 545 4095 - 2102 543 4095 - 2102 543 4095 - 2102 543 4095 - 1988 758 2 - 1988 758 119 - 1988 758 241 - 1988 758 366 - 1989 759 495 - 1990 759 626 - 1991 759 759 - 1993 760 891 - 1995 760 1023 - 1997 761 1156 - 1999 761 1292 - 2002 762 1443 - 2005 763 1612 - 2009 763 1801 - 2014 765 2014 - 2020 766 2256 - 2027 767 2527 - 2035 768 2827 - 2043 770 3152 - 2053 771 3504 - 2063 772 3875 - 2074 771 4082 - 2085 770 4095 - 2095 768 4095 - 2105 764 4095 - 2114 757 4095 - 2118 747 4095 - 2114 732 4095 - 2106 715 4095 - 2102 704 4095 - 2102 704 4095 - 2102 704 4095 - 2102 704 4095 - 2002 895 2 - 2002 895 119 - 2002 895 240 - 2003 895 366 - 2003 895 496 - 2004 895 628 - 2005 896 762 - 2007 896 896 - 2008 897 1029 - 2010 897 1162 - 2012 898 1299 - 2014 899 1451 - 2017 899 1620 - 2021 901 1811 - 2025 902 2025 - 2030 903 2268 - 2036 905 2540 - 2043 906 2840 - 2051 908 3165 - 2059 910 3514 - 2069 911 3883 - 2078 912 4082 - 2088 912 4095 - 2097 911 4095 - 2107 908 4095 - 2115 904 4095 - 2118 895 4095 - 2113 882 4095 - 2106 867 4095 - 2102 859 4095 - 2102 858 4095 - 2102 858 4095 - 2102 858 4095 - 2016 1032 0 - 2016 1032 118 - 2017 1032 240 - 2017 1033 366 - 2018 1033 497 - 2018 1033 630 - 2019 1033 765 - 2020 1034 900 - 2022 1034 1034 - 2023 1035 1168 - 2025 1035 1306 - 2027 1036 1458 - 2029 1037 1629 - 2032 1038 1821 - 2036 1039 2036 - 2040 1041 2280 - 2045 1043 2553 - 2051 1044 2854 - 2058 1046 3178 - 2066 1048 3526 - 2074 1050 3890 - 2083 1051 4081 - 2091 1052 4095 - 2100 1052 4095 - 2110 1050 4095 - 2116 1046 4095 - 2117 1038 4095 - 2113 1026 4095 - 2105 1013 4095 - 2102 1006 4095 - 2102 1006 4095 - 2102 1006 4095 - 2102 1006 4095 - 2030 1172 0 - 2030 1172 118 - 2031 1172 239 - 2031 1172 365 - 2031 1172 497 - 2032 1172 632 - 2033 1173 768 - 2034 1173 904 - 2035 1173 1039 - 2036 1174 1174 - 2037 1175 1312 - 2039 1175 1466 - 2041 1176 1638 - 2044 1177 1831 - 2047 1178 2047 - 2051 1180 2292 - 2055 1182 2566 - 2060 1184 2868 - 2066 1186 3192 - 2073 1188 3537 - 2080 1189 3898 - 2087 1191 4080 - 2095 1192 4095 - 2104 1193 4095 - 2112 1192 4095 - 2117 1189 4095 - 2117 1181 4095 - 2112 1170 4095 - 2104 1158 4095 - 2102 1152 4095 - 2102 1152 4095 - 2102 1152 4095 - 2102 1152 4095 - 2044 1316 0 - 2044 1316 117 - 2044 1316 237 - 2045 1316 364 - 2045 1316 496 - 2045 1316 632 - 2046 1317 770 - 2047 1317 907 - 2048 1318 1043 - 2049 1318 1179 - 2050 1319 1319 - 2051 1319 1473 - 2053 1320 1646 - 2055 1321 1840 - 2058 1322 2058 - 2061 1324 2304 - 2064 1325 2580 - 2069 1327 2883 - 2074 1329 3206 - 2079 1331 3549 - 2086 1333 3905 - 2092 1335 4079 - 2099 1337 4095 - 2107 1338 4095 - 2114 1338 4095 - 2118 1335 4095 - 2116 1328 4095 - 2110 1317 4095 - 2104 1307 4095 - 2102 1303 4095 - 2102 1303 4095 - 2102 1303 4095 - 2102 1303 4095 - 2058 1477 0 - 2058 1477 115 - 2058 1477 235 - 2058 1478 362 - 2059 1478 495 - 2059 1478 632 - 2059 1478 771 - 2060 1479 910 - 2061 1479 1047 - 2062 1479 1184 - 2062 1480 1324 - 2064 1481 1480 - 2065 1481 1655 - 2067 1482 1850 - 2069 1483 2069 - 2071 1485 2318 - 2074 1486 2595 - 2078 1488 2899 - 2082 1490 3221 - 2087 1492 3561 - 2092 1494 3912 - 2097 1496 4078 - 2104 1499 4095 - 2111 1501 4095 - 2116 1501 4095 - 2118 1498 4095 - 2115 1491 4095 - 2109 1481 4095 - 2103 1472 4095 - 2102 1469 4095 - 2102 1469 4095 - 2102 1469 4095 - 2102 1469 4095 - 2072 1659 0 - 2072 1659 113 - 2072 1659 231 - 2072 1659 358 - 2072 1660 492 - 2072 1660 630 - 2073 1660 771 - 2073 1660 911 - 2074 1661 1050 - 2074 1661 1188 - 2075 1662 1330 - 2076 1662 1487 - 2077 1663 1663 - 2078 1664 1859 - 2080 1665 2080 - 2082 1666 2331 - 2084 1667 2611 - 2087 1669 2915 - 2090 1671 3236 - 2094 1673 3574 - 2099 1675 3919 - 2104 1678 4076 - 2109 1681 4095 - 2114 1683 4095 - 2117 1683 4095 - 2117 1680 4095 - 2113 1673 4095 - 2107 1664 4095 - 2102 1658 4095 - 2102 1656 4095 - 2102 1656 4095 - 2102 1656 4095 - 2102 1656 4095 - 2084 1864 3 - 2084 1864 109 - 2085 1864 225 - 2085 1864 352 - 2085 1864 487 - 2085 1865 627 - 2085 1865 770 - 2086 1865 912 - 2086 1865 1051 - 2086 1866 1191 - 2087 1866 1334 - 2088 1867 1492 - 2088 1867 1670 - 2089 1868 1868 - 2091 1869 2091 - 2092 1870 2344 - 2094 1871 2627 - 2096 1873 2933 - 2099 1875 3254 - 2102 1878 3588 - 2106 1880 3926 - 2110 1883 4074 - 2114 1886 4095 - 2117 1887 4095 - 2118 1886 4095 - 2116 1883 4095 - 2111 1877 4095 - 2105 1870 4095 - 2102 1865 4095 - 2102 1865 4095 - 2102 1865 4095 - 2102 1865 4095 - 2102 1865 4095 - 2097 2097 3 - 2097 2097 105 - 2097 2097 218 - 2097 2097 344 - 2097 2097 479 - 2097 2097 622 - 2097 2097 767 - 2097 2097 911 - 2098 2098 1052 - 2098 2098 1192 - 2099 2099 1337 - 2099 2099 1497 - 2100 2100 1676 - 2101 2101 1876 - 2102 2102 2102 - 2103 2103 2359 - 2104 2104 2645 - 2106 2106 2953 - 2108 2108 3273 - 2111 2111 3602 - 2113 2113 3927 - 2115 2115 4072 - 2117 2117 4095 - 2118 2118 4095 - 2117 2117 4095 - 2113 2113 4095 - 2108 2108 4095 - 2103 2103 4095 - 2102 2102 4095 - 2102 2102 4095 - 2102 2102 4095 - 2102 2102 4095 - 2102 2102 4095 - 2108 2367 0 - 2108 2367 99 - 2108 2367 208 - 2108 2367 333 - 2109 2367 470 - 2109 2367 614 - 2109 2367 762 - 2109 2368 908 - 2109 2368 1050 - 2109 2368 1192 - 2110 2369 1338 - 2110 2369 1500 - 2110 2370 1681 - 2111 2370 1884 - 2112 2371 2112 - 2112 2372 2372 - 2113 2374 2661 - 2114 2375 2972 - 2115 2377 3289 - 2116 2379 3612 - 2117 2381 3918 - 2118 2382 4069 - 2117 2383 4095 - 2116 2383 4095 - 2113 2382 4095 - 2109 2380 4095 - 2105 2377 4095 - 2102 2375 4095 - 2102 2375 4095 - 2102 2375 4095 - 2102 2375 4095 - 2102 2375 4095 - 2102 2375 4095 - 2116 2669 0 - 2116 2669 90 - 2116 2669 194 - 2116 2669 318 - 2116 2669 456 - 2116 2670 603 - 2116 2670 753 - 2117 2670 901 - 2117 2670 1045 - 2117 2670 1189 - 2117 2671 1336 - 2117 2671 1500 - 2117 2671 1683 - 2117 2672 1887 - 2117 2672 2117 - 2117 2673 2381 - 2118 2674 2674 - 2118 2675 2985 - 2118 2676 3299 - 2117 2677 3614 - 2117 2678 3904 - 2116 2679 4065 - 2114 2679 4095 - 2112 2679 4095 - 2109 2678 4095 - 2105 2677 4095 - 2103 2677 4095 - 2102 2677 4095 - 2102 2677 4095 - 2102 2677 4095 - 2102 2677 4095 - 2102 2677 4095 - 2102 2677 4095 - 2117 2989 2 - 2117 2989 78 - 2117 2989 176 - 2117 2989 297 - 2117 2989 436 - 2117 2989 586 - 2117 2990 740 - 2117 2990 890 - 2117 2990 1035 - 2116 2990 1180 - 2116 2990 1328 - 2116 2990 1493 - 2116 2990 1677 - 2116 2990 1883 - 2116 2990 2116 - 2116 2991 2383 - 2115 2991 2679 - 2115 2991 2991 - 2114 2991 3301 - 2113 2991 3607 - 2112 2992 3884 - 2110 2991 4062 - 2108 2991 4095 - 2106 2991 4095 - 2104 2991 4095 - 2102 2991 4095 - 2102 2991 4095 - 2102 2991 4095 - 2102 2991 4095 - 2102 2991 4095 - 2102 2991 4095 - 2102 2991 4095 - 2102 2991 4095 - 2110 3299 3 - 2110 3299 62 - 2110 3299 151 - 2110 3299 272 - 2110 3299 413 - 2110 3299 566 - 2110 3299 722 - 2110 3299 875 - 2110 3299 1021 - 2110 3299 1167 - 2110 3299 1316 - 2109 3299 1482 - 2109 3298 1667 - 2109 3298 1874 - 2109 3298 2109 - 2108 3298 2379 - 2108 3298 2678 - 2107 3297 2991 - 2107 3297 3297 - 2106 3297 3595 - 2105 3296 3864 - 2104 3296 4059 - 2103 3295 4095 - 2102 3295 4095 - 2102 3295 4095 - 2102 3295 4095 - 2102 3295 4095 - 2102 3295 4095 - 2102 3295 4095 - 2102 3295 4095 - 2102 3295 4095 - 2102 3295 4095 - 2102 3295 4095 - 2103 3590 0 - 2103 3590 43 - 2103 3590 127 - 2103 3590 248 - 2103 3590 392 - 2103 3590 548 - 2103 3590 707 - 2103 3590 862 - 2103 3589 1009 - 2103 3589 1155 - 2103 3589 1305 - 2103 3589 1471 - 2103 3589 1658 - 2103 3589 1866 - 2102 3589 2102 - 2102 3589 2375 - 2102 3589 2677 - 2102 3588 2991 - 2102 3588 3295 - 2102 3588 3588 - 2102 3588 3852 - 2102 3588 4057 - 2102 3588 4095 - 2102 3588 4095 - 2102 3588 4095 - 2102 3588 4095 - 2102 3588 4095 - 2102 3588 4095 - 2102 3588 4095 - 2102 3588 4095 - 2102 3588 4095 - 2102 3588 4095 - 2102 3588 4095 - 2102 3852 0 - 2102 3852 36 - 2102 3852 119 - 2102 3852 242 - 2102 3852 387 - 2102 3852 543 - 2102 3852 704 - 2102 3852 858 - 2102 3852 1006 - 2102 3852 1152 - 2102 3852 1303 - 2102 3852 1469 - 2102 3852 1656 - 2102 3852 1865 - 2102 3852 2102 - 2102 3852 2375 - 2102 3852 2677 - 2102 3852 2991 - 2102 3852 3295 - 2102 3852 3588 - 2102 3852 3852 - 2102 3852 4057 - 2102 3852 4095 - 2102 3852 4095 - 2102 3852 4095 - 2102 3852 4095 - 2102 3852 4095 - 2102 3852 4095 - 2102 3852 4095 - 2102 3852 4095 - 2102 3852 4095 - 2102 3852 4095 - 2102 3852 4095 - 2102 4057 0 - 2102 4057 36 - 2102 4057 119 - 2102 4057 242 - 2102 4057 387 - 2102 4057 543 - 2102 4057 704 - 2102 4057 858 - 2102 4057 1006 - 2102 4057 1152 - 2102 4057 1303 - 2102 4057 1469 - 2102 4057 1656 - 2102 4057 1865 - 2102 4057 2102 - 2102 4057 2375 - 2102 4057 2677 - 2102 4057 2991 - 2102 4057 3295 - 2102 4057 3588 - 2102 4057 3852 - 2102 4057 4057 - 2102 4057 4095 - 2102 4057 4095 - 2102 4057 4095 - 2102 4057 4095 - 2102 4057 4095 - 2102 4057 4095 - 2102 4057 4095 - 2102 4057 4095 - 2102 4057 4095 - 2102 4057 4095 - 2102 4057 4095 - 2102 4095 0 - 2102 4095 36 - 2102 4095 119 - 2102 4095 242 - 2102 4095 387 - 2102 4095 543 - 2102 4095 704 - 2102 4095 858 - 2102 4095 1006 - 2102 4095 1152 - 2102 4095 1303 - 2102 4095 1469 - 2102 4095 1656 - 2102 4095 1865 - 2102 4095 2102 - 2102 4095 2375 - 2102 4095 2677 - 2102 4095 2991 - 2102 4095 3295 - 2102 4095 3588 - 2102 4095 3852 - 2102 4095 4057 - 2102 4095 4095 - 2102 4095 4095 - 2102 4095 4095 - 2102 4095 4095 - 2102 4095 4095 - 2102 4095 4095 - 2102 4095 4095 - 2102 4095 4095 - 2102 4095 4095 - 2102 4095 4095 - 2102 4095 4095 - 2102 4095 0 - 2102 4095 36 - 2102 4095 119 - 2102 4095 242 - 2102 4095 387 - 2102 4095 543 - 2102 4095 704 - 2102 4095 858 - 2102 4095 1006 - 2102 4095 1152 - 2102 4095 1303 - 2102 4095 1469 - 2102 4095 1656 - 2102 4095 1865 - 2102 4095 2102 - 2102 4095 2375 - 2102 4095 2677 - 2102 4095 2991 - 2102 4095 3295 - 2102 4095 3588 - 2102 4095 3852 - 2102 4095 4057 - 2102 4095 4095 - 2102 4095 4095 - 2102 4095 4095 - 2102 4095 4095 - 2102 4095 4095 - 2102 4095 4095 - 2102 4095 4095 - 2102 4095 4095 - 2102 4095 4095 - 2102 4095 4095 - 2102 4095 4095 - 2102 4095 0 - 2102 4095 36 - 2102 4095 119 - 2102 4095 242 - 2102 4095 387 - 2102 4095 543 - 2102 4095 704 - 2102 4095 858 - 2102 4095 1006 - 2102 4095 1152 - 2102 4095 1303 - 2102 4095 1469 - 2102 4095 1656 - 2102 4095 1865 - 2102 4095 2102 - 2102 4095 2375 - 2102 4095 2677 - 2102 4095 2991 - 2102 4095 3295 - 2102 4095 3588 - 2102 4095 3852 - 2102 4095 4057 - 2102 4095 4095 - 2102 4095 4095 - 2102 4095 4095 - 2102 4095 4095 - 2102 4095 4095 - 2102 4095 4095 - 2102 4095 4095 - 2102 4095 4095 - 2102 4095 4095 - 2102 4095 4095 - 2102 4095 4095 - 2102 4095 0 - 2102 4095 36 - 2102 4095 119 - 2102 4095 242 - 2102 4095 387 - 2102 4095 543 - 2102 4095 704 - 2102 4095 858 - 2102 4095 1006 - 2102 4095 1152 - 2102 4095 1303 - 2102 4095 1469 - 2102 4095 1656 - 2102 4095 1865 - 2102 4095 2102 - 2102 4095 2375 - 2102 4095 2677 - 2102 4095 2991 - 2102 4095 3295 - 2102 4095 3588 - 2102 4095 3852 - 2102 4095 4057 - 2102 4095 4095 - 2102 4095 4095 - 2102 4095 4095 - 2102 4095 4095 - 2102 4095 4095 - 2102 4095 4095 - 2102 4095 4095 - 2102 4095 4095 - 2102 4095 4095 - 2102 4095 4095 - 2102 4095 4095 - 2102 4095 0 - 2102 4095 36 - 2102 4095 119 - 2102 4095 242 - 2102 4095 387 - 2102 4095 543 - 2102 4095 704 - 2102 4095 858 - 2102 4095 1006 - 2102 4095 1152 - 2102 4095 1303 - 2102 4095 1469 - 2102 4095 1656 - 2102 4095 1865 - 2102 4095 2102 - 2102 4095 2375 - 2102 4095 2677 - 2102 4095 2991 - 2102 4095 3295 - 2102 4095 3588 - 2102 4095 3852 - 2102 4095 4057 - 2102 4095 4095 - 2102 4095 4095 - 2102 4095 4095 - 2102 4095 4095 - 2102 4095 4095 - 2102 4095 4095 - 2102 4095 4095 - 2102 4095 4095 - 2102 4095 4095 - 2102 4095 4095 - 2102 4095 4095 - 2102 4095 0 - 2102 4095 36 - 2102 4095 119 - 2102 4095 242 - 2102 4095 387 - 2102 4095 543 - 2102 4095 704 - 2102 4095 858 - 2102 4095 1006 - 2102 4095 1152 - 2102 4095 1303 - 2102 4095 1469 - 2102 4095 1656 - 2102 4095 1865 - 2102 4095 2102 - 2102 4095 2375 - 2102 4095 2677 - 2102 4095 2991 - 2102 4095 3295 - 2102 4095 3588 - 2102 4095 3852 - 2102 4095 4057 - 2102 4095 4095 - 2102 4095 4095 - 2102 4095 4095 - 2102 4095 4095 - 2102 4095 4095 - 2102 4095 4095 - 2102 4095 4095 - 2102 4095 4095 - 2102 4095 4095 - 2102 4095 4095 - 2102 4095 4095 - 2102 4095 0 - 2102 4095 36 - 2102 4095 119 - 2102 4095 242 - 2102 4095 387 - 2102 4095 543 - 2102 4095 704 - 2102 4095 858 - 2102 4095 1006 - 2102 4095 1152 - 2102 4095 1303 - 2102 4095 1469 - 2102 4095 1656 - 2102 4095 1865 - 2102 4095 2102 - 2102 4095 2375 - 2102 4095 2677 - 2102 4095 2991 - 2102 4095 3295 - 2102 4095 3588 - 2102 4095 3852 - 2102 4095 4057 - 2102 4095 4095 - 2102 4095 4095 - 2102 4095 4095 - 2102 4095 4095 - 2102 4095 4095 - 2102 4095 4095 - 2102 4095 4095 - 2102 4095 4095 - 2102 4095 4095 - 2102 4095 4095 - 2102 4095 4095 - 2102 4095 0 - 2102 4095 36 - 2102 4095 119 - 2102 4095 242 - 2102 4095 387 - 2102 4095 543 - 2102 4095 704 - 2102 4095 858 - 2102 4095 1006 - 2102 4095 1152 - 2102 4095 1303 - 2102 4095 1469 - 2102 4095 1656 - 2102 4095 1865 - 2102 4095 2102 - 2102 4095 2375 - 2102 4095 2677 - 2102 4095 2991 - 2102 4095 3295 - 2102 4095 3588 - 2102 4095 3852 - 2102 4095 4057 - 2102 4095 4095 - 2102 4095 4095 - 2102 4095 4095 - 2102 4095 4095 - 2102 4095 4095 - 2102 4095 4095 - 2102 4095 4095 - 2102 4095 4095 - 2102 4095 4095 - 2102 4095 4095 - 2102 4095 4095 - 2102 4095 0 - 2102 4095 36 - 2102 4095 119 - 2102 4095 242 - 2102 4095 387 - 2102 4095 543 - 2102 4095 704 - 2102 4095 858 - 2102 4095 1006 - 2102 4095 1152 - 2102 4095 1303 - 2102 4095 1469 - 2102 4095 1656 - 2102 4095 1865 - 2102 4095 2102 - 2102 4095 2375 - 2102 4095 2677 - 2102 4095 2991 - 2102 4095 3295 - 2102 4095 3588 - 2102 4095 3852 - 2102 4095 4057 - 2102 4095 4095 - 2102 4095 4095 - 2102 4095 4095 - 2102 4095 4095 - 2102 4095 4095 - 2102 4095 4095 - 2102 4095 4095 - 2102 4095 4095 - 2102 4095 4095 - 2102 4095 4095 - 2102 4095 4095 - 2102 4095 0 - 2102 4095 36 - 2102 4095 119 - 2102 4095 242 - 2102 4095 387 - 2102 4095 543 - 2102 4095 704 - 2102 4095 858 - 2102 4095 1006 - 2102 4095 1152 - 2102 4095 1303 - 2102 4095 1469 - 2102 4095 1656 - 2102 4095 1865 - 2102 4095 2102 - 2102 4095 2375 - 2102 4095 2677 - 2102 4095 2991 - 2102 4095 3295 - 2102 4095 3588 - 2102 4095 3852 - 2102 4095 4057 - 2102 4095 4095 - 2102 4095 4095 - 2102 4095 4095 - 2102 4095 4095 - 2102 4095 4095 - 2102 4095 4095 - 2102 4095 4095 - 2102 4095 4095 - 2102 4095 4095 - 2102 4095 4095 - 2102 4095 4095 - 2102 4095 0 - 2102 4095 36 - 2102 4095 119 - 2102 4095 242 - 2102 4095 387 - 2102 4095 543 - 2102 4095 704 - 2102 4095 858 - 2102 4095 1006 - 2102 4095 1152 - 2102 4095 1303 - 2102 4095 1469 - 2102 4095 1656 - 2102 4095 1865 - 2102 4095 2102 - 2102 4095 2375 - 2102 4095 2677 - 2102 4095 2991 - 2102 4095 3295 - 2102 4095 3588 - 2102 4095 3852 - 2102 4095 4057 - 2102 4095 4095 - 2102 4095 4095 - 2102 4095 4095 - 2102 4095 4095 - 2102 4095 4095 - 2102 4095 4095 - 2102 4095 4095 - 2102 4095 4095 - 2102 4095 4095 - 2102 4095 4095 - 2102 4095 4095 - 2199 2 3 - 2200 1 119 - 2200 1 240 - 2201 1 365 - 2202 2 493 - 2203 2 623 - 2205 0 755 - 2207 0 886 - 2209 0 1017 - 2212 0 1149 - 2215 1 1283 - 2219 2 1434 - 2223 1 1602 - 2229 2 1790 - 2235 2 2002 - 2243 2 2243 - 2252 3 2513 - 2263 2 2813 - 2274 2 3139 - 2287 2 3492 - 2301 2 3867 - 2315 2 4083 - 2330 3 4095 - 2344 2 4095 - 2359 3 4095 - 2373 0 4095 - 2382 1 4095 - 2383 3 4095 - 2378 2 4095 - 2375 2 4095 - 2375 0 4095 - 2375 0 4095 - 2375 0 4095 - 2201 119 3 - 2201 119 119 - 2201 119 240 - 2202 119 365 - 2203 119 493 - 2204 119 623 - 2206 119 755 - 2208 119 886 - 2210 119 1018 - 2213 119 1149 - 2216 119 1284 - 2220 119 1434 - 2224 119 1602 - 2230 119 1791 - 2236 119 2003 - 2244 119 2244 - 2253 118 2514 - 2263 118 2814 - 2275 117 3140 - 2288 116 3493 - 2301 115 3867 - 2316 113 4083 - 2330 110 4095 - 2344 107 4095 - 2360 102 4095 - 2374 95 4095 - 2382 85 4095 - 2383 72 4095 - 2378 55 4095 - 2375 39 4095 - 2375 36 4095 - 2375 36 4095 - 2375 36 4095 - 2204 240 1 - 2205 240 119 - 2205 240 240 - 2206 240 365 - 2207 240 494 - 2208 240 624 - 2209 241 756 - 2211 241 888 - 2214 241 1019 - 2216 241 1150 - 2219 241 1286 - 2223 241 1436 - 2227 240 1604 - 2233 240 1793 - 2239 240 2005 - 2247 240 2246 - 2255 240 2517 - 2265 239 2817 - 2277 238 3143 - 2289 236 3495 - 2303 234 3869 - 2317 231 4083 - 2331 227 4095 - 2345 221 4095 - 2360 213 4095 - 2374 202 4095 - 2382 186 4095 - 2383 166 4095 - 2378 141 4095 - 2375 121 4095 - 2375 119 4095 - 2375 119 4095 - 2375 119 4095 - 2211 366 2 - 2211 366 119 - 2211 366 241 - 2212 366 366 - 2213 366 494 - 2214 366 625 - 2216 366 757 - 2218 366 889 - 2220 366 1021 - 2222 366 1153 - 2225 366 1288 - 2228 366 1439 - 2233 366 1608 - 2238 366 1797 - 2244 366 2010 - 2251 366 2251 - 2259 366 2521 - 2269 365 2821 - 2280 365 3147 - 2292 363 3499 - 2305 361 3872 - 2319 358 4083 - 2333 353 4095 - 2346 346 4095 - 2361 337 4095 - 2374 325 4095 - 2382 308 4095 - 2383 286 4095 - 2378 261 4095 - 2375 243 4095 - 2375 242 4095 - 2375 242 4095 - 2375 242 4095 - 2220 495 2 - 2220 495 119 - 2220 495 241 - 2221 495 366 - 2222 495 495 - 2223 495 626 - 2224 495 759 - 2226 495 892 - 2228 496 1024 - 2230 496 1156 - 2233 496 1292 - 2236 496 1443 - 2240 496 1612 - 2245 496 1802 - 2250 497 2015 - 2257 497 2257 - 2265 497 2528 - 2274 497 2828 - 2284 496 3153 - 2296 495 3505 - 2308 494 3876 - 2321 491 4082 - 2335 487 4095 - 2348 481 4095 - 2363 473 4095 - 2375 461 4095 - 2383 446 4095 - 2382 425 4095 - 2378 403 4095 - 2375 388 4095 - 2375 387 4095 - 2375 387 4095 - 2375 387 4095 - 2231 628 2 - 2231 628 119 - 2231 628 240 - 2232 628 366 - 2232 628 496 - 2233 628 628 - 2235 628 761 - 2236 628 895 - 2238 629 1027 - 2240 629 1160 - 2242 629 1297 - 2245 630 1448 - 2249 630 1618 - 2253 630 1808 - 2258 631 2022 - 2265 631 2265 - 2272 632 2536 - 2280 632 2837 - 2290 632 3162 - 2301 632 3512 - 2312 631 3881 - 2325 630 4082 - 2337 627 4095 - 2350 622 4095 - 2364 616 4095 - 2376 607 4095 - 2383 593 4095 - 2382 575 4095 - 2378 556 4095 - 2375 544 4095 - 2375 543 4095 - 2375 543 4095 - 2375 543 4095 - 2243 763 2 - 2243 763 119 - 2243 763 240 - 2244 764 366 - 2244 764 496 - 2245 764 629 - 2247 764 764 - 2248 764 898 - 2250 765 1031 - 2251 765 1165 - 2254 765 1302 - 2256 766 1454 - 2259 766 1625 - 2263 767 1816 - 2268 768 2030 - 2274 769 2273 - 2280 769 2546 - 2288 770 2847 - 2297 771 3171 - 2307 771 3520 - 2317 772 3886 - 2329 771 4081 - 2341 769 4095 - 2353 766 4095 - 2367 762 4095 - 2378 755 4095 - 2383 744 4095 - 2382 729 4095 - 2377 713 4095 - 2375 704 4095 - 2375 704 4095 - 2375 704 4095 - 2375 704 4095 - 2256 900 2 - 2256 900 118 - 2257 900 239 - 2257 901 366 - 2258 901 497 - 2258 901 631 - 2259 901 766 - 2261 901 901 - 2262 902 1035 - 2264 902 1170 - 2266 903 1308 - 2268 903 1461 - 2271 904 1632 - 2274 905 1823 - 2278 905 2039 - 2283 906 2283 - 2289 908 2557 - 2296 909 2858 - 2304 910 3182 - 2313 911 3529 - 2323 912 3892 - 2334 912 4081 - 2345 911 4095 - 2357 910 4095 - 2369 907 4095 - 2379 902 4095 - 2383 893 4095 - 2382 880 4095 - 2377 866 4095 - 2375 859 4095 - 2375 858 4095 - 2375 858 4095 - 2375 858 4095 - 2270 1038 2 - 2270 1038 117 - 2270 1038 239 - 2271 1038 365 - 2271 1038 497 - 2272 1039 632 - 2273 1039 768 - 2274 1039 904 - 2275 1039 1039 - 2276 1040 1174 - 2278 1040 1313 - 2280 1041 1467 - 2283 1042 1639 - 2286 1042 1832 - 2289 1043 2048 - 2294 1044 2293 - 2299 1046 2568 - 2305 1047 2870 - 2312 1048 3193 - 2320 1050 3538 - 2329 1051 3899 - 2339 1052 4080 - 2349 1052 4095 - 2360 1051 4095 - 2372 1049 4095 - 2380 1045 4095 - 2383 1036 4095 - 2381 1024 4095 - 2377 1012 4095 - 2375 1006 4095 - 2375 1006 4095 - 2375 1006 4095 - 2375 1006 4095 - 2284 1177 2 - 2284 1177 117 - 2284 1177 237 - 2284 1177 364 - 2285 1177 496 - 2285 1178 632 - 2286 1178 770 - 2287 1178 907 - 2288 1179 1043 - 2289 1179 1179 - 2291 1179 1318 - 2292 1180 1473 - 2295 1181 1646 - 2297 1181 1840 - 2300 1182 2057 - 2304 1184 2304 - 2309 1185 2580 - 2314 1186 2882 - 2320 1188 3205 - 2327 1189 3548 - 2335 1191 3905 - 2344 1192 4079 - 2354 1192 4095 - 2364 1193 4095 - 2374 1192 4095 - 2381 1187 4095 - 2383 1179 4095 - 2380 1168 4095 - 2376 1157 4095 - 2375 1152 4095 - 2375 1152 4095 - 2375 1152 4095 - 2375 1152 4095 - 2297 1321 2 - 2298 1321 115 - 2298 1321 235 - 2298 1321 362 - 2298 1321 495 - 2299 1322 632 - 2299 1322 771 - 2300 1322 909 - 2301 1322 1046 - 2302 1323 1183 - 2303 1323 1323 - 2305 1324 1479 - 2307 1324 1653 - 2309 1325 1848 - 2311 1326 2066 - 2315 1327 2315 - 2319 1329 2592 - 2323 1330 2895 - 2329 1332 3217 - 2335 1333 3558 - 2342 1335 3910 - 2350 1336 4078 - 2359 1338 4095 - 2369 1339 4095 - 2377 1338 4095 - 2382 1334 4095 - 2383 1326 4095 - 2380 1315 4095 - 2376 1306 4095 - 2375 1303 4095 - 2375 1303 4095 - 2375 1303 4095 - 2375 1303 4095 - 2312 1482 2 - 2312 1482 114 - 2312 1482 232 - 2312 1482 359 - 2312 1482 493 - 2313 1483 631 - 2313 1483 771 - 2314 1483 911 - 2315 1483 1049 - 2316 1484 1187 - 2317 1484 1328 - 2318 1485 1485 - 2319 1485 1660 - 2321 1486 1856 - 2323 1487 2076 - 2326 1488 2326 - 2329 1489 2605 - 2333 1491 2909 - 2338 1492 3231 - 2343 1494 3569 - 2349 1496 3916 - 2357 1498 4077 - 2365 1500 4095 - 2373 1501 4095 - 2380 1500 4095 - 2383 1496 4095 - 2383 1489 4095 - 2379 1479 4095 - 2376 1471 4095 - 2375 1469 4095 - 2375 1469 4095 - 2375 1469 4095 - 2375 1469 4095 - 2326 1664 2 - 2326 1664 111 - 2326 1664 228 - 2327 1664 355 - 2327 1664 489 - 2327 1664 629 - 2328 1664 771 - 2328 1664 912 - 2329 1665 1051 - 2329 1665 1190 - 2330 1665 1332 - 2331 1666 1490 - 2332 1666 1666 - 2334 1667 1864 - 2336 1668 2085 - 2338 1669 2338 - 2340 1670 2619 - 2344 1672 2924 - 2348 1673 3245 - 2352 1675 3581 - 2358 1678 3923 - 2364 1680 4075 - 2371 1682 4095 - 2377 1683 4095 - 2382 1682 4095 - 2383 1678 4095 - 2382 1671 4095 - 2378 1663 4095 - 2375 1657 4095 - 2375 1656 4095 - 2375 1656 4095 - 2375 1656 4095 - 2375 1656 4095 - 2341 1868 3 - 2341 1868 108 - 2341 1868 223 - 2341 1868 349 - 2341 1868 484 - 2341 1868 625 - 2342 1869 769 - 2342 1869 911 - 2343 1869 1052 - 2343 1869 1191 - 2344 1870 1335 - 2344 1870 1494 - 2345 1871 1672 - 2347 1871 1871 - 2348 1872 2095 - 2350 1873 2350 - 2352 1875 2634 - 2355 1876 2941 - 2359 1878 3261 - 2363 1880 3594 - 2367 1883 3928 - 2372 1885 4073 - 2377 1886 4095 - 2381 1887 4095 - 2383 1886 4095 - 2383 1882 4095 - 2380 1875 4095 - 2377 1869 4095 - 2375 1865 4095 - 2375 1865 4095 - 2375 1865 4095 - 2375 1865 4095 - 2375 1865 4095 - 2356 2101 0 - 2356 2101 103 - 2356 2101 215 - 2356 2101 341 - 2356 2101 477 - 2356 2101 620 - 2356 2101 765 - 2357 2101 910 - 2357 2102 1051 - 2358 2102 1193 - 2358 2102 1338 - 2359 2103 1498 - 2360 2104 1678 - 2361 2104 1879 - 2362 2105 2105 - 2363 2106 2363 - 2365 2108 2650 - 2367 2109 2960 - 2370 2111 3278 - 2373 2113 3606 - 2376 2115 3924 - 2379 2117 4071 - 2382 2118 4095 - 2383 2118 4095 - 2383 2116 4095 - 2381 2112 4095 - 2378 2107 4095 - 2376 2103 4095 - 2375 2102 4095 - 2375 2102 4095 - 2375 2102 4095 - 2375 2102 4095 - 2375 2102 4095 - 2370 2370 2 - 2370 2370 97 - 2370 2370 205 - 2370 2370 329 - 2370 2371 466 - 2370 2371 612 - 2371 2371 760 - 2371 2371 906 - 2371 2371 1049 - 2371 2372 1192 - 2372 2372 1338 - 2372 2372 1501 - 2373 2373 1682 - 2373 2374 1885 - 2374 2374 2114 - 2375 2375 2375 - 2376 2376 2665 - 2377 2378 2976 - 2379 2379 3292 - 2380 2380 3613 - 2382 2382 3915 - 2383 2383 4068 - 2383 2383 4095 - 2383 2383 4095 - 2381 2382 4095 - 2379 2379 4095 - 2377 2377 4095 - 2375 2375 4095 - 2375 2375 4095 - 2375 2375 4095 - 2375 2375 4095 - 2375 2375 4095 - 2375 2375 4095 - 2380 2672 0 - 2380 2672 88 - 2380 2672 191 - 2380 2672 314 - 2380 2672 452 - 2381 2672 600 - 2381 2672 751 - 2381 2672 900 - 2381 2672 1044 - 2381 2673 1188 - 2381 2673 1335 - 2381 2673 1499 - 2381 2673 1682 - 2382 2674 1887 - 2382 2674 2118 - 2382 2675 2382 - 2383 2676 2675 - 2383 2676 2987 - 2383 2677 3300 - 2383 2678 3613 - 2383 2679 3900 - 2383 2679 4065 - 2382 2679 4095 - 2381 2679 4095 - 2379 2678 4095 - 2377 2677 4095 - 2375 2677 4095 - 2375 2677 4095 - 2375 2677 4095 - 2375 2677 4095 - 2375 2677 4095 - 2375 2677 4095 - 2375 2677 4095 - 2383 2990 2 - 2383 2990 76 - 2383 2990 172 - 2383 2990 293 - 2383 2990 433 - 2383 2990 583 - 2383 2990 737 - 2383 2990 888 - 2383 2990 1033 - 2383 2991 1178 - 2383 2991 1327 - 2383 2991 1492 - 2383 2991 1676 - 2383 2991 1882 - 2383 2991 2115 - 2383 2991 2383 - 2382 2991 2679 - 2382 2991 2991 - 2382 2991 3301 - 2381 2992 3605 - 2381 2991 3880 - 2380 2991 4061 - 2378 2991 4095 - 2377 2991 4095 - 2376 2991 4095 - 2375 2991 4095 - 2375 2991 4095 - 2375 2991 4095 - 2375 2991 4095 - 2375 2991 4095 - 2375 2991 4095 - 2375 2991 4095 - 2375 2991 4095 - 2379 3298 1 - 2379 3298 60 - 2379 3298 148 - 2379 3298 268 - 2379 3298 410 - 2379 3298 563 - 2379 3298 720 - 2379 3298 873 - 2379 3298 1019 - 2379 3298 1165 - 2379 3298 1314 - 2379 3298 1480 - 2379 3298 1665 - 2379 3298 1873 - 2379 3298 2108 - 2378 3297 2378 - 2378 3297 2678 - 2378 3297 2991 - 2377 3297 3297 - 2377 3296 3593 - 2377 3296 3861 - 2376 3295 4059 - 2376 3295 4095 - 2375 3295 4095 - 2375 3295 4095 - 2375 3295 4095 - 2375 3295 4095 - 2375 3295 4095 - 2375 3295 4095 - 2375 3295 4095 - 2375 3295 4095 - 2375 3295 4095 - 2375 3295 4095 - 2376 3589 2 - 2376 3589 41 - 2376 3589 125 - 2376 3589 247 - 2376 3589 391 - 2376 3589 547 - 2375 3589 706 - 2375 3589 861 - 2375 3589 1008 - 2375 3589 1154 - 2375 3589 1304 - 2375 3589 1471 - 2375 3589 1657 - 2375 3589 1866 - 2375 3588 2102 - 2375 3588 2375 - 2375 3588 2677 - 2375 3588 2991 - 2375 3588 3295 - 2375 3588 3588 - 2375 3588 3852 - 2375 3588 4057 - 2375 3588 4095 - 2375 3588 4095 - 2375 3588 4095 - 2375 3588 4095 - 2375 3588 4095 - 2375 3588 4095 - 2375 3588 4095 - 2375 3588 4095 - 2375 3588 4095 - 2375 3588 4095 - 2375 3588 4095 - 2375 3852 0 - 2375 3852 36 - 2375 3852 119 - 2375 3852 242 - 2375 3852 387 - 2375 3852 543 - 2375 3852 704 - 2375 3852 858 - 2375 3852 1006 - 2375 3852 1152 - 2375 3852 1303 - 2375 3852 1469 - 2375 3852 1656 - 2375 3852 1865 - 2375 3852 2102 - 2375 3852 2375 - 2375 3852 2677 - 2375 3852 2991 - 2375 3852 3295 - 2375 3852 3588 - 2375 3852 3852 - 2375 3852 4057 - 2375 3852 4095 - 2375 3852 4095 - 2375 3852 4095 - 2375 3852 4095 - 2375 3852 4095 - 2375 3852 4095 - 2375 3852 4095 - 2375 3852 4095 - 2375 3852 4095 - 2375 3852 4095 - 2375 3852 4095 - 2375 4057 0 - 2375 4057 36 - 2375 4057 119 - 2375 4057 242 - 2375 4057 387 - 2375 4057 543 - 2375 4057 704 - 2375 4057 858 - 2375 4057 1006 - 2375 4057 1152 - 2375 4057 1303 - 2375 4057 1469 - 2375 4057 1656 - 2375 4057 1865 - 2375 4057 2102 - 2375 4057 2375 - 2375 4057 2677 - 2375 4057 2991 - 2375 4057 3295 - 2375 4057 3588 - 2375 4057 3852 - 2375 4057 4057 - 2375 4057 4095 - 2375 4057 4095 - 2375 4057 4095 - 2375 4057 4095 - 2375 4057 4095 - 2375 4057 4095 - 2375 4057 4095 - 2375 4057 4095 - 2375 4057 4095 - 2375 4057 4095 - 2375 4057 4095 - 2375 4095 0 - 2375 4095 36 - 2375 4095 119 - 2375 4095 242 - 2375 4095 387 - 2375 4095 543 - 2375 4095 704 - 2375 4095 858 - 2375 4095 1006 - 2375 4095 1152 - 2375 4095 1303 - 2375 4095 1469 - 2375 4095 1656 - 2375 4095 1865 - 2375 4095 2102 - 2375 4095 2375 - 2375 4095 2677 - 2375 4095 2991 - 2375 4095 3295 - 2375 4095 3588 - 2375 4095 3852 - 2375 4095 4057 - 2375 4095 4095 - 2375 4095 4095 - 2375 4095 4095 - 2375 4095 4095 - 2375 4095 4095 - 2375 4095 4095 - 2375 4095 4095 - 2375 4095 4095 - 2375 4095 4095 - 2375 4095 4095 - 2375 4095 4095 - 2375 4095 0 - 2375 4095 36 - 2375 4095 119 - 2375 4095 242 - 2375 4095 387 - 2375 4095 543 - 2375 4095 704 - 2375 4095 858 - 2375 4095 1006 - 2375 4095 1152 - 2375 4095 1303 - 2375 4095 1469 - 2375 4095 1656 - 2375 4095 1865 - 2375 4095 2102 - 2375 4095 2375 - 2375 4095 2677 - 2375 4095 2991 - 2375 4095 3295 - 2375 4095 3588 - 2375 4095 3852 - 2375 4095 4057 - 2375 4095 4095 - 2375 4095 4095 - 2375 4095 4095 - 2375 4095 4095 - 2375 4095 4095 - 2375 4095 4095 - 2375 4095 4095 - 2375 4095 4095 - 2375 4095 4095 - 2375 4095 4095 - 2375 4095 4095 - 2375 4095 0 - 2375 4095 36 - 2375 4095 119 - 2375 4095 242 - 2375 4095 387 - 2375 4095 543 - 2375 4095 704 - 2375 4095 858 - 2375 4095 1006 - 2375 4095 1152 - 2375 4095 1303 - 2375 4095 1469 - 2375 4095 1656 - 2375 4095 1865 - 2375 4095 2102 - 2375 4095 2375 - 2375 4095 2677 - 2375 4095 2991 - 2375 4095 3295 - 2375 4095 3588 - 2375 4095 3852 - 2375 4095 4057 - 2375 4095 4095 - 2375 4095 4095 - 2375 4095 4095 - 2375 4095 4095 - 2375 4095 4095 - 2375 4095 4095 - 2375 4095 4095 - 2375 4095 4095 - 2375 4095 4095 - 2375 4095 4095 - 2375 4095 4095 - 2375 4095 0 - 2375 4095 36 - 2375 4095 119 - 2375 4095 242 - 2375 4095 387 - 2375 4095 543 - 2375 4095 704 - 2375 4095 858 - 2375 4095 1006 - 2375 4095 1152 - 2375 4095 1303 - 2375 4095 1469 - 2375 4095 1656 - 2375 4095 1865 - 2375 4095 2102 - 2375 4095 2375 - 2375 4095 2677 - 2375 4095 2991 - 2375 4095 3295 - 2375 4095 3588 - 2375 4095 3852 - 2375 4095 4057 - 2375 4095 4095 - 2375 4095 4095 - 2375 4095 4095 - 2375 4095 4095 - 2375 4095 4095 - 2375 4095 4095 - 2375 4095 4095 - 2375 4095 4095 - 2375 4095 4095 - 2375 4095 4095 - 2375 4095 4095 - 2375 4095 0 - 2375 4095 36 - 2375 4095 119 - 2375 4095 242 - 2375 4095 387 - 2375 4095 543 - 2375 4095 704 - 2375 4095 858 - 2375 4095 1006 - 2375 4095 1152 - 2375 4095 1303 - 2375 4095 1469 - 2375 4095 1656 - 2375 4095 1865 - 2375 4095 2102 - 2375 4095 2375 - 2375 4095 2677 - 2375 4095 2991 - 2375 4095 3295 - 2375 4095 3588 - 2375 4095 3852 - 2375 4095 4057 - 2375 4095 4095 - 2375 4095 4095 - 2375 4095 4095 - 2375 4095 4095 - 2375 4095 4095 - 2375 4095 4095 - 2375 4095 4095 - 2375 4095 4095 - 2375 4095 4095 - 2375 4095 4095 - 2375 4095 4095 - 2375 4095 0 - 2375 4095 36 - 2375 4095 119 - 2375 4095 242 - 2375 4095 387 - 2375 4095 543 - 2375 4095 704 - 2375 4095 858 - 2375 4095 1006 - 2375 4095 1152 - 2375 4095 1303 - 2375 4095 1469 - 2375 4095 1656 - 2375 4095 1865 - 2375 4095 2102 - 2375 4095 2375 - 2375 4095 2677 - 2375 4095 2991 - 2375 4095 3295 - 2375 4095 3588 - 2375 4095 3852 - 2375 4095 4057 - 2375 4095 4095 - 2375 4095 4095 - 2375 4095 4095 - 2375 4095 4095 - 2375 4095 4095 - 2375 4095 4095 - 2375 4095 4095 - 2375 4095 4095 - 2375 4095 4095 - 2375 4095 4095 - 2375 4095 4095 - 2375 4095 0 - 2375 4095 36 - 2375 4095 119 - 2375 4095 242 - 2375 4095 387 - 2375 4095 543 - 2375 4095 704 - 2375 4095 858 - 2375 4095 1006 - 2375 4095 1152 - 2375 4095 1303 - 2375 4095 1469 - 2375 4095 1656 - 2375 4095 1865 - 2375 4095 2102 - 2375 4095 2375 - 2375 4095 2677 - 2375 4095 2991 - 2375 4095 3295 - 2375 4095 3588 - 2375 4095 3852 - 2375 4095 4057 - 2375 4095 4095 - 2375 4095 4095 - 2375 4095 4095 - 2375 4095 4095 - 2375 4095 4095 - 2375 4095 4095 - 2375 4095 4095 - 2375 4095 4095 - 2375 4095 4095 - 2375 4095 4095 - 2375 4095 4095 - 2375 4095 0 - 2375 4095 36 - 2375 4095 119 - 2375 4095 242 - 2375 4095 387 - 2375 4095 543 - 2375 4095 704 - 2375 4095 858 - 2375 4095 1006 - 2375 4095 1152 - 2375 4095 1303 - 2375 4095 1469 - 2375 4095 1656 - 2375 4095 1865 - 2375 4095 2102 - 2375 4095 2375 - 2375 4095 2677 - 2375 4095 2991 - 2375 4095 3295 - 2375 4095 3588 - 2375 4095 3852 - 2375 4095 4057 - 2375 4095 4095 - 2375 4095 4095 - 2375 4095 4095 - 2375 4095 4095 - 2375 4095 4095 - 2375 4095 4095 - 2375 4095 4095 - 2375 4095 4095 - 2375 4095 4095 - 2375 4095 4095 - 2375 4095 4095 - 2375 4095 0 - 2375 4095 36 - 2375 4095 119 - 2375 4095 242 - 2375 4095 387 - 2375 4095 543 - 2375 4095 704 - 2375 4095 858 - 2375 4095 1006 - 2375 4095 1152 - 2375 4095 1303 - 2375 4095 1469 - 2375 4095 1656 - 2375 4095 1865 - 2375 4095 2102 - 2375 4095 2375 - 2375 4095 2677 - 2375 4095 2991 - 2375 4095 3295 - 2375 4095 3588 - 2375 4095 3852 - 2375 4095 4057 - 2375 4095 4095 - 2375 4095 4095 - 2375 4095 4095 - 2375 4095 4095 - 2375 4095 4095 - 2375 4095 4095 - 2375 4095 4095 - 2375 4095 4095 - 2375 4095 4095 - 2375 4095 4095 - 2375 4095 4095 - 2375 4095 0 - 2375 4095 36 - 2375 4095 119 - 2375 4095 242 - 2375 4095 387 - 2375 4095 543 - 2375 4095 704 - 2375 4095 858 - 2375 4095 1006 - 2375 4095 1152 - 2375 4095 1303 - 2375 4095 1469 - 2375 4095 1656 - 2375 4095 1865 - 2375 4095 2102 - 2375 4095 2375 - 2375 4095 2677 - 2375 4095 2991 - 2375 4095 3295 - 2375 4095 3588 - 2375 4095 3852 - 2375 4095 4057 - 2375 4095 4095 - 2375 4095 4095 - 2375 4095 4095 - 2375 4095 4095 - 2375 4095 4095 - 2375 4095 4095 - 2375 4095 4095 - 2375 4095 4095 - 2375 4095 4095 - 2375 4095 4095 - 2375 4095 4095 - 2375 4095 0 - 2375 4095 36 - 2375 4095 119 - 2375 4095 242 - 2375 4095 387 - 2375 4095 543 - 2375 4095 704 - 2375 4095 858 - 2375 4095 1006 - 2375 4095 1152 - 2375 4095 1303 - 2375 4095 1469 - 2375 4095 1656 - 2375 4095 1865 - 2375 4095 2102 - 2375 4095 2375 - 2375 4095 2677 - 2375 4095 2991 - 2375 4095 3295 - 2375 4095 3588 - 2375 4095 3852 - 2375 4095 4057 - 2375 4095 4095 - 2375 4095 4095 - 2375 4095 4095 - 2375 4095 4095 - 2375 4095 4095 - 2375 4095 4095 - 2375 4095 4095 - 2375 4095 4095 - 2375 4095 4095 - 2375 4095 4095 - 2375 4095 4095 - 2494 0 1 - 2494 0 119 - 2494 1 240 - 2495 1 366 - 2495 2 496 - 2497 2 628 - 2498 2 762 - 2500 2 896 - 2502 1 1029 - 2504 2 1162 - 2507 2 1299 - 2510 3 1451 - 2514 2 1621 - 2519 2 1811 - 2525 3 2025 - 2532 2 2268 - 2540 1 2540 - 2549 2 2840 - 2560 2 3165 - 2573 1 3514 - 2587 2 3883 - 2601 3 4082 - 2617 0 4095 - 2633 2 4095 - 2650 1 4095 - 2666 3 4095 - 2676 3 4095 - 2679 1 4095 - 2677 2 4095 - 2677 0 4095 - 2677 0 4095 - 2677 0 4095 - 2677 0 4095 - 2494 119 2 - 2495 119 119 - 2495 119 240 - 2495 119 366 - 2496 119 496 - 2497 119 629 - 2499 119 762 - 2501 119 896 - 2503 119 1029 - 2505 119 1162 - 2507 118 1299 - 2511 118 1451 - 2515 118 1621 - 2519 118 1811 - 2525 118 2026 - 2532 118 2268 - 2540 117 2540 - 2550 117 2841 - 2561 116 3165 - 2573 115 3515 - 2587 113 3883 - 2602 111 4082 - 2617 108 4095 - 2633 104 4095 - 2651 99 4095 - 2666 92 4095 - 2676 83 4095 - 2679 69 4095 - 2677 52 4095 - 2677 37 4095 - 2677 36 4095 - 2677 36 4095 - 2677 36 4095 - 2498 240 2 - 2498 240 119 - 2498 240 240 - 2499 240 366 - 2499 240 496 - 2501 240 629 - 2502 240 763 - 2504 240 897 - 2506 240 1030 - 2508 240 1163 - 2510 240 1300 - 2513 240 1452 - 2517 240 1622 - 2522 239 1813 - 2528 239 2027 - 2535 239 2270 - 2543 238 2542 - 2552 237 2843 - 2563 236 3168 - 2575 234 3517 - 2588 232 3884 - 2603 228 4081 - 2618 223 4095 - 2634 217 4095 - 2651 209 4095 - 2667 197 4095 - 2676 182 4095 - 2679 161 4095 - 2677 137 4095 - 2677 120 4095 - 2677 119 4095 - 2677 119 4095 - 2677 119 4095 - 2503 366 2 - 2503 366 119 - 2503 366 240 - 2504 366 366 - 2505 366 496 - 2506 366 629 - 2507 366 764 - 2509 366 898 - 2511 366 1031 - 2513 366 1165 - 2515 366 1302 - 2518 366 1455 - 2522 366 1625 - 2526 366 1816 - 2532 365 2030 - 2539 365 2274 - 2546 364 2546 - 2555 364 2847 - 2566 362 3171 - 2578 361 3520 - 2591 358 3886 - 2605 354 4081 - 2619 349 4095 - 2635 342 4095 - 2652 333 4095 - 2667 321 4095 - 2677 303 4095 - 2679 282 4095 - 2677 258 4095 - 2677 243 4095 - 2677 242 4095 - 2677 242 4095 - 2677 242 4095 - 2511 497 3 - 2511 497 118 - 2511 497 240 - 2512 497 366 - 2512 497 497 - 2513 497 630 - 2515 497 765 - 2516 497 900 - 2518 497 1033 - 2520 497 1167 - 2522 497 1305 - 2525 497 1458 - 2528 497 1628 - 2533 497 1820 - 2538 497 2035 - 2544 497 2278 - 2552 496 2551 - 2560 496 2852 - 2570 495 3176 - 2581 493 3524 - 2594 491 3890 - 2607 488 4081 - 2622 483 4095 - 2637 477 4095 - 2654 469 4095 - 2668 457 4095 - 2677 441 4095 - 2679 421 4095 - 2677 399 4095 - 2677 387 4095 - 2677 387 4095 - 2677 387 4095 - 2677 387 4095 - 2520 631 2 - 2520 631 118 - 2521 631 239 - 2521 631 366 - 2522 631 497 - 2523 631 631 - 2524 631 766 - 2525 631 902 - 2527 631 1036 - 2529 631 1170 - 2531 631 1308 - 2533 632 1461 - 2537 632 1633 - 2541 632 1825 - 2545 632 2040 - 2551 632 2285 - 2558 632 2558 - 2566 632 2859 - 2576 632 3183 - 2586 631 3530 - 2598 630 3893 - 2611 627 4080 - 2625 624 4095 - 2640 619 4095 - 2656 613 4095 - 2669 603 4095 - 2677 589 4095 - 2679 571 4095 - 2677 553 4095 - 2677 544 4095 - 2677 543 4095 - 2677 543 4095 - 2677 543 4095 - 2531 768 2 - 2531 768 118 - 2532 768 239 - 2532 768 365 - 2533 768 497 - 2534 768 631 - 2535 768 768 - 2536 768 904 - 2537 768 1039 - 2539 769 1174 - 2541 769 1312 - 2543 769 1466 - 2546 769 1638 - 2550 770 1830 - 2554 770 2046 - 2560 771 2292 - 2566 771 2566 - 2574 771 2868 - 2582 772 3191 - 2592 772 3537 - 2603 771 3898 - 2615 770 4080 - 2628 768 4095 - 2643 765 4095 - 2658 760 4095 - 2671 752 4095 - 2678 741 4095 - 2679 726 4095 - 2677 711 4095 - 2677 704 4095 - 2677 704 4095 - 2677 704 4095 - 2677 704 4095 - 2544 905 2 - 2544 905 117 - 2544 905 238 - 2544 906 365 - 2545 906 496 - 2545 906 632 - 2546 906 769 - 2548 906 906 - 2549 906 1041 - 2550 907 1177 - 2552 907 1316 - 2554 907 1470 - 2557 908 1643 - 2560 908 1836 - 2564 909 2053 - 2569 909 2300 - 2575 910 2575 - 2582 911 2877 - 2590 911 3200 - 2599 912 3544 - 2609 912 3902 - 2620 912 4079 - 2633 911 4095 - 2647 909 4095 - 2661 906 4095 - 2672 900 4095 - 2678 890 4095 - 2679 877 4095 - 2677 864 4095 - 2677 859 4095 - 2677 858 4095 - 2677 858 4095 - 2677 858 4095 - 2556 1043 2 - 2556 1043 116 - 2557 1043 236 - 2557 1043 363 - 2557 1044 496 - 2558 1044 632 - 2559 1044 770 - 2560 1044 908 - 2561 1044 1044 - 2562 1045 1180 - 2564 1045 1320 - 2566 1045 1475 - 2568 1046 1649 - 2571 1046 1843 - 2575 1047 2061 - 2579 1048 2308 - 2584 1049 2584 - 2591 1049 2887 - 2598 1050 3210 - 2606 1051 3552 - 2616 1052 3907 - 2626 1052 4079 - 2638 1052 4095 - 2651 1051 4095 - 2664 1048 4095 - 2674 1043 4095 - 2679 1034 4095 - 2678 1022 4095 - 2677 1010 4095 - 2677 1006 4095 - 2677 1006 4095 - 2677 1006 4095 - 2677 1006 4095 - 2570 1182 2 - 2570 1182 115 - 2570 1182 235 - 2570 1182 362 - 2571 1183 495 - 2571 1183 632 - 2572 1183 771 - 2573 1183 910 - 2574 1183 1047 - 2575 1184 1184 - 2576 1184 1324 - 2578 1184 1480 - 2580 1185 1654 - 2583 1185 1849 - 2586 1186 2068 - 2590 1187 2317 - 2594 1188 2594 - 2600 1189 2898 - 2606 1190 3220 - 2614 1191 3560 - 2622 1192 3912 - 2632 1192 4078 - 2644 1193 4095 - 2656 1193 4095 - 2667 1190 4095 - 2675 1185 4095 - 2679 1177 4095 - 2678 1166 4095 - 2677 1156 4095 - 2677 1152 4095 - 2677 1152 4095 - 2677 1152 4095 - 2677 1152 4095 - 2583 1326 3 - 2583 1326 114 - 2583 1326 233 - 2584 1326 359 - 2584 1326 493 - 2584 1327 631 - 2585 1327 771 - 2586 1327 911 - 2587 1327 1049 - 2588 1327 1186 - 2589 1328 1328 - 2590 1328 1484 - 2592 1329 1660 - 2594 1329 1855 - 2597 1330 2076 - 2601 1331 2326 - 2605 1332 2605 - 2610 1333 2909 - 2615 1334 3230 - 2622 1335 3569 - 2630 1336 3916 - 2639 1337 4077 - 2650 1338 4095 - 2661 1338 4095 - 2670 1337 4095 - 2677 1332 4095 - 2679 1324 4095 - 2678 1313 4095 - 2677 1305 4095 - 2677 1303 4095 - 2677 1303 4095 - 2677 1303 4095 - 2677 1303 4095 - 2598 1487 2 - 2598 1487 112 - 2598 1487 229 - 2598 1487 356 - 2598 1487 490 - 2599 1487 630 - 2599 1487 771 - 2600 1488 912 - 2601 1488 1050 - 2601 1488 1189 - 2602 1488 1331 - 2604 1489 1489 - 2605 1489 1665 - 2607 1490 1862 - 2609 1491 2083 - 2612 1491 2335 - 2616 1492 2616 - 2620 1493 2921 - 2625 1495 3242 - 2631 1496 3578 - 2639 1498 3922 - 2647 1499 4075 - 2657 1501 4095 - 2666 1501 4095 - 2673 1499 4095 - 2678 1495 4095 - 2679 1487 4095 - 2678 1478 4095 - 2677 1471 4095 - 2677 1469 4095 - 2677 1469 4095 - 2677 1469 4095 - 2677 1469 4095 - 2613 1668 2 - 2613 1668 109 - 2613 1668 225 - 2613 1668 351 - 2613 1668 486 - 2614 1668 627 - 2614 1668 770 - 2615 1669 912 - 2615 1669 1051 - 2616 1669 1191 - 2617 1669 1334 - 2618 1670 1493 - 2619 1670 1670 - 2621 1671 1868 - 2623 1672 2091 - 2625 1672 2345 - 2628 1673 2628 - 2632 1675 2935 - 2637 1676 3255 - 2642 1678 3589 - 2649 1680 3927 - 2656 1681 4074 - 2664 1683 4095 - 2671 1683 4095 - 2676 1681 4095 - 2679 1676 4095 - 2679 1669 4095 - 2677 1661 4095 - 2677 1657 4095 - 2677 1656 4095 - 2677 1656 4095 - 2677 1656 4095 - 2677 1656 4095 - 2629 1872 3 - 2629 1872 105 - 2629 1872 219 - 2629 1872 345 - 2629 1872 480 - 2629 1873 622 - 2630 1873 767 - 2630 1873 911 - 2631 1873 1052 - 2631 1873 1192 - 2632 1874 1336 - 2633 1874 1496 - 2634 1875 1675 - 2635 1875 1875 - 2637 1876 2100 - 2639 1877 2357 - 2642 1878 2642 - 2646 1879 2950 - 2649 1881 3270 - 2654 1883 3600 - 2659 1885 3927 - 2665 1886 4072 - 2670 1887 4095 - 2675 1887 4095 - 2678 1884 4095 - 2679 1880 4095 - 2678 1874 4095 - 2677 1868 4095 - 2677 1865 4095 - 2677 1865 4095 - 2677 1865 4095 - 2677 1865 4095 - 2677 1865 4095 - 2646 2105 3 - 2646 2105 101 - 2646 2105 212 - 2646 2105 337 - 2646 2105 473 - 2647 2105 617 - 2647 2106 764 - 2647 2106 909 - 2648 2106 1051 - 2648 2106 1193 - 2649 2107 1338 - 2650 2107 1500 - 2651 2108 1680 - 2652 2108 1882 - 2653 2109 2109 - 2655 2110 2368 - 2657 2111 2657 - 2659 2112 2967 - 2662 2114 3285 - 2666 2115 3610 - 2669 2116 3921 - 2673 2117 4070 - 2676 2118 4095 - 2678 2117 4095 - 2679 2115 4095 - 2679 2111 4095 - 2677 2106 4095 - 2677 2102 4095 - 2677 2102 4095 - 2677 2102 4095 - 2677 2102 4095 - 2677 2102 4095 - 2677 2102 4095 - 2662 2374 1 - 2662 2374 94 - 2662 2374 201 - 2663 2374 325 - 2663 2375 462 - 2663 2375 608 - 2663 2375 758 - 2663 2375 905 - 2664 2375 1048 - 2664 2375 1191 - 2664 2376 1338 - 2665 2376 1501 - 2665 2376 1683 - 2666 2377 1886 - 2667 2378 2116 - 2668 2378 2378 - 2669 2379 2669 - 2671 2380 2980 - 2672 2381 3296 - 2674 2382 3614 - 2676 2383 3910 - 2677 2383 4067 - 2679 2383 4095 - 2679 2383 4095 - 2679 2381 4095 - 2678 2378 4095 - 2677 2376 4095 - 2677 2375 4095 - 2677 2375 4095 - 2677 2375 4095 - 2677 2375 4095 - 2677 2375 4095 - 2677 2375 4095 - 2674 2674 1 - 2674 2674 85 - 2674 2674 187 - 2674 2674 309 - 2674 2674 448 - 2674 2675 596 - 2674 2675 748 - 2675 2675 897 - 2675 2675 1042 - 2675 2675 1186 - 2675 2675 1334 - 2675 2675 1498 - 2676 2676 1681 - 2676 2676 1886 - 2676 2676 2118 - 2677 2677 2383 - 2677 2677 2677 - 2678 2678 2989 - 2678 2678 3301 - 2679 2679 3612 - 2679 2679 3895 - 2679 2679 4064 - 2679 2679 4095 - 2678 2678 4095 - 2677 2678 4095 - 2677 2677 4095 - 2677 2677 4095 - 2677 2677 4095 - 2677 2677 4095 - 2677 2677 4095 - 2677 2677 4095 - 2677 2677 4095 - 2677 2677 4095 - 2679 2991 3 - 2679 2991 73 - 2679 2991 167 - 2679 2991 289 - 2679 2991 428 - 2679 2991 579 - 2679 2991 734 - 2679 2991 885 - 2679 2991 1030 - 2679 2991 1175 - 2679 2991 1324 - 2679 2991 1489 - 2679 2991 1674 - 2679 2991 1880 - 2679 2991 2114 - 2679 2991 2382 - 2679 2991 2679 - 2679 2992 2992 - 2679 2992 3300 - 2679 2991 3603 - 2678 2991 3876 - 2678 2991 4061 - 2677 2991 4095 - 2677 2991 4095 - 2677 2991 4095 - 2677 2991 4095 - 2677 2991 4095 - 2677 2991 4095 - 2677 2991 4095 - 2677 2991 4095 - 2677 2991 4095 - 2677 2991 4095 - 2677 2991 4095 - 2678 3298 2 - 2678 3298 57 - 2678 3298 144 - 2678 3298 264 - 2678 3298 406 - 2678 3298 560 - 2678 3298 717 - 2678 3297 870 - 2678 3297 1017 - 2678 3297 1163 - 2678 3297 1312 - 2678 3297 1478 - 2678 3297 1664 - 2678 3297 1871 - 2677 3297 2106 - 2677 3297 2378 - 2677 3297 2677 - 2677 3296 2991 - 2677 3296 3296 - 2677 3296 3592 - 2677 3295 3859 - 2677 3295 4058 - 2677 3295 4095 - 2677 3295 4095 - 2677 3295 4095 - 2677 3295 4095 - 2677 3295 4095 - 2677 3295 4095 - 2677 3295 4095 - 2677 3295 4095 - 2677 3295 4095 - 2677 3295 4095 - 2677 3295 4095 - 2677 3588 1 - 2677 3588 40 - 2677 3588 123 - 2677 3588 245 - 2677 3588 389 - 2677 3588 545 - 2677 3588 705 - 2677 3588 860 - 2677 3588 1007 - 2677 3588 1153 - 2677 3588 1304 - 2677 3588 1470 - 2677 3588 1657 - 2677 3588 1865 - 2677 3588 2102 - 2677 3588 2375 - 2677 3588 2677 - 2677 3588 2991 - 2677 3588 3295 - 2677 3588 3588 - 2677 3588 3852 - 2677 3588 4057 - 2677 3588 4095 - 2677 3588 4095 - 2677 3588 4095 - 2677 3588 4095 - 2677 3588 4095 - 2677 3588 4095 - 2677 3588 4095 - 2677 3588 4095 - 2677 3588 4095 - 2677 3588 4095 - 2677 3588 4095 - 2677 3852 0 - 2677 3852 36 - 2677 3852 119 - 2677 3852 242 - 2677 3852 387 - 2677 3852 543 - 2677 3852 704 - 2677 3852 858 - 2677 3852 1006 - 2677 3852 1152 - 2677 3852 1303 - 2677 3852 1469 - 2677 3852 1656 - 2677 3852 1865 - 2677 3852 2102 - 2677 3852 2375 - 2677 3852 2677 - 2677 3852 2991 - 2677 3852 3295 - 2677 3852 3588 - 2677 3852 3852 - 2677 3852 4057 - 2677 3852 4095 - 2677 3852 4095 - 2677 3852 4095 - 2677 3852 4095 - 2677 3852 4095 - 2677 3852 4095 - 2677 3852 4095 - 2677 3852 4095 - 2677 3852 4095 - 2677 3852 4095 - 2677 3852 4095 - 2677 4057 0 - 2677 4057 36 - 2677 4057 119 - 2677 4057 242 - 2677 4057 387 - 2677 4057 543 - 2677 4057 704 - 2677 4057 858 - 2677 4057 1006 - 2677 4057 1152 - 2677 4057 1303 - 2677 4057 1469 - 2677 4057 1656 - 2677 4057 1865 - 2677 4057 2102 - 2677 4057 2375 - 2677 4057 2677 - 2677 4057 2991 - 2677 4057 3295 - 2677 4057 3588 - 2677 4057 3852 - 2677 4057 4057 - 2677 4057 4095 - 2677 4057 4095 - 2677 4057 4095 - 2677 4057 4095 - 2677 4057 4095 - 2677 4057 4095 - 2677 4057 4095 - 2677 4057 4095 - 2677 4057 4095 - 2677 4057 4095 - 2677 4057 4095 - 2677 4095 0 - 2677 4095 36 - 2677 4095 119 - 2677 4095 242 - 2677 4095 387 - 2677 4095 543 - 2677 4095 704 - 2677 4095 858 - 2677 4095 1006 - 2677 4095 1152 - 2677 4095 1303 - 2677 4095 1469 - 2677 4095 1656 - 2677 4095 1865 - 2677 4095 2102 - 2677 4095 2375 - 2677 4095 2677 - 2677 4095 2991 - 2677 4095 3295 - 2677 4095 3588 - 2677 4095 3852 - 2677 4095 4057 - 2677 4095 4095 - 2677 4095 4095 - 2677 4095 4095 - 2677 4095 4095 - 2677 4095 4095 - 2677 4095 4095 - 2677 4095 4095 - 2677 4095 4095 - 2677 4095 4095 - 2677 4095 4095 - 2677 4095 4095 - 2677 4095 0 - 2677 4095 36 - 2677 4095 119 - 2677 4095 242 - 2677 4095 387 - 2677 4095 543 - 2677 4095 704 - 2677 4095 858 - 2677 4095 1006 - 2677 4095 1152 - 2677 4095 1303 - 2677 4095 1469 - 2677 4095 1656 - 2677 4095 1865 - 2677 4095 2102 - 2677 4095 2375 - 2677 4095 2677 - 2677 4095 2991 - 2677 4095 3295 - 2677 4095 3588 - 2677 4095 3852 - 2677 4095 4057 - 2677 4095 4095 - 2677 4095 4095 - 2677 4095 4095 - 2677 4095 4095 - 2677 4095 4095 - 2677 4095 4095 - 2677 4095 4095 - 2677 4095 4095 - 2677 4095 4095 - 2677 4095 4095 - 2677 4095 4095 - 2677 4095 0 - 2677 4095 36 - 2677 4095 119 - 2677 4095 242 - 2677 4095 387 - 2677 4095 543 - 2677 4095 704 - 2677 4095 858 - 2677 4095 1006 - 2677 4095 1152 - 2677 4095 1303 - 2677 4095 1469 - 2677 4095 1656 - 2677 4095 1865 - 2677 4095 2102 - 2677 4095 2375 - 2677 4095 2677 - 2677 4095 2991 - 2677 4095 3295 - 2677 4095 3588 - 2677 4095 3852 - 2677 4095 4057 - 2677 4095 4095 - 2677 4095 4095 - 2677 4095 4095 - 2677 4095 4095 - 2677 4095 4095 - 2677 4095 4095 - 2677 4095 4095 - 2677 4095 4095 - 2677 4095 4095 - 2677 4095 4095 - 2677 4095 4095 - 2677 4095 0 - 2677 4095 36 - 2677 4095 119 - 2677 4095 242 - 2677 4095 387 - 2677 4095 543 - 2677 4095 704 - 2677 4095 858 - 2677 4095 1006 - 2677 4095 1152 - 2677 4095 1303 - 2677 4095 1469 - 2677 4095 1656 - 2677 4095 1865 - 2677 4095 2102 - 2677 4095 2375 - 2677 4095 2677 - 2677 4095 2991 - 2677 4095 3295 - 2677 4095 3588 - 2677 4095 3852 - 2677 4095 4057 - 2677 4095 4095 - 2677 4095 4095 - 2677 4095 4095 - 2677 4095 4095 - 2677 4095 4095 - 2677 4095 4095 - 2677 4095 4095 - 2677 4095 4095 - 2677 4095 4095 - 2677 4095 4095 - 2677 4095 4095 - 2677 4095 0 - 2677 4095 36 - 2677 4095 119 - 2677 4095 242 - 2677 4095 387 - 2677 4095 543 - 2677 4095 704 - 2677 4095 858 - 2677 4095 1006 - 2677 4095 1152 - 2677 4095 1303 - 2677 4095 1469 - 2677 4095 1656 - 2677 4095 1865 - 2677 4095 2102 - 2677 4095 2375 - 2677 4095 2677 - 2677 4095 2991 - 2677 4095 3295 - 2677 4095 3588 - 2677 4095 3852 - 2677 4095 4057 - 2677 4095 4095 - 2677 4095 4095 - 2677 4095 4095 - 2677 4095 4095 - 2677 4095 4095 - 2677 4095 4095 - 2677 4095 4095 - 2677 4095 4095 - 2677 4095 4095 - 2677 4095 4095 - 2677 4095 4095 - 2677 4095 0 - 2677 4095 36 - 2677 4095 119 - 2677 4095 242 - 2677 4095 387 - 2677 4095 543 - 2677 4095 704 - 2677 4095 858 - 2677 4095 1006 - 2677 4095 1152 - 2677 4095 1303 - 2677 4095 1469 - 2677 4095 1656 - 2677 4095 1865 - 2677 4095 2102 - 2677 4095 2375 - 2677 4095 2677 - 2677 4095 2991 - 2677 4095 3295 - 2677 4095 3588 - 2677 4095 3852 - 2677 4095 4057 - 2677 4095 4095 - 2677 4095 4095 - 2677 4095 4095 - 2677 4095 4095 - 2677 4095 4095 - 2677 4095 4095 - 2677 4095 4095 - 2677 4095 4095 - 2677 4095 4095 - 2677 4095 4095 - 2677 4095 4095 - 2677 4095 0 - 2677 4095 36 - 2677 4095 119 - 2677 4095 242 - 2677 4095 387 - 2677 4095 543 - 2677 4095 704 - 2677 4095 858 - 2677 4095 1006 - 2677 4095 1152 - 2677 4095 1303 - 2677 4095 1469 - 2677 4095 1656 - 2677 4095 1865 - 2677 4095 2102 - 2677 4095 2375 - 2677 4095 2677 - 2677 4095 2991 - 2677 4095 3295 - 2677 4095 3588 - 2677 4095 3852 - 2677 4095 4057 - 2677 4095 4095 - 2677 4095 4095 - 2677 4095 4095 - 2677 4095 4095 - 2677 4095 4095 - 2677 4095 4095 - 2677 4095 4095 - 2677 4095 4095 - 2677 4095 4095 - 2677 4095 4095 - 2677 4095 4095 - 2677 4095 0 - 2677 4095 36 - 2677 4095 119 - 2677 4095 242 - 2677 4095 387 - 2677 4095 543 - 2677 4095 704 - 2677 4095 858 - 2677 4095 1006 - 2677 4095 1152 - 2677 4095 1303 - 2677 4095 1469 - 2677 4095 1656 - 2677 4095 1865 - 2677 4095 2102 - 2677 4095 2375 - 2677 4095 2677 - 2677 4095 2991 - 2677 4095 3295 - 2677 4095 3588 - 2677 4095 3852 - 2677 4095 4057 - 2677 4095 4095 - 2677 4095 4095 - 2677 4095 4095 - 2677 4095 4095 - 2677 4095 4095 - 2677 4095 4095 - 2677 4095 4095 - 2677 4095 4095 - 2677 4095 4095 - 2677 4095 4095 - 2677 4095 4095 - 2677 4095 0 - 2677 4095 36 - 2677 4095 119 - 2677 4095 242 - 2677 4095 387 - 2677 4095 543 - 2677 4095 704 - 2677 4095 858 - 2677 4095 1006 - 2677 4095 1152 - 2677 4095 1303 - 2677 4095 1469 - 2677 4095 1656 - 2677 4095 1865 - 2677 4095 2102 - 2677 4095 2375 - 2677 4095 2677 - 2677 4095 2991 - 2677 4095 3295 - 2677 4095 3588 - 2677 4095 3852 - 2677 4095 4057 - 2677 4095 4095 - 2677 4095 4095 - 2677 4095 4095 - 2677 4095 4095 - 2677 4095 4095 - 2677 4095 4095 - 2677 4095 4095 - 2677 4095 4095 - 2677 4095 4095 - 2677 4095 4095 - 2677 4095 4095 - 2677 4095 0 - 2677 4095 36 - 2677 4095 119 - 2677 4095 242 - 2677 4095 387 - 2677 4095 543 - 2677 4095 704 - 2677 4095 858 - 2677 4095 1006 - 2677 4095 1152 - 2677 4095 1303 - 2677 4095 1469 - 2677 4095 1656 - 2677 4095 1865 - 2677 4095 2102 - 2677 4095 2375 - 2677 4095 2677 - 2677 4095 2991 - 2677 4095 3295 - 2677 4095 3588 - 2677 4095 3852 - 2677 4095 4057 - 2677 4095 4095 - 2677 4095 4095 - 2677 4095 4095 - 2677 4095 4095 - 2677 4095 4095 - 2677 4095 4095 - 2677 4095 4095 - 2677 4095 4095 - 2677 4095 4095 - 2677 4095 4095 - 2677 4095 4095 - 2677 4095 0 - 2677 4095 36 - 2677 4095 119 - 2677 4095 242 - 2677 4095 387 - 2677 4095 543 - 2677 4095 704 - 2677 4095 858 - 2677 4095 1006 - 2677 4095 1152 - 2677 4095 1303 - 2677 4095 1469 - 2677 4095 1656 - 2677 4095 1865 - 2677 4095 2102 - 2677 4095 2375 - 2677 4095 2677 - 2677 4095 2991 - 2677 4095 3295 - 2677 4095 3588 - 2677 4095 3852 - 2677 4095 4057 - 2677 4095 4095 - 2677 4095 4095 - 2677 4095 4095 - 2677 4095 4095 - 2677 4095 4095 - 2677 4095 4095 - 2677 4095 4095 - 2677 4095 4095 - 2677 4095 4095 - 2677 4095 4095 - 2677 4095 4095 - 2819 0 0 - 2819 3 118 - 2820 1 239 - 2820 0 365 - 2821 1 497 - 2822 1 631 - 2823 1 768 - 2824 1 904 - 2826 1 1039 - 2828 1 1174 - 2830 2 1312 - 2833 1 1466 - 2836 3 1638 - 2841 0 1830 - 2846 3 2046 - 2852 0 2291 - 2859 0 2566 - 2867 0 2867 - 2877 2 3191 - 2889 2 3537 - 2901 3 3898 - 2915 2 4080 - 2930 0 4095 - 2948 1 4095 - 2965 4 4095 - 2980 3 4095 - 2989 4 4095 - 2992 2 4095 - 2991 1 4095 - 2991 0 4095 - 2991 0 4095 - 2991 0 4095 - 2991 0 4095 - 2820 118 2 - 2820 118 118 - 2821 118 239 - 2821 118 365 - 2822 118 497 - 2823 117 632 - 2824 117 768 - 2825 117 904 - 2827 117 1039 - 2829 117 1174 - 2831 117 1312 - 2834 117 1466 - 2837 117 1638 - 2841 117 1830 - 2846 116 2047 - 2852 116 2292 - 2859 115 2566 - 2868 115 2868 - 2878 114 3191 - 2889 112 3537 - 2902 111 3898 - 2916 109 4080 - 2931 105 4095 - 2948 102 4095 - 2966 96 4095 - 2980 89 4095 - 2989 79 4095 - 2992 65 4095 - 2991 49 4095 - 2991 37 4095 - 2991 36 4095 - 2991 36 4095 - 2991 36 4095 - 2823 239 2 - 2823 239 118 - 2823 239 239 - 2824 239 365 - 2824 238 497 - 2825 238 632 - 2826 238 768 - 2828 238 904 - 2829 238 1039 - 2831 238 1174 - 2833 238 1313 - 2836 238 1467 - 2839 237 1639 - 2843 237 1832 - 2848 236 2048 - 2854 236 2293 - 2861 235 2568 - 2870 234 2870 - 2879 232 3193 - 2891 230 3538 - 2903 228 3899 - 2917 224 4080 - 2932 219 4095 - 2949 212 4095 - 2966 204 4095 - 2981 192 4095 - 2989 176 4095 - 2992 156 4095 - 2991 133 4095 - 2991 120 4095 - 2991 119 4095 - 2991 119 4095 - 2991 119 4095 - 2827 365 1 - 2827 365 117 - 2828 365 238 - 2828 365 365 - 2829 365 497 - 2830 365 632 - 2831 365 769 - 2832 365 905 - 2834 365 1040 - 2835 365 1176 - 2838 364 1314 - 2840 364 1468 - 2843 364 1641 - 2847 364 1834 - 2852 363 2050 - 2858 362 2296 - 2865 362 2571 - 2873 360 2873 - 2882 359 3196 - 2893 357 3541 - 2905 354 3900 - 2919 350 4080 - 2933 344 4095 - 2950 337 4095 - 2967 328 4095 - 2981 315 4095 - 2990 297 4095 - 2992 276 4095 - 2991 254 4095 - 2991 242 4095 - 2991 242 4095 - 2991 242 4095 - 2991 242 4095 - 2834 497 3 - 2834 497 117 - 2834 497 238 - 2834 497 365 - 2835 497 496 - 2836 497 632 - 2837 496 769 - 2838 496 906 - 2840 496 1041 - 2842 496 1177 - 2843 496 1316 - 2846 496 1471 - 2849 496 1643 - 2853 496 1836 - 2857 495 2053 - 2863 495 2300 - 2869 494 2575 - 2877 493 2877 - 2886 492 3200 - 2897 490 3544 - 2908 488 3902 - 2921 484 4079 - 2936 479 4095 - 2952 473 4095 - 2969 464 4095 - 2982 452 4095 - 2990 435 4095 - 2992 415 4095 - 2991 396 4095 - 2991 387 4095 - 2991 387 4095 - 2991 387 4095 - 2991 387 4095 - 2842 632 2 - 2842 632 117 - 2842 632 237 - 2843 632 364 - 2843 632 496 - 2844 632 632 - 2845 632 770 - 2846 632 907 - 2848 632 1043 - 2849 632 1179 - 2851 632 1318 - 2853 632 1473 - 2856 632 1646 - 2860 632 1840 - 2864 632 2058 - 2869 632 2304 - 2875 632 2580 - 2883 631 2883 - 2891 630 3205 - 2901 629 3549 - 2912 627 3905 - 2925 624 4079 - 2939 621 4095 - 2955 616 4095 - 2971 608 4095 - 2983 598 4095 - 2990 584 4095 - 2992 567 4095 - 2991 551 4095 - 2991 543 4095 - 2991 543 4095 - 2991 543 4095 - 2991 543 4095 - 2851 771 0 - 2852 771 116 - 2852 771 236 - 2852 771 363 - 2853 771 496 - 2853 771 632 - 2854 771 771 - 2855 771 908 - 2857 771 1045 - 2858 771 1181 - 2860 771 1321 - 2862 771 1476 - 2865 771 1650 - 2868 771 1844 - 2872 771 2062 - 2877 772 2310 - 2883 772 2587 - 2889 772 2889 - 2898 771 3212 - 2907 771 3554 - 2917 770 3908 - 2929 768 4078 - 2943 766 4095 - 2958 762 4095 - 2973 757 4095 - 2985 749 4095 - 2991 737 4095 - 2991 722 4095 - 2991 709 4095 - 2991 704 4095 - 2991 704 4095 - 2991 704 4095 - 2991 704 4095 - 2862 909 2 - 2862 909 115 - 2862 909 235 - 2863 909 362 - 2863 909 495 - 2864 909 632 - 2865 910 771 - 2866 910 910 - 2867 910 1046 - 2868 910 1183 - 2870 910 1324 - 2872 910 1480 - 2874 911 1654 - 2877 911 1849 - 2881 911 2068 - 2885 911 2316 - 2891 912 2594 - 2897 912 2897 - 2905 912 3219 - 2913 912 3560 - 2923 912 3911 - 2934 911 4078 - 2948 910 4095 - 2962 907 4095 - 2976 903 4095 - 2986 896 4095 - 2991 886 4095 - 2991 874 4095 - 2991 862 4095 - 2991 858 4095 - 2991 858 4095 - 2991 858 4095 - 2991 858 4095 - 2874 1048 3 - 2874 1048 114 - 2874 1048 233 - 2874 1048 360 - 2875 1048 494 - 2875 1048 631 - 2876 1048 771 - 2877 1048 911 - 2878 1048 1048 - 2879 1048 1186 - 2881 1049 1327 - 2882 1049 1483 - 2885 1049 1658 - 2887 1049 1854 - 2891 1050 2073 - 2895 1050 2323 - 2900 1051 2601 - 2905 1051 2905 - 2912 1051 3227 - 2920 1052 3566 - 2929 1052 3915 - 2940 1052 4077 - 2953 1051 4095 - 2966 1049 4095 - 2979 1046 4095 - 2987 1040 4095 - 2991 1030 4095 - 2991 1019 4095 - 2991 1009 4095 - 2991 1006 4095 - 2991 1006 4095 - 2991 1006 4095 - 2991 1006 4095 - 2886 1187 3 - 2886 1187 113 - 2886 1187 231 - 2886 1187 358 - 2887 1187 492 - 2887 1187 631 - 2888 1187 771 - 2889 1187 911 - 2890 1188 1050 - 2891 1188 1188 - 2892 1188 1329 - 2894 1188 1486 - 2895 1189 1662 - 2898 1189 1858 - 2901 1189 2079 - 2904 1190 2330 - 2909 1190 2610 - 2914 1191 2914 - 2920 1191 3235 - 2928 1192 3573 - 2937 1192 3919 - 2947 1193 4076 - 2959 1193 4095 - 2971 1192 4095 - 2981 1188 4095 - 2989 1183 4095 - 2991 1174 4095 - 2991 1163 4095 - 2991 1154 4095 - 2991 1152 4095 - 2991 1152 4095 - 2991 1152 4095 - 2991 1152 4095 - 2898 1331 2 - 2898 1331 111 - 2898 1331 229 - 2899 1331 355 - 2899 1331 490 - 2899 1331 629 - 2900 1331 771 - 2901 1331 912 - 2902 1331 1051 - 2903 1332 1189 - 2904 1332 1332 - 2905 1332 1490 - 2907 1332 1666 - 2909 1333 1863 - 2912 1333 2085 - 2915 1334 2337 - 2919 1334 2618 - 2923 1335 2923 - 2929 1336 3244 - 2936 1337 3580 - 2945 1337 3923 - 2954 1338 4075 - 2965 1339 4095 - 2975 1338 4095 - 2984 1335 4095 - 2990 1329 4095 - 2992 1321 4095 - 2991 1311 4095 - 2991 1304 4095 - 2991 1303 4095 - 2991 1303 4095 - 2991 1303 4095 - 2991 1303 4095 - 2912 1491 3 - 2912 1491 109 - 2912 1491 225 - 2912 1491 352 - 2912 1492 486 - 2913 1492 627 - 2913 1492 770 - 2914 1492 912 - 2915 1492 1051 - 2916 1492 1191 - 2916 1492 1334 - 2918 1493 1493 - 2919 1493 1670 - 2921 1493 1868 - 2923 1494 2091 - 2926 1495 2345 - 2930 1495 2628 - 2934 1496 2934 - 2940 1497 3255 - 2946 1498 3589 - 2954 1500 3927 - 2962 1501 4074 - 2971 1501 4095 - 2980 1500 4095 - 2987 1497 4095 - 2991 1492 4095 - 2992 1484 4095 - 2991 1475 4095 - 2991 1470 4095 - 2991 1469 4095 - 2991 1469 4095 - 2991 1469 4095 - 2991 1469 4095 - 2927 1672 3 - 2927 1672 106 - 2927 1672 221 - 2927 1672 347 - 2927 1672 482 - 2927 1673 624 - 2928 1673 768 - 2928 1673 911 - 2929 1673 1052 - 2930 1673 1192 - 2931 1673 1336 - 2932 1674 1495 - 2933 1674 1674 - 2935 1675 1873 - 2937 1675 2098 - 2940 1676 2354 - 2943 1677 2639 - 2947 1678 2947 - 2952 1679 3267 - 2957 1680 3598 - 2964 1682 3928 - 2971 1683 4072 - 2978 1683 4095 - 2984 1682 4095 - 2989 1679 4095 - 2991 1674 4095 - 2991 1667 4095 - 2991 1660 4095 - 2991 1656 4095 - 2991 1656 4095 - 2991 1656 4095 - 2991 1656 4095 - 2991 1656 4095 - 2943 1877 3 - 2943 1877 103 - 2943 1877 215 - 2943 1877 340 - 2944 1877 476 - 2944 1877 619 - 2944 1877 765 - 2945 1878 910 - 2945 1878 1051 - 2946 1878 1193 - 2947 1878 1338 - 2948 1879 1498 - 2949 1879 1678 - 2951 1880 1879 - 2952 1880 2106 - 2955 1881 2364 - 2957 1882 2651 - 2961 1883 2961 - 2965 1884 3279 - 2969 1885 3607 - 2974 1886 3924 - 2979 1887 4070 - 2984 1887 4095 - 2988 1886 4095 - 2991 1883 4095 - 2992 1878 4095 - 2991 1872 4095 - 2991 1867 4095 - 2991 1865 4095 - 2991 1865 4095 - 2991 1865 4095 - 2991 1865 4095 - 2991 1865 4095 - 2961 2110 0 - 2961 2110 98 - 2961 2110 207 - 2961 2110 331 - 2962 2110 468 - 2962 2110 613 - 2962 2110 761 - 2962 2111 907 - 2963 2111 1050 - 2963 2111 1192 - 2964 2111 1339 - 2965 2111 1501 - 2966 2112 1682 - 2967 2112 1885 - 2968 2113 2113 - 2970 2114 2374 - 2972 2114 2664 - 2974 2115 2974 - 2977 2116 3291 - 2980 2117 3613 - 2983 2118 3916 - 2986 2118 4068 - 2989 2117 4095 - 2991 2116 4095 - 2992 2113 4095 - 2991 2109 4095 - 2991 2105 4095 - 2991 2102 4095 - 2991 2102 4095 - 2991 2102 4095 - 2991 2102 4095 - 2991 2102 4095 - 2991 2102 4095 - 2977 2378 2 - 2977 2378 91 - 2977 2378 196 - 2977 2378 319 - 2977 2378 457 - 2977 2378 604 - 2977 2379 754 - 2978 2379 902 - 2978 2379 1046 - 2978 2379 1190 - 2979 2379 1337 - 2979 2379 1500 - 2980 2380 1683 - 2980 2380 1887 - 2981 2380 2117 - 2982 2381 2381 - 2983 2381 2673 - 2984 2382 2984 - 2986 2383 3299 - 2987 2383 3614 - 2989 2383 3905 - 2990 2383 4066 - 2991 2383 4095 - 2992 2382 4095 - 2991 2380 4095 - 2991 2377 4095 - 2991 2376 4095 - 2991 2375 4095 - 2991 2375 4095 - 2991 2375 4095 - 2991 2375 4095 - 2991 2375 4095 - 2991 2375 4095 - 2988 2677 3 - 2988 2677 82 - 2988 2677 181 - 2988 2677 303 - 2988 2677 442 - 2988 2677 591 - 2988 2677 744 - 2988 2677 893 - 2988 2677 1038 - 2988 2677 1183 - 2988 2677 1331 - 2988 2677 1496 - 2989 2677 1679 - 2989 2678 1885 - 2989 2678 2117 - 2990 2678 2383 - 2990 2678 2678 - 2990 2679 2990 - 2991 2679 3301 - 2991 2679 3609 - 2991 2679 3889 - 2992 2679 4063 - 2991 2678 4095 - 2991 2678 4095 - 2991 2677 4095 - 2991 2677 4095 - 2991 2677 4095 - 2991 2677 4095 - 2991 2677 4095 - 2991 2677 4095 - 2991 2677 4095 - 2991 2677 4095 - 2991 2677 4095 - 2991 2991 2 - 2991 2991 69 - 2991 2991 162 - 2991 2991 283 - 2991 2991 423 - 2991 2991 574 - 2991 2991 730 - 2991 2991 881 - 2991 2991 1027 - 2991 2991 1172 - 2992 2991 1321 - 2992 2991 1487 - 2992 2991 1671 - 2992 2992 1878 - 2992 2992 2112 - 2992 2992 2381 - 2992 2991 2679 - 2991 2991 2992 - 2991 2991 3299 - 2991 2991 3600 - 2991 2991 3871 - 2991 2991 4060 - 2991 2991 4095 - 2991 2991 4095 - 2991 2991 4095 - 2991 2991 4095 - 2991 2991 4095 - 2991 2991 4095 - 2991 2991 4095 - 2991 2991 4095 - 2991 2991 4095 - 2991 2991 4095 - 2991 2991 4095 - 2991 3297 2 - 2991 3297 53 - 2991 3297 139 - 2991 3297 260 - 2991 3297 402 - 2991 3297 556 - 2991 3297 714 - 2991 3297 868 - 2991 3297 1014 - 2991 3297 1160 - 2991 3297 1310 - 2991 3296 1476 - 2991 3296 1662 - 2991 3296 1870 - 2991 3296 2105 - 2991 3296 2377 - 2991 3296 2677 - 2991 3296 2991 - 2991 3296 3296 - 2991 3295 3590 - 2991 3295 3856 - 2991 3295 4058 - 2991 3295 4095 - 2991 3295 4095 - 2991 3295 4095 - 2991 3295 4095 - 2991 3295 4095 - 2991 3295 4095 - 2991 3295 4095 - 2991 3295 4095 - 2991 3295 4095 - 2991 3295 4095 - 2991 3295 4095 - 2991 3588 1 - 2991 3588 38 - 2991 3588 121 - 2991 3588 243 - 2991 3588 388 - 2991 3588 544 - 2991 3588 704 - 2991 3588 859 - 2991 3588 1006 - 2991 3588 1153 - 2991 3588 1303 - 2991 3588 1470 - 2991 3588 1656 - 2991 3588 1865 - 2991 3588 2102 - 2991 3588 2375 - 2991 3588 2677 - 2991 3588 2991 - 2991 3588 3295 - 2991 3588 3588 - 2991 3588 3852 - 2991 3588 4057 - 2991 3588 4095 - 2991 3588 4095 - 2991 3588 4095 - 2991 3588 4095 - 2991 3588 4095 - 2991 3588 4095 - 2991 3588 4095 - 2991 3588 4095 - 2991 3588 4095 - 2991 3588 4095 - 2991 3588 4095 - 2991 3852 0 - 2991 3852 36 - 2991 3852 119 - 2991 3852 242 - 2991 3852 387 - 2991 3852 543 - 2991 3852 704 - 2991 3852 858 - 2991 3852 1006 - 2991 3852 1152 - 2991 3852 1303 - 2991 3852 1469 - 2991 3852 1656 - 2991 3852 1865 - 2991 3852 2102 - 2991 3852 2375 - 2991 3852 2677 - 2991 3852 2991 - 2991 3852 3295 - 2991 3852 3588 - 2991 3852 3852 - 2991 3852 4057 - 2991 3852 4095 - 2991 3852 4095 - 2991 3852 4095 - 2991 3852 4095 - 2991 3852 4095 - 2991 3852 4095 - 2991 3852 4095 - 2991 3852 4095 - 2991 3852 4095 - 2991 3852 4095 - 2991 3852 4095 - 2991 4057 0 - 2991 4057 36 - 2991 4057 119 - 2991 4057 242 - 2991 4057 387 - 2991 4057 543 - 2991 4057 704 - 2991 4057 858 - 2991 4057 1006 - 2991 4057 1152 - 2991 4057 1303 - 2991 4057 1469 - 2991 4057 1656 - 2991 4057 1865 - 2991 4057 2102 - 2991 4057 2375 - 2991 4057 2677 - 2991 4057 2991 - 2991 4057 3295 - 2991 4057 3588 - 2991 4057 3852 - 2991 4057 4057 - 2991 4057 4095 - 2991 4057 4095 - 2991 4057 4095 - 2991 4057 4095 - 2991 4057 4095 - 2991 4057 4095 - 2991 4057 4095 - 2991 4057 4095 - 2991 4057 4095 - 2991 4057 4095 - 2991 4057 4095 - 2991 4095 0 - 2991 4095 36 - 2991 4095 119 - 2991 4095 242 - 2991 4095 387 - 2991 4095 543 - 2991 4095 704 - 2991 4095 858 - 2991 4095 1006 - 2991 4095 1152 - 2991 4095 1303 - 2991 4095 1469 - 2991 4095 1656 - 2991 4095 1865 - 2991 4095 2102 - 2991 4095 2375 - 2991 4095 2677 - 2991 4095 2991 - 2991 4095 3295 - 2991 4095 3588 - 2991 4095 3852 - 2991 4095 4057 - 2991 4095 4095 - 2991 4095 4095 - 2991 4095 4095 - 2991 4095 4095 - 2991 4095 4095 - 2991 4095 4095 - 2991 4095 4095 - 2991 4095 4095 - 2991 4095 4095 - 2991 4095 4095 - 2991 4095 4095 - 2991 4095 0 - 2991 4095 36 - 2991 4095 119 - 2991 4095 242 - 2991 4095 387 - 2991 4095 543 - 2991 4095 704 - 2991 4095 858 - 2991 4095 1006 - 2991 4095 1152 - 2991 4095 1303 - 2991 4095 1469 - 2991 4095 1656 - 2991 4095 1865 - 2991 4095 2102 - 2991 4095 2375 - 2991 4095 2677 - 2991 4095 2991 - 2991 4095 3295 - 2991 4095 3588 - 2991 4095 3852 - 2991 4095 4057 - 2991 4095 4095 - 2991 4095 4095 - 2991 4095 4095 - 2991 4095 4095 - 2991 4095 4095 - 2991 4095 4095 - 2991 4095 4095 - 2991 4095 4095 - 2991 4095 4095 - 2991 4095 4095 - 2991 4095 4095 - 2991 4095 0 - 2991 4095 36 - 2991 4095 119 - 2991 4095 242 - 2991 4095 387 - 2991 4095 543 - 2991 4095 704 - 2991 4095 858 - 2991 4095 1006 - 2991 4095 1152 - 2991 4095 1303 - 2991 4095 1469 - 2991 4095 1656 - 2991 4095 1865 - 2991 4095 2102 - 2991 4095 2375 - 2991 4095 2677 - 2991 4095 2991 - 2991 4095 3295 - 2991 4095 3588 - 2991 4095 3852 - 2991 4095 4057 - 2991 4095 4095 - 2991 4095 4095 - 2991 4095 4095 - 2991 4095 4095 - 2991 4095 4095 - 2991 4095 4095 - 2991 4095 4095 - 2991 4095 4095 - 2991 4095 4095 - 2991 4095 4095 - 2991 4095 4095 - 2991 4095 0 - 2991 4095 36 - 2991 4095 119 - 2991 4095 242 - 2991 4095 387 - 2991 4095 543 - 2991 4095 704 - 2991 4095 858 - 2991 4095 1006 - 2991 4095 1152 - 2991 4095 1303 - 2991 4095 1469 - 2991 4095 1656 - 2991 4095 1865 - 2991 4095 2102 - 2991 4095 2375 - 2991 4095 2677 - 2991 4095 2991 - 2991 4095 3295 - 2991 4095 3588 - 2991 4095 3852 - 2991 4095 4057 - 2991 4095 4095 - 2991 4095 4095 - 2991 4095 4095 - 2991 4095 4095 - 2991 4095 4095 - 2991 4095 4095 - 2991 4095 4095 - 2991 4095 4095 - 2991 4095 4095 - 2991 4095 4095 - 2991 4095 4095 - 2991 4095 0 - 2991 4095 36 - 2991 4095 119 - 2991 4095 242 - 2991 4095 387 - 2991 4095 543 - 2991 4095 704 - 2991 4095 858 - 2991 4095 1006 - 2991 4095 1152 - 2991 4095 1303 - 2991 4095 1469 - 2991 4095 1656 - 2991 4095 1865 - 2991 4095 2102 - 2991 4095 2375 - 2991 4095 2677 - 2991 4095 2991 - 2991 4095 3295 - 2991 4095 3588 - 2991 4095 3852 - 2991 4095 4057 - 2991 4095 4095 - 2991 4095 4095 - 2991 4095 4095 - 2991 4095 4095 - 2991 4095 4095 - 2991 4095 4095 - 2991 4095 4095 - 2991 4095 4095 - 2991 4095 4095 - 2991 4095 4095 - 2991 4095 4095 - 2991 4095 0 - 2991 4095 36 - 2991 4095 119 - 2991 4095 242 - 2991 4095 387 - 2991 4095 543 - 2991 4095 704 - 2991 4095 858 - 2991 4095 1006 - 2991 4095 1152 - 2991 4095 1303 - 2991 4095 1469 - 2991 4095 1656 - 2991 4095 1865 - 2991 4095 2102 - 2991 4095 2375 - 2991 4095 2677 - 2991 4095 2991 - 2991 4095 3295 - 2991 4095 3588 - 2991 4095 3852 - 2991 4095 4057 - 2991 4095 4095 - 2991 4095 4095 - 2991 4095 4095 - 2991 4095 4095 - 2991 4095 4095 - 2991 4095 4095 - 2991 4095 4095 - 2991 4095 4095 - 2991 4095 4095 - 2991 4095 4095 - 2991 4095 4095 - 2991 4095 0 - 2991 4095 36 - 2991 4095 119 - 2991 4095 242 - 2991 4095 387 - 2991 4095 543 - 2991 4095 704 - 2991 4095 858 - 2991 4095 1006 - 2991 4095 1152 - 2991 4095 1303 - 2991 4095 1469 - 2991 4095 1656 - 2991 4095 1865 - 2991 4095 2102 - 2991 4095 2375 - 2991 4095 2677 - 2991 4095 2991 - 2991 4095 3295 - 2991 4095 3588 - 2991 4095 3852 - 2991 4095 4057 - 2991 4095 4095 - 2991 4095 4095 - 2991 4095 4095 - 2991 4095 4095 - 2991 4095 4095 - 2991 4095 4095 - 2991 4095 4095 - 2991 4095 4095 - 2991 4095 4095 - 2991 4095 4095 - 2991 4095 4095 - 2991 4095 0 - 2991 4095 36 - 2991 4095 119 - 2991 4095 242 - 2991 4095 387 - 2991 4095 543 - 2991 4095 704 - 2991 4095 858 - 2991 4095 1006 - 2991 4095 1152 - 2991 4095 1303 - 2991 4095 1469 - 2991 4095 1656 - 2991 4095 1865 - 2991 4095 2102 - 2991 4095 2375 - 2991 4095 2677 - 2991 4095 2991 - 2991 4095 3295 - 2991 4095 3588 - 2991 4095 3852 - 2991 4095 4057 - 2991 4095 4095 - 2991 4095 4095 - 2991 4095 4095 - 2991 4095 4095 - 2991 4095 4095 - 2991 4095 4095 - 2991 4095 4095 - 2991 4095 4095 - 2991 4095 4095 - 2991 4095 4095 - 2991 4095 4095 - 2991 4095 0 - 2991 4095 36 - 2991 4095 119 - 2991 4095 242 - 2991 4095 387 - 2991 4095 543 - 2991 4095 704 - 2991 4095 858 - 2991 4095 1006 - 2991 4095 1152 - 2991 4095 1303 - 2991 4095 1469 - 2991 4095 1656 - 2991 4095 1865 - 2991 4095 2102 - 2991 4095 2375 - 2991 4095 2677 - 2991 4095 2991 - 2991 4095 3295 - 2991 4095 3588 - 2991 4095 3852 - 2991 4095 4057 - 2991 4095 4095 - 2991 4095 4095 - 2991 4095 4095 - 2991 4095 4095 - 2991 4095 4095 - 2991 4095 4095 - 2991 4095 4095 - 2991 4095 4095 - 2991 4095 4095 - 2991 4095 4095 - 2991 4095 4095 - 2991 4095 0 - 2991 4095 36 - 2991 4095 119 - 2991 4095 242 - 2991 4095 387 - 2991 4095 543 - 2991 4095 704 - 2991 4095 858 - 2991 4095 1006 - 2991 4095 1152 - 2991 4095 1303 - 2991 4095 1469 - 2991 4095 1656 - 2991 4095 1865 - 2991 4095 2102 - 2991 4095 2375 - 2991 4095 2677 - 2991 4095 2991 - 2991 4095 3295 - 2991 4095 3588 - 2991 4095 3852 - 2991 4095 4057 - 2991 4095 4095 - 2991 4095 4095 - 2991 4095 4095 - 2991 4095 4095 - 2991 4095 4095 - 2991 4095 4095 - 2991 4095 4095 - 2991 4095 4095 - 2991 4095 4095 - 2991 4095 4095 - 2991 4095 4095 - 2991 4095 0 - 2991 4095 36 - 2991 4095 119 - 2991 4095 242 - 2991 4095 387 - 2991 4095 543 - 2991 4095 704 - 2991 4095 858 - 2991 4095 1006 - 2991 4095 1152 - 2991 4095 1303 - 2991 4095 1469 - 2991 4095 1656 - 2991 4095 1865 - 2991 4095 2102 - 2991 4095 2375 - 2991 4095 2677 - 2991 4095 2991 - 2991 4095 3295 - 2991 4095 3588 - 2991 4095 3852 - 2991 4095 4057 - 2991 4095 4095 - 2991 4095 4095 - 2991 4095 4095 - 2991 4095 4095 - 2991 4095 4095 - 2991 4095 4095 - 2991 4095 4095 - 2991 4095 4095 - 2991 4095 4095 - 2991 4095 4095 - 2991 4095 4095 - 3171 3 2 - 3171 3 115 - 3171 3 235 - 3172 2 362 - 3172 2 495 - 3173 3 632 - 3174 2 771 - 3175 1 909 - 3176 2 1046 - 3178 3 1183 - 3179 3 1323 - 3181 2 1479 - 3184 3 1652 - 3187 3 1847 - 3191 3 2066 - 3196 2 2314 - 3202 4 2591 - 3209 3 2894 - 3216 2 3216 - 3226 3 3558 - 3236 3 3910 - 3247 2 4078 - 3261 3 4095 - 3276 1 4095 - 3289 2 4095 - 3298 3 4095 - 3301 3 4095 - 3299 3 4095 - 3295 2 4095 - 3295 0 4095 - 3295 0 4095 - 3295 0 4095 - 3295 0 4095 - 3171 115 2 - 3172 115 115 - 3172 115 235 - 3172 115 362 - 3173 115 495 - 3173 115 632 - 3174 115 771 - 3175 115 909 - 3177 115 1046 - 3178 115 1183 - 3180 115 1323 - 3182 115 1479 - 3185 114 1653 - 3188 114 1847 - 3192 114 2066 - 3196 113 2314 - 3202 113 2592 - 3209 112 2895 - 3217 111 3217 - 3226 109 3558 - 3236 108 3910 - 3248 105 4078 - 3261 102 4095 - 3276 98 4095 - 3289 92 4095 - 3298 85 4095 - 3301 74 4095 - 3299 60 4095 - 3295 44 4095 - 3295 36 4095 - 3295 36 4095 - 3295 36 4095 - 3295 36 4095 - 3173 235 1 - 3174 235 115 - 3174 235 235 - 3174 235 362 - 3175 235 495 - 3175 235 632 - 3176 235 771 - 3177 235 909 - 3179 234 1046 - 3180 234 1183 - 3182 234 1323 - 3184 234 1479 - 3186 233 1653 - 3189 233 1848 - 3193 232 2067 - 3198 232 2315 - 3204 231 2593 - 3210 229 2896 - 3218 227 3218 - 3227 225 3559 - 3237 222 3911 - 3249 218 4078 - 3262 213 4095 - 3277 206 4095 - 3290 197 4095 - 3299 185 4095 - 3301 169 4095 - 3299 149 4095 - 3295 128 4095 - 3295 119 4095 - 3295 119 4095 - 3295 119 4095 - 3295 119 4095 - 3177 362 3 - 3177 362 115 - 3177 362 235 - 3178 362 362 - 3178 362 495 - 3179 361 632 - 3180 361 771 - 3181 361 910 - 3182 361 1047 - 3183 361 1184 - 3185 361 1324 - 3187 360 1480 - 3189 360 1655 - 3193 359 1850 - 3196 359 2069 - 3201 358 2317 - 3206 357 2595 - 3213 355 2898 - 3220 354 3220 - 3229 351 3561 - 3239 348 3912 - 3250 343 4078 - 3264 338 4095 - 3278 330 4095 - 3290 320 4095 - 3299 307 4095 - 3301 289 4095 - 3299 269 4095 - 3295 249 4095 - 3295 242 4095 - 3295 242 4095 - 3295 242 4095 - 3295 242 4095 - 3182 494 2 - 3182 494 115 - 3182 494 234 - 3183 494 361 - 3183 494 494 - 3184 494 632 - 3185 494 771 - 3186 494 910 - 3187 494 1047 - 3188 494 1185 - 3190 493 1325 - 3191 493 1482 - 3194 493 1656 - 3197 492 1852 - 3200 492 2071 - 3205 491 2320 - 3210 490 2598 - 3216 489 2902 - 3224 487 3224 - 3232 485 3563 - 3241 482 3913 - 3253 478 4077 - 3266 473 4095 - 3279 466 4095 - 3291 457 4095 - 3299 444 4095 - 3301 428 4095 - 3298 409 4095 - 3295 392 4095 - 3295 387 4095 - 3295 387 4095 - 3295 387 4095 - 3295 387 4095 - 3188 632 2 - 3188 632 114 - 3189 632 233 - 3189 632 360 - 3189 632 493 - 3190 631 631 - 3191 631 771 - 3192 631 911 - 3193 631 1048 - 3194 631 1186 - 3195 631 1327 - 3197 631 1483 - 3200 631 1658 - 3202 631 1854 - 3206 630 2074 - 3210 630 2324 - 3215 629 2602 - 3221 628 2906 - 3228 627 3228 - 3236 625 3567 - 3245 623 3915 - 3256 620 4077 - 3269 616 4095 - 3282 611 4095 - 3293 603 4095 - 3300 592 4095 - 3301 578 4095 - 3298 561 4095 - 3295 548 4095 - 3295 543 4095 - 3295 543 4095 - 3295 543 4095 - 3295 543 4095 - 3196 772 2 - 3196 772 113 - 3196 772 232 - 3196 772 359 - 3197 772 492 - 3197 772 631 - 3198 772 771 - 3199 772 911 - 3200 772 1049 - 3201 772 1187 - 3203 772 1329 - 3204 771 1485 - 3206 771 1661 - 3209 771 1857 - 3212 771 2077 - 3216 771 2328 - 3221 771 2607 - 3226 770 2911 - 3233 770 3233 - 3240 768 3571 - 3249 767 3917 - 3260 765 4076 - 3272 762 4095 - 3284 758 4095 - 3294 752 4095 - 3300 743 4095 - 3301 731 4095 - 3298 718 4095 - 3295 707 4095 - 3295 704 4095 - 3295 704 4095 - 3295 704 4095 - 3295 704 4095 - 3204 912 2 - 3204 912 112 - 3205 912 230 - 3205 912 357 - 3205 912 491 - 3206 912 630 - 3206 912 771 - 3207 912 912 - 3208 912 1050 - 3209 912 1188 - 3210 912 1330 - 3212 912 1488 - 3214 912 1663 - 3216 912 1860 - 3219 912 2081 - 3223 912 2333 - 3227 912 2613 - 3232 912 2917 - 3238 911 3238 - 3246 911 3575 - 3254 910 3920 - 3265 909 4076 - 3276 908 4095 - 3287 905 4095 - 3296 900 4095 - 3301 892 4095 - 3301 881 4095 - 3297 870 4095 - 3295 860 4095 - 3295 858 4095 - 3295 858 4095 - 3295 858 4095 - 3295 858 4095 - 3214 1051 1 - 3214 1051 111 - 3214 1051 228 - 3214 1051 355 - 3214 1051 489 - 3215 1051 629 - 3215 1051 771 - 3216 1051 912 - 3217 1051 1051 - 3218 1051 1190 - 3219 1051 1332 - 3220 1051 1490 - 3222 1051 1666 - 3224 1051 1864 - 3227 1051 2085 - 3230 1052 2338 - 3234 1052 2619 - 3239 1052 2924 - 3245 1052 3245 - 3252 1052 3581 - 3260 1051 3923 - 3270 1051 4075 - 3280 1050 4095 - 3290 1047 4095 - 3297 1043 4095 - 3301 1036 4095 - 3300 1026 4095 - 3297 1015 4095 - 3295 1007 4095 - 3295 1006 4095 - 3295 1006 4095 - 3295 1006 4095 - 3295 1006 4095 - 3223 1190 0 - 3223 1190 110 - 3223 1190 226 - 3224 1190 353 - 3224 1190 487 - 3224 1190 627 - 3225 1190 770 - 3225 1191 912 - 3226 1191 1051 - 3227 1191 1191 - 3228 1191 1333 - 3229 1191 1492 - 3231 1191 1669 - 3233 1191 1867 - 3235 1191 2090 - 3238 1192 2343 - 3242 1192 2625 - 3246 1192 2931 - 3252 1192 3252 - 3259 1193 3587 - 3267 1193 3926 - 3275 1193 4074 - 3284 1192 4095 - 3293 1190 4095 - 3299 1185 4095 - 3301 1179 4095 - 3300 1170 4095 - 3297 1160 4095 - 3295 1153 4095 - 3295 1152 4095 - 3295 1152 4095 - 3295 1152 4095 - 3295 1152 4095 - 3233 1334 1 - 3233 1334 108 - 3233 1334 223 - 3233 1334 350 - 3234 1334 484 - 3234 1334 625 - 3235 1334 769 - 3235 1335 912 - 3236 1335 1052 - 3237 1335 1191 - 3238 1335 1335 - 3239 1335 1494 - 3240 1335 1672 - 3242 1335 1871 - 3244 1336 2094 - 3247 1336 2349 - 3250 1336 2633 - 3255 1337 2940 - 3260 1338 3260 - 3266 1338 3593 - 3273 1338 3928 - 3281 1339 4073 - 3289 1338 4095 - 3295 1336 4095 - 3300 1332 4095 - 3301 1325 4095 - 3299 1317 4095 - 3296 1308 4095 - 3295 1303 4095 - 3295 1303 4095 - 3295 1303 4095 - 3295 1303 4095 - 3295 1303 4095 - 3244 1495 2 - 3244 1495 106 - 3245 1495 220 - 3245 1495 345 - 3245 1495 481 - 3245 1495 623 - 3246 1495 767 - 3246 1496 911 - 3247 1496 1052 - 3248 1496 1192 - 3248 1496 1336 - 3250 1496 1496 - 3251 1496 1675 - 3253 1497 1875 - 3255 1497 2100 - 3257 1498 2356 - 3261 1498 2641 - 3264 1499 2949 - 3269 1500 3269 - 3275 1500 3600 - 3281 1501 3928 - 3287 1501 4072 - 3293 1500 4095 - 3298 1498 4095 - 3301 1494 4095 - 3301 1488 4095 - 3298 1481 4095 - 3296 1473 4095 - 3295 1470 4095 - 3295 1469 4095 - 3295 1469 4095 - 3295 1469 4095 - 3295 1469 4095 - 3258 1677 1 - 3258 1677 103 - 3258 1677 215 - 3258 1677 340 - 3258 1677 476 - 3258 1677 619 - 3259 1677 765 - 3259 1677 910 - 3260 1677 1051 - 3261 1678 1193 - 3261 1678 1338 - 3262 1678 1498 - 3263 1678 1678 - 3265 1679 1879 - 3267 1679 2106 - 3269 1680 2364 - 3272 1680 2651 - 3275 1681 2960 - 3279 1682 3279 - 3283 1682 3607 - 3288 1683 3924 - 3293 1683 4071 - 3297 1682 4095 - 3300 1680 4095 - 3301 1676 4095 - 3300 1671 4095 - 3297 1664 4095 - 3295 1658 4095 - 3295 1656 4095 - 3295 1656 4095 - 3295 1656 4095 - 3295 1656 4095 - 3295 1656 4095 - 3272 1882 3 - 3272 1882 99 - 3272 1882 208 - 3272 1882 333 - 3272 1882 470 - 3273 1882 614 - 3273 1882 762 - 3273 1882 908 - 3274 1882 1050 - 3274 1883 1193 - 3275 1883 1338 - 3276 1883 1500 - 3277 1883 1681 - 3278 1884 1883 - 3279 1884 2111 - 3281 1885 2372 - 3283 1885 2661 - 3286 1886 2971 - 3288 1886 3288 - 3291 1887 3612 - 3295 1887 3918 - 3298 1887 4069 - 3300 1886 4095 - 3301 1883 4095 - 3301 1880 4095 - 3299 1875 4095 - 3296 1870 4095 - 3295 1866 4095 - 3295 1865 4095 - 3295 1865 4095 - 3295 1865 4095 - 3295 1865 4095 - 3295 1865 4095 - 3286 2114 3 - 3286 2114 94 - 3286 2114 200 - 3286 2114 324 - 3286 2114 462 - 3287 2114 608 - 3287 2115 757 - 3287 2115 904 - 3287 2115 1048 - 3288 2115 1191 - 3288 2115 1338 - 3289 2115 1501 - 3289 2115 1683 - 3290 2116 1886 - 3291 2116 2116 - 3292 2116 2379 - 3293 2117 2670 - 3295 2117 2981 - 3296 2118 3296 - 3298 2118 3615 - 3300 2118 3910 - 3301 2117 4067 - 3301 2116 4095 - 3301 2114 4095 - 3300 2111 4095 - 3297 2107 4095 - 3295 2103 4095 - 3295 2102 4095 - 3295 2102 4095 - 3295 2102 4095 - 3295 2102 4095 - 3295 2102 4095 - 3295 2102 4095 - 3296 2381 3 - 3296 2381 87 - 3296 2381 189 - 3296 2381 312 - 3296 2381 450 - 3296 2382 598 - 3297 2382 749 - 3297 2382 898 - 3297 2382 1043 - 3297 2382 1187 - 3297 2382 1334 - 3297 2382 1498 - 3298 2382 1682 - 3298 2382 1886 - 3299 2383 2118 - 3299 2383 2383 - 3300 2383 2676 - 3300 2383 2988 - 3301 2383 3301 - 3301 2383 3613 - 3301 2383 3897 - 3301 2383 4064 - 3300 2382 4095 - 3299 2380 4095 - 3297 2378 4095 - 3296 2376 4095 - 3295 2375 4095 - 3295 2375 4095 - 3295 2375 4095 - 3295 2375 4095 - 3295 2375 4095 - 3295 2375 4095 - 3295 2375 4095 - 3301 2678 1 - 3301 2678 77 - 3301 2678 174 - 3301 2678 295 - 3301 2678 435 - 3301 2678 584 - 3301 2678 738 - 3301 2678 889 - 3301 2678 1034 - 3301 2679 1179 - 3301 2679 1328 - 3301 2679 1492 - 3301 2679 1677 - 3301 2679 1883 - 3301 2679 2115 - 3301 2679 2383 - 3301 2679 2679 - 3301 2679 2991 - 3301 2679 3301 - 3300 2679 3606 - 3300 2679 3882 - 3299 2678 4062 - 3298 2678 4095 - 3297 2677 4095 - 3296 2677 4095 - 3295 2677 4095 - 3295 2677 4095 - 3295 2677 4095 - 3295 2677 4095 - 3295 2677 4095 - 3295 2677 4095 - 3295 2677 4095 - 3295 2677 4095 - 3300 2991 2 - 3300 2991 64 - 3300 2991 154 - 3300 2991 275 - 3300 2991 416 - 3300 2991 568 - 3300 2991 724 - 3300 2991 877 - 3300 2991 1023 - 3300 2991 1168 - 3299 2991 1317 - 3299 2991 1483 - 3299 2991 1668 - 3299 2991 1875 - 3299 2991 2110 - 3299 2991 2380 - 3298 2991 2678 - 3298 2991 2991 - 3298 2991 3298 - 3297 2991 3596 - 3297 2991 3866 - 3296 2991 4059 - 3296 2991 4095 - 3295 2991 4095 - 3295 2991 4095 - 3295 2991 4095 - 3295 2991 4095 - 3295 2991 4095 - 3295 2991 4095 - 3295 2991 4095 - 3295 2991 4095 - 3295 2991 4095 - 3295 2991 4095 - 3296 3296 1 - 3296 3296 49 - 3296 3296 133 - 3296 3296 254 - 3296 3296 397 - 3296 3296 552 - 3296 3296 711 - 3296 3296 865 - 3296 3296 1012 - 3296 3296 1158 - 3296 3296 1307 - 3296 3296 1474 - 3296 3296 1660 - 3296 3296 1868 - 3296 3296 2104 - 3296 3295 2376 - 3295 3295 2677 - 3295 3295 2991 - 3295 3295 3295 - 3295 3295 3589 - 3295 3295 3854 - 3295 3295 4058 - 3295 3295 4095 - 3295 3295 4095 - 3295 3295 4095 - 3295 3295 4095 - 3295 3295 4095 - 3295 3295 4095 - 3295 3295 4095 - 3295 3295 4095 - 3295 3295 4095 - 3295 3295 4095 - 3295 3295 4095 - 3295 3588 1 - 3295 3588 37 - 3295 3588 120 - 3295 3588 242 - 3295 3588 387 - 3295 3588 544 - 3295 3588 704 - 3295 3588 859 - 3295 3588 1006 - 3295 3588 1152 - 3295 3588 1303 - 3295 3588 1470 - 3295 3588 1656 - 3295 3588 1865 - 3295 3588 2102 - 3295 3588 2375 - 3295 3588 2677 - 3295 3588 2991 - 3295 3588 3295 - 3295 3588 3588 - 3295 3588 3852 - 3295 3588 4057 - 3295 3588 4095 - 3295 3588 4095 - 3295 3588 4095 - 3295 3588 4095 - 3295 3588 4095 - 3295 3588 4095 - 3295 3588 4095 - 3295 3588 4095 - 3295 3588 4095 - 3295 3588 4095 - 3295 3588 4095 - 3295 3852 0 - 3295 3852 36 - 3295 3852 119 - 3295 3852 242 - 3295 3852 387 - 3295 3852 543 - 3295 3852 704 - 3295 3852 858 - 3295 3852 1006 - 3295 3852 1152 - 3295 3852 1303 - 3295 3852 1469 - 3295 3852 1656 - 3295 3852 1865 - 3295 3852 2102 - 3295 3852 2375 - 3295 3852 2677 - 3295 3852 2991 - 3295 3852 3295 - 3295 3852 3588 - 3295 3852 3852 - 3295 3852 4057 - 3295 3852 4095 - 3295 3852 4095 - 3295 3852 4095 - 3295 3852 4095 - 3295 3852 4095 - 3295 3852 4095 - 3295 3852 4095 - 3295 3852 4095 - 3295 3852 4095 - 3295 3852 4095 - 3295 3852 4095 - 3295 4057 0 - 3295 4057 36 - 3295 4057 119 - 3295 4057 242 - 3295 4057 387 - 3295 4057 543 - 3295 4057 704 - 3295 4057 858 - 3295 4057 1006 - 3295 4057 1152 - 3295 4057 1303 - 3295 4057 1469 - 3295 4057 1656 - 3295 4057 1865 - 3295 4057 2102 - 3295 4057 2375 - 3295 4057 2677 - 3295 4057 2991 - 3295 4057 3295 - 3295 4057 3588 - 3295 4057 3852 - 3295 4057 4057 - 3295 4057 4095 - 3295 4057 4095 - 3295 4057 4095 - 3295 4057 4095 - 3295 4057 4095 - 3295 4057 4095 - 3295 4057 4095 - 3295 4057 4095 - 3295 4057 4095 - 3295 4057 4095 - 3295 4057 4095 - 3295 4095 0 - 3295 4095 36 - 3295 4095 119 - 3295 4095 242 - 3295 4095 387 - 3295 4095 543 - 3295 4095 704 - 3295 4095 858 - 3295 4095 1006 - 3295 4095 1152 - 3295 4095 1303 - 3295 4095 1469 - 3295 4095 1656 - 3295 4095 1865 - 3295 4095 2102 - 3295 4095 2375 - 3295 4095 2677 - 3295 4095 2991 - 3295 4095 3295 - 3295 4095 3588 - 3295 4095 3852 - 3295 4095 4057 - 3295 4095 4095 - 3295 4095 4095 - 3295 4095 4095 - 3295 4095 4095 - 3295 4095 4095 - 3295 4095 4095 - 3295 4095 4095 - 3295 4095 4095 - 3295 4095 4095 - 3295 4095 4095 - 3295 4095 4095 - 3295 4095 0 - 3295 4095 36 - 3295 4095 119 - 3295 4095 242 - 3295 4095 387 - 3295 4095 543 - 3295 4095 704 - 3295 4095 858 - 3295 4095 1006 - 3295 4095 1152 - 3295 4095 1303 - 3295 4095 1469 - 3295 4095 1656 - 3295 4095 1865 - 3295 4095 2102 - 3295 4095 2375 - 3295 4095 2677 - 3295 4095 2991 - 3295 4095 3295 - 3295 4095 3588 - 3295 4095 3852 - 3295 4095 4057 - 3295 4095 4095 - 3295 4095 4095 - 3295 4095 4095 - 3295 4095 4095 - 3295 4095 4095 - 3295 4095 4095 - 3295 4095 4095 - 3295 4095 4095 - 3295 4095 4095 - 3295 4095 4095 - 3295 4095 4095 - 3295 4095 0 - 3295 4095 36 - 3295 4095 119 - 3295 4095 242 - 3295 4095 387 - 3295 4095 543 - 3295 4095 704 - 3295 4095 858 - 3295 4095 1006 - 3295 4095 1152 - 3295 4095 1303 - 3295 4095 1469 - 3295 4095 1656 - 3295 4095 1865 - 3295 4095 2102 - 3295 4095 2375 - 3295 4095 2677 - 3295 4095 2991 - 3295 4095 3295 - 3295 4095 3588 - 3295 4095 3852 - 3295 4095 4057 - 3295 4095 4095 - 3295 4095 4095 - 3295 4095 4095 - 3295 4095 4095 - 3295 4095 4095 - 3295 4095 4095 - 3295 4095 4095 - 3295 4095 4095 - 3295 4095 4095 - 3295 4095 4095 - 3295 4095 4095 - 3295 4095 0 - 3295 4095 36 - 3295 4095 119 - 3295 4095 242 - 3295 4095 387 - 3295 4095 543 - 3295 4095 704 - 3295 4095 858 - 3295 4095 1006 - 3295 4095 1152 - 3295 4095 1303 - 3295 4095 1469 - 3295 4095 1656 - 3295 4095 1865 - 3295 4095 2102 - 3295 4095 2375 - 3295 4095 2677 - 3295 4095 2991 - 3295 4095 3295 - 3295 4095 3588 - 3295 4095 3852 - 3295 4095 4057 - 3295 4095 4095 - 3295 4095 4095 - 3295 4095 4095 - 3295 4095 4095 - 3295 4095 4095 - 3295 4095 4095 - 3295 4095 4095 - 3295 4095 4095 - 3295 4095 4095 - 3295 4095 4095 - 3295 4095 4095 - 3295 4095 0 - 3295 4095 36 - 3295 4095 119 - 3295 4095 242 - 3295 4095 387 - 3295 4095 543 - 3295 4095 704 - 3295 4095 858 - 3295 4095 1006 - 3295 4095 1152 - 3295 4095 1303 - 3295 4095 1469 - 3295 4095 1656 - 3295 4095 1865 - 3295 4095 2102 - 3295 4095 2375 - 3295 4095 2677 - 3295 4095 2991 - 3295 4095 3295 - 3295 4095 3588 - 3295 4095 3852 - 3295 4095 4057 - 3295 4095 4095 - 3295 4095 4095 - 3295 4095 4095 - 3295 4095 4095 - 3295 4095 4095 - 3295 4095 4095 - 3295 4095 4095 - 3295 4095 4095 - 3295 4095 4095 - 3295 4095 4095 - 3295 4095 4095 - 3295 4095 0 - 3295 4095 36 - 3295 4095 119 - 3295 4095 242 - 3295 4095 387 - 3295 4095 543 - 3295 4095 704 - 3295 4095 858 - 3295 4095 1006 - 3295 4095 1152 - 3295 4095 1303 - 3295 4095 1469 - 3295 4095 1656 - 3295 4095 1865 - 3295 4095 2102 - 3295 4095 2375 - 3295 4095 2677 - 3295 4095 2991 - 3295 4095 3295 - 3295 4095 3588 - 3295 4095 3852 - 3295 4095 4057 - 3295 4095 4095 - 3295 4095 4095 - 3295 4095 4095 - 3295 4095 4095 - 3295 4095 4095 - 3295 4095 4095 - 3295 4095 4095 - 3295 4095 4095 - 3295 4095 4095 - 3295 4095 4095 - 3295 4095 4095 - 3295 4095 0 - 3295 4095 36 - 3295 4095 119 - 3295 4095 242 - 3295 4095 387 - 3295 4095 543 - 3295 4095 704 - 3295 4095 858 - 3295 4095 1006 - 3295 4095 1152 - 3295 4095 1303 - 3295 4095 1469 - 3295 4095 1656 - 3295 4095 1865 - 3295 4095 2102 - 3295 4095 2375 - 3295 4095 2677 - 3295 4095 2991 - 3295 4095 3295 - 3295 4095 3588 - 3295 4095 3852 - 3295 4095 4057 - 3295 4095 4095 - 3295 4095 4095 - 3295 4095 4095 - 3295 4095 4095 - 3295 4095 4095 - 3295 4095 4095 - 3295 4095 4095 - 3295 4095 4095 - 3295 4095 4095 - 3295 4095 4095 - 3295 4095 4095 - 3295 4095 0 - 3295 4095 36 - 3295 4095 119 - 3295 4095 242 - 3295 4095 387 - 3295 4095 543 - 3295 4095 704 - 3295 4095 858 - 3295 4095 1006 - 3295 4095 1152 - 3295 4095 1303 - 3295 4095 1469 - 3295 4095 1656 - 3295 4095 1865 - 3295 4095 2102 - 3295 4095 2375 - 3295 4095 2677 - 3295 4095 2991 - 3295 4095 3295 - 3295 4095 3588 - 3295 4095 3852 - 3295 4095 4057 - 3295 4095 4095 - 3295 4095 4095 - 3295 4095 4095 - 3295 4095 4095 - 3295 4095 4095 - 3295 4095 4095 - 3295 4095 4095 - 3295 4095 4095 - 3295 4095 4095 - 3295 4095 4095 - 3295 4095 4095 - 3295 4095 0 - 3295 4095 36 - 3295 4095 119 - 3295 4095 242 - 3295 4095 387 - 3295 4095 543 - 3295 4095 704 - 3295 4095 858 - 3295 4095 1006 - 3295 4095 1152 - 3295 4095 1303 - 3295 4095 1469 - 3295 4095 1656 - 3295 4095 1865 - 3295 4095 2102 - 3295 4095 2375 - 3295 4095 2677 - 3295 4095 2991 - 3295 4095 3295 - 3295 4095 3588 - 3295 4095 3852 - 3295 4095 4057 - 3295 4095 4095 - 3295 4095 4095 - 3295 4095 4095 - 3295 4095 4095 - 3295 4095 4095 - 3295 4095 4095 - 3295 4095 4095 - 3295 4095 4095 - 3295 4095 4095 - 3295 4095 4095 - 3295 4095 4095 - 3295 4095 0 - 3295 4095 36 - 3295 4095 119 - 3295 4095 242 - 3295 4095 387 - 3295 4095 543 - 3295 4095 704 - 3295 4095 858 - 3295 4095 1006 - 3295 4095 1152 - 3295 4095 1303 - 3295 4095 1469 - 3295 4095 1656 - 3295 4095 1865 - 3295 4095 2102 - 3295 4095 2375 - 3295 4095 2677 - 3295 4095 2991 - 3295 4095 3295 - 3295 4095 3588 - 3295 4095 3852 - 3295 4095 4057 - 3295 4095 4095 - 3295 4095 4095 - 3295 4095 4095 - 3295 4095 4095 - 3295 4095 4095 - 3295 4095 4095 - 3295 4095 4095 - 3295 4095 4095 - 3295 4095 4095 - 3295 4095 4095 - 3295 4095 4095 - 3295 4095 0 - 3295 4095 36 - 3295 4095 119 - 3295 4095 242 - 3295 4095 387 - 3295 4095 543 - 3295 4095 704 - 3295 4095 858 - 3295 4095 1006 - 3295 4095 1152 - 3295 4095 1303 - 3295 4095 1469 - 3295 4095 1656 - 3295 4095 1865 - 3295 4095 2102 - 3295 4095 2375 - 3295 4095 2677 - 3295 4095 2991 - 3295 4095 3295 - 3295 4095 3588 - 3295 4095 3852 - 3295 4095 4057 - 3295 4095 4095 - 3295 4095 4095 - 3295 4095 4095 - 3295 4095 4095 - 3295 4095 4095 - 3295 4095 4095 - 3295 4095 4095 - 3295 4095 4095 - 3295 4095 4095 - 3295 4095 4095 - 3295 4095 4095 - 3542 0 0 - 3542 2 112 - 3542 1 230 - 3542 2 356 - 3542 2 490 - 3543 2 630 - 3544 3 771 - 3544 2 912 - 3545 1 1050 - 3546 2 1189 - 3547 2 1331 - 3549 1 1489 - 3550 0 1665 - 3552 0 1862 - 3555 0 2083 - 3558 3 2335 - 3562 3 2615 - 3566 3 2920 - 3571 0 3241 - 3577 0 3578 - 3585 2 3921 - 3594 3 4075 - 3602 2 4095 - 3610 3 4095 - 3614 3 4095 - 3613 1 4095 - 3607 3 4095 - 3596 1 4095 - 3589 2 4095 - 3588 0 4095 - 3588 0 4095 - 3588 0 4095 - 3588 0 4095 - 3542 112 2 - 3542 112 112 - 3542 112 230 - 3542 112 356 - 3543 112 490 - 3543 112 630 - 3544 112 771 - 3545 111 912 - 3545 111 1050 - 3546 111 1189 - 3548 111 1331 - 3549 111 1489 - 3551 111 1665 - 3553 110 1862 - 3555 110 2083 - 3558 109 2335 - 3562 109 2615 - 3566 108 2920 - 3571 106 3241 - 3578 105 3578 - 3585 103 3922 - 3594 101 4075 - 3603 97 4095 - 3610 93 4095 - 3614 87 4095 - 3613 79 4095 - 3607 68 4095 - 3596 54 4095 - 3589 40 4095 - 3588 36 4095 - 3588 36 4095 - 3588 36 4095 - 3588 36 4095 - 3543 229 2 - 3543 229 112 - 3544 229 229 - 3544 229 356 - 3544 229 490 - 3545 229 629 - 3545 229 771 - 3546 229 912 - 3547 229 1051 - 3548 228 1189 - 3549 228 1331 - 3550 228 1489 - 3552 227 1665 - 3554 227 1862 - 3556 226 2084 - 3559 225 2336 - 3563 224 2616 - 3567 222 2921 - 3572 220 3242 - 3579 218 3579 - 3586 215 3922 - 3594 211 4075 - 3603 205 4095 - 3610 198 4095 - 3614 189 4095 - 3613 176 4095 - 3606 160 4095 - 3596 140 4095 - 3589 123 4095 - 3588 119 4095 - 3588 119 4095 - 3588 119 4095 - 3588 119 4095 - 3546 355 3 - 3546 355 111 - 3546 355 229 - 3546 355 355 - 3546 355 490 - 3547 355 629 - 3547 355 771 - 3548 355 912 - 3549 355 1051 - 3550 354 1189 - 3551 354 1332 - 3552 354 1490 - 3554 353 1666 - 3556 353 1863 - 3558 352 2085 - 3561 351 2337 - 3565 350 2618 - 3569 348 2923 - 3574 346 3244 - 3580 343 3580 - 3587 340 3923 - 3596 335 4075 - 3604 329 4095 - 3611 321 4095 - 3614 311 4095 - 3613 297 4095 - 3606 280 4095 - 3596 261 4095 - 3589 245 4095 - 3588 242 4095 - 3588 242 4095 - 3588 242 4095 - 3588 242 4095 - 3549 489 2 - 3549 489 111 - 3549 489 228 - 3549 489 355 - 3550 489 489 - 3550 489 629 - 3551 489 771 - 3551 489 912 - 3552 488 1051 - 3553 488 1190 - 3554 488 1332 - 3555 488 1490 - 3557 487 1667 - 3559 487 1864 - 3561 486 2086 - 3564 485 2339 - 3567 484 2620 - 3571 482 2926 - 3576 480 3246 - 3582 478 3582 - 3589 475 3924 - 3597 471 4075 - 3605 465 4095 - 3611 458 4095 - 3615 448 4095 - 3613 435 4095 - 3605 419 4095 - 3595 402 4095 - 3588 389 4095 - 3588 387 4095 - 3588 387 4095 - 3588 387 4095 - 3588 387 4095 - 3553 628 1 - 3553 628 110 - 3553 628 227 - 3553 628 353 - 3554 628 488 - 3554 628 628 - 3555 628 770 - 3555 628 912 - 3556 628 1051 - 3557 628 1190 - 3558 627 1333 - 3559 627 1491 - 3560 627 1668 - 3562 626 1866 - 3564 626 2088 - 3567 625 2341 - 3570 624 2623 - 3574 623 2929 - 3579 622 3250 - 3585 620 3585 - 3592 617 3925 - 3599 614 4074 - 3607 610 4095 - 3612 604 4095 - 3615 595 4095 - 3612 584 4095 - 3605 570 4095 - 3594 555 4095 - 3588 545 4095 - 3588 543 4095 - 3588 543 4095 - 3588 543 4095 - 3588 543 4095 - 3558 770 1 - 3558 770 109 - 3558 770 225 - 3558 770 352 - 3559 770 487 - 3559 770 627 - 3559 770 770 - 3560 770 912 - 3561 770 1051 - 3561 770 1191 - 3562 770 1334 - 3563 770 1492 - 3565 769 1670 - 3566 769 1868 - 3568 769 2091 - 3571 768 2345 - 3574 768 2627 - 3578 767 2934 - 3583 766 3254 - 3588 765 3588 - 3595 763 3927 - 3602 761 4074 - 3608 758 4095 - 3613 753 4095 - 3615 746 4095 - 3611 736 4095 - 3604 725 4095 - 3594 713 4095 - 3588 705 4095 - 3588 704 4095 - 3588 704 4095 - 3588 704 4095 - 3588 704 4095 - 3563 912 0 - 3563 912 108 - 3564 912 224 - 3564 912 350 - 3564 912 485 - 3564 912 626 - 3565 912 769 - 3565 912 912 - 3566 912 1052 - 3567 912 1191 - 3567 912 1335 - 3568 912 1494 - 3570 911 1671 - 3571 911 1870 - 3573 911 2094 - 3576 911 2348 - 3579 911 2632 - 3582 910 2939 - 3587 910 3259 - 3592 909 3592 - 3598 908 3928 - 3604 907 4073 - 3610 904 4095 - 3614 900 4095 - 3614 894 4095 - 3610 886 4095 - 3602 876 4095 - 3593 866 4095 - 3588 859 4095 - 3588 858 4095 - 3588 858 4095 - 3588 858 4095 - 3588 858 4095 - 3569 1052 0 - 3569 1052 107 - 3569 1052 222 - 3570 1052 348 - 3570 1052 483 - 3570 1052 624 - 3571 1052 768 - 3571 1052 911 - 3572 1052 1052 - 3572 1052 1192 - 3573 1052 1335 - 3574 1052 1495 - 3575 1052 1673 - 3577 1052 1873 - 3579 1052 2097 - 3581 1052 2352 - 3584 1052 2637 - 3587 1051 2945 - 3592 1051 3265 - 3596 1051 3597 - 3602 1050 3928 - 3607 1049 4073 - 3612 1047 4095 - 3614 1043 4095 - 3614 1038 4095 - 3609 1030 4095 - 3601 1021 4095 - 3592 1011 4095 - 3588 1006 4095 - 3588 1006 4095 - 3588 1006 4095 - 3588 1006 4095 - 3588 1006 4095 - 3576 1192 2 - 3576 1192 105 - 3576 1192 219 - 3576 1192 345 - 3576 1192 480 - 3577 1192 622 - 3577 1192 767 - 3577 1192 911 - 3578 1192 1052 - 3579 1192 1192 - 3579 1192 1336 - 3580 1192 1496 - 3581 1192 1675 - 3583 1192 1875 - 3585 1193 2100 - 3587 1193 2357 - 3590 1193 2643 - 3593 1193 2951 - 3597 1193 3271 - 3601 1193 3601 - 3605 1192 3927 - 3610 1191 4072 - 3613 1189 4095 - 3615 1186 4095 - 3613 1181 4095 - 3608 1173 4095 - 3599 1165 4095 - 3591 1157 4095 - 3588 1152 4095 - 3588 1152 4095 - 3588 1152 4095 - 3588 1152 4095 - 3588 1152 4095 - 3583 1337 4 - 3583 1337 104 - 3583 1337 216 - 3583 1337 342 - 3584 1337 477 - 3584 1337 620 - 3584 1337 766 - 3585 1337 910 - 3585 1337 1051 - 3586 1337 1193 - 3586 1337 1337 - 3587 1337 1498 - 3588 1338 1677 - 3590 1338 1878 - 3591 1338 2104 - 3593 1338 2362 - 3596 1338 2649 - 3598 1338 2958 - 3602 1339 3277 - 3605 1339 3605 - 3609 1338 3925 - 3612 1337 4071 - 3614 1335 4095 - 3614 1332 4095 - 3612 1327 4095 - 3606 1321 4095 - 3597 1313 4095 - 3590 1306 4095 - 3588 1303 4095 - 3588 1303 4095 - 3588 1303 4095 - 3588 1303 4095 - 3588 1303 4095 - 3591 1499 4 - 3591 1499 101 - 3591 1499 212 - 3592 1499 337 - 3592 1499 474 - 3592 1499 617 - 3592 1499 764 - 3593 1499 909 - 3593 1499 1051 - 3594 1499 1193 - 3594 1499 1338 - 3595 1499 1499 - 3596 1500 1680 - 3597 1500 1881 - 3598 1500 2108 - 3600 1500 2368 - 3602 1501 2656 - 3604 1501 2965 - 3607 1501 3284 - 3609 1501 3609 - 3612 1501 3922 - 3614 1500 4070 - 3615 1498 4095 - 3614 1495 4095 - 3610 1490 4095 - 3603 1484 4095 - 3595 1477 4095 - 3589 1471 4095 - 3588 1469 4095 - 3588 1469 4095 - 3588 1469 4095 - 3588 1469 4095 - 3588 1469 4095 - 3600 1681 3 - 3600 1681 98 - 3600 1681 207 - 3600 1681 332 - 3600 1681 469 - 3601 1681 613 - 3601 1681 761 - 3601 1681 907 - 3602 1681 1050 - 3602 1681 1192 - 3602 1682 1338 - 3603 1682 1501 - 3604 1682 1682 - 3604 1682 1884 - 3605 1682 2112 - 3607 1682 2373 - 3608 1683 2663 - 3610 1683 2973 - 3611 1683 3290 - 3613 1683 3613 - 3614 1682 3917 - 3615 1681 4068 - 3614 1680 4095 - 3611 1677 4095 - 3607 1672 4095 - 3600 1667 4095 - 3593 1661 4095 - 3588 1657 4095 - 3588 1656 4095 - 3588 1656 4095 - 3588 1656 4095 - 3588 1656 4095 - 3588 1656 4095 - 3608 1886 1 - 3608 1886 94 - 3608 1886 200 - 3608 1886 324 - 3608 1886 462 - 3608 1886 608 - 3609 1886 757 - 3609 1886 905 - 3609 1886 1048 - 3609 1886 1191 - 3609 1886 1338 - 3610 1886 1501 - 3610 1886 1683 - 3611 1886 1886 - 3611 1887 2116 - 3612 1887 2378 - 3613 1887 2670 - 3613 1887 2981 - 3614 1887 3296 - 3614 1887 3615 - 3614 1886 3910 - 3614 1885 4067 - 3612 1883 4095 - 3608 1880 4095 - 3603 1876 4095 - 3596 1872 4095 - 3591 1867 4095 - 3588 1865 4095 - 3588 1865 4095 - 3588 1865 4095 - 3588 1865 4095 - 3588 1865 4095 - 3588 1865 4095 - 3614 2117 1 - 3614 2117 89 - 3614 2117 192 - 3614 2117 315 - 3614 2117 453 - 3614 2117 600 - 3614 2117 751 - 3614 2117 900 - 3614 2117 1044 - 3614 2117 1188 - 3614 2117 1336 - 3614 2118 1499 - 3614 2118 1682 - 3614 2118 1887 - 3615 2118 2118 - 3615 2118 2382 - 3615 2118 2675 - 3615 2118 2987 - 3614 2118 3300 - 3614 2117 3614 - 3612 2116 3901 - 3610 2115 4065 - 3607 2113 4095 - 3603 2111 4095 - 3598 2108 4095 - 3593 2105 4095 - 3589 2102 4095 - 3588 2102 4095 - 3588 2102 4095 - 3588 2102 4095 - 3588 2102 4095 - 3588 2102 4095 - 3588 2102 4095 - 3614 2383 3 - 3614 2383 81 - 3614 2383 180 - 3614 2383 302 - 3614 2383 441 - 3614 2383 590 - 3614 2383 743 - 3614 2383 893 - 3614 2383 1038 - 3614 2383 1182 - 3614 2383 1331 - 3614 2383 1495 - 3613 2383 1679 - 3613 2383 1885 - 3613 2383 2117 - 3613 2383 2383 - 3612 2383 2678 - 3611 2383 2991 - 3610 2383 3301 - 3609 2383 3609 - 3607 2382 3888 - 3604 2381 4063 - 3601 2380 4095 - 3597 2378 4095 - 3593 2377 4095 - 3589 2376 4095 - 3588 2375 4095 - 3588 2375 4095 - 3588 2375 4095 - 3588 2375 4095 - 3588 2375 4095 - 3588 2375 4095 - 3588 2375 4095 - 3609 2679 2 - 3609 2679 71 - 3609 2679 164 - 3609 2679 285 - 3609 2679 425 - 3608 2679 577 - 3608 2679 732 - 3608 2679 883 - 3608 2679 1029 - 3608 2679 1174 - 3608 2679 1323 - 3608 2679 1488 - 3607 2679 1673 - 3607 2679 1879 - 3606 2679 2113 - 3606 2679 2382 - 3605 2679 2679 - 3604 2679 2992 - 3603 2679 3300 - 3601 2678 3601 - 3599 2678 3874 - 3597 2678 4060 - 3594 2677 4095 - 3591 2677 4095 - 3589 2677 4095 - 3588 2677 4095 - 3588 2677 4095 - 3588 2677 4095 - 3588 2677 4095 - 3588 2677 4095 - 3588 2677 4095 - 3588 2677 4095 - 3588 2677 4095 - 3599 2991 1 - 3599 2991 58 - 3599 2991 146 - 3599 2991 266 - 3599 2991 408 - 3599 2991 561 - 3599 2991 719 - 3598 2991 872 - 3598 2991 1018 - 3598 2991 1164 - 3598 2991 1313 - 3598 2991 1479 - 3597 2991 1665 - 3597 2991 1872 - 3597 2991 2107 - 3596 2991 2378 - 3595 2991 2677 - 3595 2991 2991 - 3594 2991 3296 - 3593 2991 3593 - 3591 2991 3860 - 3590 2991 4058 - 3589 2991 4095 - 3588 2991 4095 - 3588 2991 4095 - 3588 2991 4095 - 3588 2991 4095 - 3588 2991 4095 - 3588 2991 4095 - 3588 2991 4095 - 3588 2991 4095 - 3588 2991 4095 - 3588 2991 4095 - 3590 3295 1 - 3590 3295 43 - 3590 3295 127 - 3590 3295 249 - 3590 3295 392 - 3590 3295 548 - 3590 3295 707 - 3590 3295 862 - 3590 3295 1009 - 3590 3295 1155 - 3590 3295 1305 - 3590 3295 1472 - 3589 3295 1658 - 3589 3295 1866 - 3589 3295 2103 - 3589 3295 2375 - 3589 3295 2677 - 3588 3295 2991 - 3588 3295 3295 - 3588 3295 3588 - 3588 3295 3852 - 3588 3295 4057 - 3588 3295 4095 - 3588 3295 4095 - 3588 3295 4095 - 3588 3295 4095 - 3588 3295 4095 - 3588 3295 4095 - 3588 3295 4095 - 3588 3295 4095 - 3588 3295 4095 - 3588 3295 4095 - 3588 3295 4095 - 3588 3588 0 - 3588 3588 36 - 3588 3588 120 - 3588 3588 242 - 3588 3588 387 - 3588 3588 543 - 3588 3588 704 - 3588 3588 858 - 3588 3588 1006 - 3588 3588 1152 - 3588 3588 1303 - 3588 3588 1469 - 3588 3588 1656 - 3588 3588 1865 - 3588 3588 2102 - 3588 3588 2375 - 3588 3588 2677 - 3588 3588 2991 - 3588 3588 3295 - 3588 3588 3588 - 3588 3588 3852 - 3588 3588 4057 - 3588 3588 4095 - 3588 3588 4095 - 3588 3588 4095 - 3588 3588 4095 - 3588 3588 4095 - 3588 3588 4095 - 3588 3588 4095 - 3588 3588 4095 - 3588 3588 4095 - 3588 3588 4095 - 3588 3588 4095 - 3588 3852 0 - 3588 3852 36 - 3588 3852 119 - 3588 3852 242 - 3588 3852 387 - 3588 3852 543 - 3588 3852 704 - 3588 3852 858 - 3588 3852 1006 - 3588 3852 1152 - 3588 3852 1303 - 3588 3852 1469 - 3588 3852 1656 - 3588 3852 1865 - 3588 3852 2102 - 3588 3852 2375 - 3588 3852 2677 - 3588 3852 2991 - 3588 3852 3295 - 3588 3852 3588 - 3588 3852 3852 - 3588 3852 4057 - 3588 3852 4095 - 3588 3852 4095 - 3588 3852 4095 - 3588 3852 4095 - 3588 3852 4095 - 3588 3852 4095 - 3588 3852 4095 - 3588 3852 4095 - 3588 3852 4095 - 3588 3852 4095 - 3588 3852 4095 - 3588 4057 0 - 3588 4057 36 - 3588 4057 119 - 3588 4057 242 - 3588 4057 387 - 3588 4057 543 - 3588 4057 704 - 3588 4057 858 - 3588 4057 1006 - 3588 4057 1152 - 3588 4057 1303 - 3588 4057 1469 - 3588 4057 1656 - 3588 4057 1865 - 3588 4057 2102 - 3588 4057 2375 - 3588 4057 2677 - 3588 4057 2991 - 3588 4057 3295 - 3588 4057 3588 - 3588 4057 3852 - 3588 4057 4057 - 3588 4057 4095 - 3588 4057 4095 - 3588 4057 4095 - 3588 4057 4095 - 3588 4057 4095 - 3588 4057 4095 - 3588 4057 4095 - 3588 4057 4095 - 3588 4057 4095 - 3588 4057 4095 - 3588 4057 4095 - 3588 4095 0 - 3588 4095 36 - 3588 4095 119 - 3588 4095 242 - 3588 4095 387 - 3588 4095 543 - 3588 4095 704 - 3588 4095 858 - 3588 4095 1006 - 3588 4095 1152 - 3588 4095 1303 - 3588 4095 1469 - 3588 4095 1656 - 3588 4095 1865 - 3588 4095 2102 - 3588 4095 2375 - 3588 4095 2677 - 3588 4095 2991 - 3588 4095 3295 - 3588 4095 3588 - 3588 4095 3852 - 3588 4095 4057 - 3588 4095 4095 - 3588 4095 4095 - 3588 4095 4095 - 3588 4095 4095 - 3588 4095 4095 - 3588 4095 4095 - 3588 4095 4095 - 3588 4095 4095 - 3588 4095 4095 - 3588 4095 4095 - 3588 4095 4095 - 3588 4095 0 - 3588 4095 36 - 3588 4095 119 - 3588 4095 242 - 3588 4095 387 - 3588 4095 543 - 3588 4095 704 - 3588 4095 858 - 3588 4095 1006 - 3588 4095 1152 - 3588 4095 1303 - 3588 4095 1469 - 3588 4095 1656 - 3588 4095 1865 - 3588 4095 2102 - 3588 4095 2375 - 3588 4095 2677 - 3588 4095 2991 - 3588 4095 3295 - 3588 4095 3588 - 3588 4095 3852 - 3588 4095 4057 - 3588 4095 4095 - 3588 4095 4095 - 3588 4095 4095 - 3588 4095 4095 - 3588 4095 4095 - 3588 4095 4095 - 3588 4095 4095 - 3588 4095 4095 - 3588 4095 4095 - 3588 4095 4095 - 3588 4095 4095 - 3588 4095 0 - 3588 4095 36 - 3588 4095 119 - 3588 4095 242 - 3588 4095 387 - 3588 4095 543 - 3588 4095 704 - 3588 4095 858 - 3588 4095 1006 - 3588 4095 1152 - 3588 4095 1303 - 3588 4095 1469 - 3588 4095 1656 - 3588 4095 1865 - 3588 4095 2102 - 3588 4095 2375 - 3588 4095 2677 - 3588 4095 2991 - 3588 4095 3295 - 3588 4095 3588 - 3588 4095 3852 - 3588 4095 4057 - 3588 4095 4095 - 3588 4095 4095 - 3588 4095 4095 - 3588 4095 4095 - 3588 4095 4095 - 3588 4095 4095 - 3588 4095 4095 - 3588 4095 4095 - 3588 4095 4095 - 3588 4095 4095 - 3588 4095 4095 - 3588 4095 0 - 3588 4095 36 - 3588 4095 119 - 3588 4095 242 - 3588 4095 387 - 3588 4095 543 - 3588 4095 704 - 3588 4095 858 - 3588 4095 1006 - 3588 4095 1152 - 3588 4095 1303 - 3588 4095 1469 - 3588 4095 1656 - 3588 4095 1865 - 3588 4095 2102 - 3588 4095 2375 - 3588 4095 2677 - 3588 4095 2991 - 3588 4095 3295 - 3588 4095 3588 - 3588 4095 3852 - 3588 4095 4057 - 3588 4095 4095 - 3588 4095 4095 - 3588 4095 4095 - 3588 4095 4095 - 3588 4095 4095 - 3588 4095 4095 - 3588 4095 4095 - 3588 4095 4095 - 3588 4095 4095 - 3588 4095 4095 - 3588 4095 4095 - 3588 4095 0 - 3588 4095 36 - 3588 4095 119 - 3588 4095 242 - 3588 4095 387 - 3588 4095 543 - 3588 4095 704 - 3588 4095 858 - 3588 4095 1006 - 3588 4095 1152 - 3588 4095 1303 - 3588 4095 1469 - 3588 4095 1656 - 3588 4095 1865 - 3588 4095 2102 - 3588 4095 2375 - 3588 4095 2677 - 3588 4095 2991 - 3588 4095 3295 - 3588 4095 3588 - 3588 4095 3852 - 3588 4095 4057 - 3588 4095 4095 - 3588 4095 4095 - 3588 4095 4095 - 3588 4095 4095 - 3588 4095 4095 - 3588 4095 4095 - 3588 4095 4095 - 3588 4095 4095 - 3588 4095 4095 - 3588 4095 4095 - 3588 4095 4095 - 3588 4095 0 - 3588 4095 36 - 3588 4095 119 - 3588 4095 242 - 3588 4095 387 - 3588 4095 543 - 3588 4095 704 - 3588 4095 858 - 3588 4095 1006 - 3588 4095 1152 - 3588 4095 1303 - 3588 4095 1469 - 3588 4095 1656 - 3588 4095 1865 - 3588 4095 2102 - 3588 4095 2375 - 3588 4095 2677 - 3588 4095 2991 - 3588 4095 3295 - 3588 4095 3588 - 3588 4095 3852 - 3588 4095 4057 - 3588 4095 4095 - 3588 4095 4095 - 3588 4095 4095 - 3588 4095 4095 - 3588 4095 4095 - 3588 4095 4095 - 3588 4095 4095 - 3588 4095 4095 - 3588 4095 4095 - 3588 4095 4095 - 3588 4095 4095 - 3588 4095 0 - 3588 4095 36 - 3588 4095 119 - 3588 4095 242 - 3588 4095 387 - 3588 4095 543 - 3588 4095 704 - 3588 4095 858 - 3588 4095 1006 - 3588 4095 1152 - 3588 4095 1303 - 3588 4095 1469 - 3588 4095 1656 - 3588 4095 1865 - 3588 4095 2102 - 3588 4095 2375 - 3588 4095 2677 - 3588 4095 2991 - 3588 4095 3295 - 3588 4095 3588 - 3588 4095 3852 - 3588 4095 4057 - 3588 4095 4095 - 3588 4095 4095 - 3588 4095 4095 - 3588 4095 4095 - 3588 4095 4095 - 3588 4095 4095 - 3588 4095 4095 - 3588 4095 4095 - 3588 4095 4095 - 3588 4095 4095 - 3588 4095 4095 - 3588 4095 0 - 3588 4095 36 - 3588 4095 119 - 3588 4095 242 - 3588 4095 387 - 3588 4095 543 - 3588 4095 704 - 3588 4095 858 - 3588 4095 1006 - 3588 4095 1152 - 3588 4095 1303 - 3588 4095 1469 - 3588 4095 1656 - 3588 4095 1865 - 3588 4095 2102 - 3588 4095 2375 - 3588 4095 2677 - 3588 4095 2991 - 3588 4095 3295 - 3588 4095 3588 - 3588 4095 3852 - 3588 4095 4057 - 3588 4095 4095 - 3588 4095 4095 - 3588 4095 4095 - 3588 4095 4095 - 3588 4095 4095 - 3588 4095 4095 - 3588 4095 4095 - 3588 4095 4095 - 3588 4095 4095 - 3588 4095 4095 - 3588 4095 4095 - 3588 4095 0 - 3588 4095 36 - 3588 4095 119 - 3588 4095 242 - 3588 4095 387 - 3588 4095 543 - 3588 4095 704 - 3588 4095 858 - 3588 4095 1006 - 3588 4095 1152 - 3588 4095 1303 - 3588 4095 1469 - 3588 4095 1656 - 3588 4095 1865 - 3588 4095 2102 - 3588 4095 2375 - 3588 4095 2677 - 3588 4095 2991 - 3588 4095 3295 - 3588 4095 3588 - 3588 4095 3852 - 3588 4095 4057 - 3588 4095 4095 - 3588 4095 4095 - 3588 4095 4095 - 3588 4095 4095 - 3588 4095 4095 - 3588 4095 4095 - 3588 4095 4095 - 3588 4095 4095 - 3588 4095 4095 - 3588 4095 4095 - 3588 4095 4095 - 3588 4095 0 - 3588 4095 36 - 3588 4095 119 - 3588 4095 242 - 3588 4095 387 - 3588 4095 543 - 3588 4095 704 - 3588 4095 858 - 3588 4095 1006 - 3588 4095 1152 - 3588 4095 1303 - 3588 4095 1469 - 3588 4095 1656 - 3588 4095 1865 - 3588 4095 2102 - 3588 4095 2375 - 3588 4095 2677 - 3588 4095 2991 - 3588 4095 3295 - 3588 4095 3588 - 3588 4095 3852 - 3588 4095 4057 - 3588 4095 4095 - 3588 4095 4095 - 3588 4095 4095 - 3588 4095 4095 - 3588 4095 4095 - 3588 4095 4095 - 3588 4095 4095 - 3588 4095 4095 - 3588 4095 4095 - 3588 4095 4095 - 3588 4095 4095 - 3588 4095 0 - 3588 4095 36 - 3588 4095 119 - 3588 4095 242 - 3588 4095 387 - 3588 4095 543 - 3588 4095 704 - 3588 4095 858 - 3588 4095 1006 - 3588 4095 1152 - 3588 4095 1303 - 3588 4095 1469 - 3588 4095 1656 - 3588 4095 1865 - 3588 4095 2102 - 3588 4095 2375 - 3588 4095 2677 - 3588 4095 2991 - 3588 4095 3295 - 3588 4095 3588 - 3588 4095 3852 - 3588 4095 4057 - 3588 4095 4095 - 3588 4095 4095 - 3588 4095 4095 - 3588 4095 4095 - 3588 4095 4095 - 3588 4095 4095 - 3588 4095 4095 - 3588 4095 4095 - 3588 4095 4095 - 3588 4095 4095 - 3588 4095 4095 - 3912 0 2 - 3912 3 107 - 3913 1 221 - 3913 3 347 - 3913 3 482 - 3913 2 624 - 3913 2 768 - 3914 2 911 - 3914 0 1052 - 3914 2 1192 - 3915 3 1336 - 3915 2 1495 - 3916 0 1674 - 3917 0 1873 - 3918 2 2098 - 3920 3 2353 - 3921 3 2638 - 3923 3 2946 - 3925 2 3266 - 3928 3 3598 - 3927 3 3928 - 3924 3 4072 - 3920 3 4095 - 3914 2 4095 - 3905 3 4095 - 3892 2 4095 - 3876 2 4095 - 3861 0 4095 - 3852 1 4095 - 3852 0 4095 - 3852 0 4095 - 3852 0 4095 - 3852 0 4095 - 3913 106 1 - 3913 107 106 - 3913 106 221 - 3913 106 347 - 3913 106 482 - 3913 106 624 - 3913 106 768 - 3914 106 911 - 3914 106 1052 - 3914 106 1192 - 3915 106 1336 - 3915 105 1495 - 3916 105 1674 - 3917 105 1873 - 3918 104 2098 - 3920 104 2354 - 3921 103 2638 - 3923 102 2946 - 3926 101 3266 - 3928 99 3598 - 3927 97 3928 - 3924 94 4072 - 3920 91 4095 - 3914 86 4095 - 3905 80 4095 - 3892 71 4095 - 3876 60 4095 - 3861 47 4095 - 3852 37 4095 - 3852 36 4095 - 3852 36 4095 - 3852 36 4095 - 3852 36 4095 - 3913 221 0 - 3913 221 106 - 3913 220 221 - 3913 220 346 - 3913 220 482 - 3914 220 623 - 3914 220 768 - 3914 220 911 - 3915 220 1052 - 3915 219 1192 - 3915 219 1336 - 3916 219 1496 - 3917 218 1674 - 3918 218 1874 - 3919 217 2098 - 3920 216 2354 - 3922 215 2639 - 3924 213 2947 - 3926 211 3267 - 3928 208 3598 - 3927 205 3928 - 3924 201 4072 - 3920 195 4095 - 3914 187 4095 - 3904 177 4095 - 3891 164 4095 - 3876 148 4095 - 3861 131 4095 - 3852 120 4095 - 3852 119 4095 - 3852 119 4095 - 3852 119 4095 - 3852 119 4095 - 3914 346 3 - 3914 346 106 - 3914 346 220 - 3914 346 346 - 3914 346 481 - 3915 346 623 - 3915 345 768 - 3915 345 911 - 3915 345 1052 - 3916 345 1192 - 3916 344 1336 - 3917 344 1496 - 3918 343 1675 - 3918 343 1874 - 3920 342 2099 - 3921 341 2355 - 3923 339 2641 - 3924 338 2949 - 3926 335 3268 - 3928 333 3599 - 3926 329 3928 - 3924 324 4072 - 3920 317 4095 - 3913 309 4095 - 3904 298 4095 - 3891 284 4095 - 3875 268 4095 - 3860 252 4095 - 3852 242 4095 - 3852 242 4095 - 3852 242 4095 - 3852 242 4095 - 3852 242 4095 - 3915 481 2 - 3915 481 105 - 3916 480 219 - 3916 480 345 - 3916 480 480 - 3916 480 622 - 3916 480 767 - 3916 480 911 - 3917 480 1052 - 3917 479 1192 - 3918 479 1336 - 3918 479 1496 - 3919 478 1675 - 3920 478 1875 - 3921 477 2100 - 3922 476 2357 - 3924 475 2643 - 3925 473 2951 - 3927 471 3270 - 3927 468 3601 - 3926 465 3927 - 3923 460 4072 - 3919 454 4095 - 3912 446 4095 - 3902 436 4095 - 3890 424 4095 - 3874 409 4095 - 3860 395 4095 - 3852 387 4095 - 3852 387 4095 - 3852 387 4095 - 3852 387 4095 - 3852 387 4095 - 3917 622 2 - 3917 622 105 - 3917 622 218 - 3917 622 344 - 3918 622 479 - 3918 622 621 - 3918 621 767 - 3918 621 910 - 3919 621 1052 - 3919 621 1192 - 3919 621 1337 - 3920 620 1497 - 3921 620 1676 - 3921 620 1876 - 3922 619 2102 - 3924 618 2359 - 3925 617 2645 - 3927 616 2954 - 3928 614 3273 - 3927 612 3603 - 3925 609 3926 - 3922 606 4071 - 3918 601 4095 - 3911 594 4095 - 3901 585 4095 - 3888 574 4095 - 3873 561 4095 - 3859 550 4095 - 3852 544 4095 - 3852 543 4095 - 3852 543 4095 - 3852 543 4095 - 3852 543 4095 - 3919 766 3 - 3919 766 104 - 3920 766 216 - 3920 766 342 - 3920 766 478 - 3920 766 620 - 3920 766 766 - 3920 766 910 - 3921 766 1051 - 3921 766 1193 - 3921 766 1337 - 3922 765 1498 - 3923 765 1677 - 3923 765 1878 - 3924 765 2104 - 3925 764 2361 - 3926 763 2648 - 3927 762 2957 - 3927 761 3276 - 3926 760 3605 - 3924 758 3925 - 3921 755 4071 - 3916 750 4095 - 3909 745 4095 - 3899 737 4095 - 3886 728 4095 - 3871 718 4095 - 3858 708 4095 - 3852 704 4095 - 3852 704 4095 - 3852 704 4095 - 3852 704 4095 - 3852 704 4095 - 3922 910 2 - 3922 910 103 - 3922 910 214 - 3922 910 340 - 3922 910 476 - 3922 910 619 - 3923 910 765 - 3923 910 910 - 3923 910 1051 - 3923 910 1193 - 3924 910 1338 - 3924 909 1499 - 3925 909 1678 - 3925 909 1879 - 3926 909 2106 - 3927 909 2364 - 3927 908 2652 - 3927 908 2961 - 3926 907 3280 - 3925 906 3607 - 3923 904 3924 - 3919 901 4070 - 3914 898 4095 - 3907 893 4095 - 3897 887 4095 - 3884 879 4095 - 3869 869 4095 - 3857 862 4095 - 3852 858 4095 - 3852 858 4095 - 3852 858 4095 - 3852 858 4095 - 3852 858 4095 - 3925 1051 3 - 3925 1051 101 - 3925 1051 212 - 3925 1051 337 - 3925 1051 474 - 3925 1051 617 - 3925 1051 764 - 3925 1051 909 - 3926 1051 1051 - 3926 1051 1193 - 3926 1051 1338 - 3926 1051 1499 - 3927 1051 1680 - 3927 1051 1881 - 3927 1051 2108 - 3928 1050 2367 - 3927 1050 2656 - 3926 1050 2965 - 3925 1049 3283 - 3923 1048 3609 - 3921 1047 3922 - 3917 1044 4070 - 3912 1041 4095 - 3904 1037 4095 - 3894 1031 4095 - 3881 1023 4095 - 3867 1015 4095 - 3856 1008 4095 - 3852 1006 4095 - 3852 1006 4095 - 3852 1006 4095 - 3852 1006 4095 - 3852 1006 4095 - 3927 1193 3 - 3927 1193 100 - 3927 1193 210 - 3927 1193 334 - 3927 1193 471 - 3927 1193 615 - 3927 1193 763 - 3927 1193 908 - 3927 1193 1051 - 3927 1193 1193 - 3928 1193 1338 - 3928 1193 1500 - 3928 1193 1681 - 3927 1193 1883 - 3927 1192 2111 - 3926 1192 2371 - 3926 1192 2660 - 3925 1192 2970 - 3923 1191 3287 - 3921 1190 3611 - 3918 1189 3919 - 3914 1187 4069 - 3909 1184 4095 - 3901 1180 4095 - 3891 1174 4095 - 3878 1167 4095 - 3865 1160 4095 - 3855 1154 4095 - 3852 1152 4095 - 3852 1152 4095 - 3852 1152 4095 - 3852 1152 4095 - 3852 1152 4095 - 3927 1339 2 - 3927 1339 98 - 3927 1339 206 - 3927 1339 331 - 3927 1339 468 - 3927 1339 613 - 3927 1339 761 - 3927 1339 907 - 3927 1339 1050 - 3927 1339 1192 - 3927 1339 1338 - 3926 1339 1501 - 3926 1339 1682 - 3926 1338 1885 - 3925 1338 2113 - 3925 1338 2374 - 3924 1338 2664 - 3922 1338 2974 - 3921 1337 3291 - 3919 1336 3613 - 3915 1335 3916 - 3911 1333 4068 - 3905 1331 4095 - 3897 1326 4095 - 3887 1321 4095 - 3875 1315 4095 - 3863 1308 4095 - 3854 1303 4095 - 3852 1303 4095 - 3852 1303 4095 - 3852 1303 4095 - 3852 1303 4095 - 3852 1303 4095 - 3925 1501 3 - 3925 1501 95 - 3925 1501 202 - 3925 1501 326 - 3925 1501 464 - 3925 1501 609 - 3925 1501 758 - 3925 1501 905 - 3925 1501 1049 - 3924 1501 1192 - 3924 1501 1338 - 3924 1501 1501 - 3923 1501 1683 - 3923 1501 1886 - 3922 1501 2115 - 3922 1501 2377 - 3921 1501 2668 - 3919 1500 2979 - 3917 1500 3295 - 3915 1499 3614 - 3911 1498 3912 - 3907 1496 4067 - 3900 1493 4095 - 3892 1489 4095 - 3882 1484 4095 - 3871 1479 4095 - 3860 1473 4095 - 3853 1470 4095 - 3852 1469 4095 - 3852 1469 4095 - 3852 1469 4095 - 3852 1469 4095 - 3852 1469 4095 - 3922 1683 3 - 3922 1683 92 - 3921 1683 197 - 3921 1683 320 - 3921 1683 458 - 3921 1683 605 - 3921 1683 755 - 3921 1683 903 - 3921 1683 1046 - 3921 1683 1190 - 3920 1683 1337 - 3920 1683 1500 - 3920 1683 1683 - 3919 1683 1887 - 3918 1683 2117 - 3917 1683 2380 - 3916 1682 2673 - 3914 1682 2984 - 3912 1682 3298 - 3909 1681 3614 - 3906 1680 3906 - 3901 1678 4066 - 3894 1675 4095 - 3886 1672 4095 - 3877 1667 4095 - 3866 1662 4095 - 3857 1658 4095 - 3852 1656 4095 - 3852 1656 4095 - 3852 1656 4095 - 3852 1656 4095 - 3852 1656 4095 - 3852 1656 4095 - 3916 1887 2 - 3916 1887 87 - 3916 1887 190 - 3916 1887 313 - 3916 1887 451 - 3916 1887 598 - 3915 1887 750 - 3915 1887 899 - 3915 1887 1043 - 3915 1887 1187 - 3914 1887 1335 - 3914 1887 1499 - 3913 1887 1682 - 3913 1887 1887 - 3912 1887 2118 - 3911 1886 2383 - 3909 1886 2676 - 3908 1886 2988 - 3905 1885 3301 - 3902 1884 3613 - 3898 1883 3898 - 3893 1881 4064 - 3887 1879 4095 - 3879 1876 4095 - 3870 1872 4095 - 3861 1868 4095 - 3854 1866 4095 - 3852 1865 4095 - 3852 1865 4095 - 3852 1865 4095 - 3852 1865 4095 - 3852 1865 4095 - 3852 1865 4095 - 3908 2118 0 - 3907 2118 81 - 3907 2117 180 - 3907 2117 302 - 3907 2117 441 - 3907 2117 590 - 3907 2117 743 - 3907 2117 893 - 3906 2117 1038 - 3906 2117 1183 - 3906 2117 1331 - 3905 2117 1495 - 3905 2117 1679 - 3904 2117 1885 - 3903 2117 2117 - 3902 2117 2383 - 3900 2116 2678 - 3898 2116 2991 - 3896 2115 3301 - 3893 2114 3609 - 3889 2113 3889 - 3884 2112 4063 - 3878 2110 4095 - 3871 2107 4095 - 3863 2105 4095 - 3856 2103 4095 - 3852 2102 4095 - 3852 2102 4095 - 3852 2102 4095 - 3852 2102 4095 - 3852 2102 4095 - 3852 2102 4095 - 3852 2102 4095 - 3895 2383 2 - 3895 2383 73 - 3895 2383 168 - 3895 2383 289 - 3895 2383 429 - 3895 2383 580 - 3895 2383 734 - 3895 2383 885 - 3894 2383 1031 - 3894 2383 1176 - 3894 2383 1325 - 3893 2383 1490 - 3893 2383 1674 - 3892 2383 1881 - 3891 2382 2114 - 3890 2382 2382 - 3888 2382 2679 - 3886 2382 2992 - 3884 2381 3300 - 3881 2381 3603 - 3877 2380 3877 - 3873 2379 4061 - 3868 2378 4095 - 3862 2377 4095 - 3857 2376 4095 - 3853 2375 4095 - 3852 2375 4095 - 3852 2375 4095 - 3852 2375 4095 - 3852 2375 4095 - 3852 2375 4095 - 3852 2375 4095 - 3852 2375 4095 - 3880 2679 2 - 3880 2679 63 - 3880 2679 153 - 3880 2679 274 - 3880 2679 414 - 3880 2679 567 - 3880 2679 723 - 3880 2679 876 - 3879 2679 1022 - 3879 2679 1167 - 3879 2678 1317 - 3878 2678 1482 - 3878 2678 1668 - 3877 2678 1875 - 3876 2678 2109 - 3875 2678 2379 - 3874 2678 2678 - 3872 2678 2991 - 3870 2678 3298 - 3868 2677 3596 - 3865 2677 3865 - 3862 2677 4059 - 3858 2677 4095 - 3855 2677 4095 - 3853 2677 4095 - 3852 2677 4095 - 3852 2677 4095 - 3852 2677 4095 - 3852 2677 4095 - 3852 2677 4095 - 3852 2677 4095 - 3852 2677 4095 - 3852 2677 4095 - 3865 2991 2 - 3865 2991 51 - 3864 2991 136 - 3864 2991 257 - 3864 2991 399 - 3864 2991 554 - 3864 2991 712 - 3864 2991 866 - 3864 2991 1013 - 3864 2991 1159 - 3863 2991 1308 - 3863 2991 1475 - 3863 2991 1661 - 3862 2991 1869 - 3862 2991 2104 - 3861 2991 2376 - 3860 2991 2677 - 3859 2991 2991 - 3858 2991 3295 - 3856 2991 3590 - 3855 2991 3855 - 3854 2991 4058 - 3853 2991 4095 - 3852 2991 4095 - 3852 2991 4095 - 3852 2991 4095 - 3852 2991 4095 - 3852 2991 4095 - 3852 2991 4095 - 3852 2991 4095 - 3852 2991 4095 - 3852 2991 4095 - 3852 2991 4095 - 3854 3295 0 - 3854 3295 39 - 3854 3295 122 - 3854 3295 244 - 3854 3295 388 - 3854 3295 545 - 3853 3295 705 - 3853 3295 859 - 3853 3295 1007 - 3853 3295 1153 - 3853 3295 1303 - 3853 3295 1470 - 3853 3295 1657 - 3853 3295 1865 - 3853 3295 2102 - 3853 3295 2375 - 3852 3295 2677 - 3852 3295 2991 - 3852 3295 3295 - 3852 3295 3588 - 3852 3295 3852 - 3852 3295 4057 - 3852 3295 4095 - 3852 3295 4095 - 3852 3295 4095 - 3852 3295 4095 - 3852 3295 4095 - 3852 3295 4095 - 3852 3295 4095 - 3852 3295 4095 - 3852 3295 4095 - 3852 3295 4095 - 3852 3295 4095 - 3852 3588 0 - 3852 3588 36 - 3852 3588 119 - 3852 3588 242 - 3852 3588 387 - 3852 3588 543 - 3852 3588 704 - 3852 3588 858 - 3852 3588 1006 - 3852 3588 1152 - 3852 3588 1303 - 3852 3588 1469 - 3852 3588 1656 - 3852 3588 1865 - 3852 3588 2102 - 3852 3588 2375 - 3852 3588 2677 - 3852 3588 2991 - 3852 3588 3295 - 3852 3588 3588 - 3852 3588 3852 - 3852 3588 4057 - 3852 3588 4095 - 3852 3588 4095 - 3852 3588 4095 - 3852 3588 4095 - 3852 3588 4095 - 3852 3588 4095 - 3852 3588 4095 - 3852 3588 4095 - 3852 3588 4095 - 3852 3588 4095 - 3852 3588 4095 - 3852 3852 0 - 3852 3852 36 - 3852 3852 119 - 3852 3852 242 - 3852 3852 387 - 3852 3852 543 - 3852 3852 704 - 3852 3852 858 - 3852 3852 1006 - 3852 3852 1152 - 3852 3852 1303 - 3852 3852 1469 - 3852 3852 1656 - 3852 3852 1865 - 3852 3852 2102 - 3852 3852 2375 - 3852 3852 2677 - 3852 3852 2991 - 3852 3852 3295 - 3852 3852 3588 - 3852 3852 3852 - 3852 3852 4057 - 3852 3852 4095 - 3852 3852 4095 - 3852 3852 4095 - 3852 3852 4095 - 3852 3852 4095 - 3852 3852 4095 - 3852 3852 4095 - 3852 3852 4095 - 3852 3852 4095 - 3852 3852 4095 - 3852 3852 4095 - 3852 4057 0 - 3852 4057 36 - 3852 4057 119 - 3852 4057 242 - 3852 4057 387 - 3852 4057 543 - 3852 4057 704 - 3852 4057 858 - 3852 4057 1006 - 3852 4057 1152 - 3852 4057 1303 - 3852 4057 1469 - 3852 4057 1656 - 3852 4057 1865 - 3852 4057 2102 - 3852 4057 2375 - 3852 4057 2677 - 3852 4057 2991 - 3852 4057 3295 - 3852 4057 3588 - 3852 4057 3852 - 3852 4057 4057 - 3852 4057 4095 - 3852 4057 4095 - 3852 4057 4095 - 3852 4057 4095 - 3852 4057 4095 - 3852 4057 4095 - 3852 4057 4095 - 3852 4057 4095 - 3852 4057 4095 - 3852 4057 4095 - 3852 4057 4095 - 3852 4095 0 - 3852 4095 36 - 3852 4095 119 - 3852 4095 242 - 3852 4095 387 - 3852 4095 543 - 3852 4095 704 - 3852 4095 858 - 3852 4095 1006 - 3852 4095 1152 - 3852 4095 1303 - 3852 4095 1469 - 3852 4095 1656 - 3852 4095 1865 - 3852 4095 2102 - 3852 4095 2375 - 3852 4095 2677 - 3852 4095 2991 - 3852 4095 3295 - 3852 4095 3588 - 3852 4095 3852 - 3852 4095 4057 - 3852 4095 4095 - 3852 4095 4095 - 3852 4095 4095 - 3852 4095 4095 - 3852 4095 4095 - 3852 4095 4095 - 3852 4095 4095 - 3852 4095 4095 - 3852 4095 4095 - 3852 4095 4095 - 3852 4095 4095 - 3852 4095 0 - 3852 4095 36 - 3852 4095 119 - 3852 4095 242 - 3852 4095 387 - 3852 4095 543 - 3852 4095 704 - 3852 4095 858 - 3852 4095 1006 - 3852 4095 1152 - 3852 4095 1303 - 3852 4095 1469 - 3852 4095 1656 - 3852 4095 1865 - 3852 4095 2102 - 3852 4095 2375 - 3852 4095 2677 - 3852 4095 2991 - 3852 4095 3295 - 3852 4095 3588 - 3852 4095 3852 - 3852 4095 4057 - 3852 4095 4095 - 3852 4095 4095 - 3852 4095 4095 - 3852 4095 4095 - 3852 4095 4095 - 3852 4095 4095 - 3852 4095 4095 - 3852 4095 4095 - 3852 4095 4095 - 3852 4095 4095 - 3852 4095 4095 - 3852 4095 0 - 3852 4095 36 - 3852 4095 119 - 3852 4095 242 - 3852 4095 387 - 3852 4095 543 - 3852 4095 704 - 3852 4095 858 - 3852 4095 1006 - 3852 4095 1152 - 3852 4095 1303 - 3852 4095 1469 - 3852 4095 1656 - 3852 4095 1865 - 3852 4095 2102 - 3852 4095 2375 - 3852 4095 2677 - 3852 4095 2991 - 3852 4095 3295 - 3852 4095 3588 - 3852 4095 3852 - 3852 4095 4057 - 3852 4095 4095 - 3852 4095 4095 - 3852 4095 4095 - 3852 4095 4095 - 3852 4095 4095 - 3852 4095 4095 - 3852 4095 4095 - 3852 4095 4095 - 3852 4095 4095 - 3852 4095 4095 - 3852 4095 4095 - 3852 4095 0 - 3852 4095 36 - 3852 4095 119 - 3852 4095 242 - 3852 4095 387 - 3852 4095 543 - 3852 4095 704 - 3852 4095 858 - 3852 4095 1006 - 3852 4095 1152 - 3852 4095 1303 - 3852 4095 1469 - 3852 4095 1656 - 3852 4095 1865 - 3852 4095 2102 - 3852 4095 2375 - 3852 4095 2677 - 3852 4095 2991 - 3852 4095 3295 - 3852 4095 3588 - 3852 4095 3852 - 3852 4095 4057 - 3852 4095 4095 - 3852 4095 4095 - 3852 4095 4095 - 3852 4095 4095 - 3852 4095 4095 - 3852 4095 4095 - 3852 4095 4095 - 3852 4095 4095 - 3852 4095 4095 - 3852 4095 4095 - 3852 4095 4095 - 3852 4095 0 - 3852 4095 36 - 3852 4095 119 - 3852 4095 242 - 3852 4095 387 - 3852 4095 543 - 3852 4095 704 - 3852 4095 858 - 3852 4095 1006 - 3852 4095 1152 - 3852 4095 1303 - 3852 4095 1469 - 3852 4095 1656 - 3852 4095 1865 - 3852 4095 2102 - 3852 4095 2375 - 3852 4095 2677 - 3852 4095 2991 - 3852 4095 3295 - 3852 4095 3588 - 3852 4095 3852 - 3852 4095 4057 - 3852 4095 4095 - 3852 4095 4095 - 3852 4095 4095 - 3852 4095 4095 - 3852 4095 4095 - 3852 4095 4095 - 3852 4095 4095 - 3852 4095 4095 - 3852 4095 4095 - 3852 4095 4095 - 3852 4095 4095 - 3852 4095 0 - 3852 4095 36 - 3852 4095 119 - 3852 4095 242 - 3852 4095 387 - 3852 4095 543 - 3852 4095 704 - 3852 4095 858 - 3852 4095 1006 - 3852 4095 1152 - 3852 4095 1303 - 3852 4095 1469 - 3852 4095 1656 - 3852 4095 1865 - 3852 4095 2102 - 3852 4095 2375 - 3852 4095 2677 - 3852 4095 2991 - 3852 4095 3295 - 3852 4095 3588 - 3852 4095 3852 - 3852 4095 4057 - 3852 4095 4095 - 3852 4095 4095 - 3852 4095 4095 - 3852 4095 4095 - 3852 4095 4095 - 3852 4095 4095 - 3852 4095 4095 - 3852 4095 4095 - 3852 4095 4095 - 3852 4095 4095 - 3852 4095 4095 - 3852 4095 0 - 3852 4095 36 - 3852 4095 119 - 3852 4095 242 - 3852 4095 387 - 3852 4095 543 - 3852 4095 704 - 3852 4095 858 - 3852 4095 1006 - 3852 4095 1152 - 3852 4095 1303 - 3852 4095 1469 - 3852 4095 1656 - 3852 4095 1865 - 3852 4095 2102 - 3852 4095 2375 - 3852 4095 2677 - 3852 4095 2991 - 3852 4095 3295 - 3852 4095 3588 - 3852 4095 3852 - 3852 4095 4057 - 3852 4095 4095 - 3852 4095 4095 - 3852 4095 4095 - 3852 4095 4095 - 3852 4095 4095 - 3852 4095 4095 - 3852 4095 4095 - 3852 4095 4095 - 3852 4095 4095 - 3852 4095 4095 - 3852 4095 4095 - 3852 4095 0 - 3852 4095 36 - 3852 4095 119 - 3852 4095 242 - 3852 4095 387 - 3852 4095 543 - 3852 4095 704 - 3852 4095 858 - 3852 4095 1006 - 3852 4095 1152 - 3852 4095 1303 - 3852 4095 1469 - 3852 4095 1656 - 3852 4095 1865 - 3852 4095 2102 - 3852 4095 2375 - 3852 4095 2677 - 3852 4095 2991 - 3852 4095 3295 - 3852 4095 3588 - 3852 4095 3852 - 3852 4095 4057 - 3852 4095 4095 - 3852 4095 4095 - 3852 4095 4095 - 3852 4095 4095 - 3852 4095 4095 - 3852 4095 4095 - 3852 4095 4095 - 3852 4095 4095 - 3852 4095 4095 - 3852 4095 4095 - 3852 4095 4095 - 3852 4095 0 - 3852 4095 36 - 3852 4095 119 - 3852 4095 242 - 3852 4095 387 - 3852 4095 543 - 3852 4095 704 - 3852 4095 858 - 3852 4095 1006 - 3852 4095 1152 - 3852 4095 1303 - 3852 4095 1469 - 3852 4095 1656 - 3852 4095 1865 - 3852 4095 2102 - 3852 4095 2375 - 3852 4095 2677 - 3852 4095 2991 - 3852 4095 3295 - 3852 4095 3588 - 3852 4095 3852 - 3852 4095 4057 - 3852 4095 4095 - 3852 4095 4095 - 3852 4095 4095 - 3852 4095 4095 - 3852 4095 4095 - 3852 4095 4095 - 3852 4095 4095 - 3852 4095 4095 - 3852 4095 4095 - 3852 4095 4095 - 3852 4095 4095 - 3852 4095 0 - 3852 4095 36 - 3852 4095 119 - 3852 4095 242 - 3852 4095 387 - 3852 4095 543 - 3852 4095 704 - 3852 4095 858 - 3852 4095 1006 - 3852 4095 1152 - 3852 4095 1303 - 3852 4095 1469 - 3852 4095 1656 - 3852 4095 1865 - 3852 4095 2102 - 3852 4095 2375 - 3852 4095 2677 - 3852 4095 2991 - 3852 4095 3295 - 3852 4095 3588 - 3852 4095 3852 - 3852 4095 4057 - 3852 4095 4095 - 3852 4095 4095 - 3852 4095 4095 - 3852 4095 4095 - 3852 4095 4095 - 3852 4095 4095 - 3852 4095 4095 - 3852 4095 4095 - 3852 4095 4095 - 3852 4095 4095 - 3852 4095 4095 - 3852 4095 0 - 3852 4095 36 - 3852 4095 119 - 3852 4095 242 - 3852 4095 387 - 3852 4095 543 - 3852 4095 704 - 3852 4095 858 - 3852 4095 1006 - 3852 4095 1152 - 3852 4095 1303 - 3852 4095 1469 - 3852 4095 1656 - 3852 4095 1865 - 3852 4095 2102 - 3852 4095 2375 - 3852 4095 2677 - 3852 4095 2991 - 3852 4095 3295 - 3852 4095 3588 - 3852 4095 3852 - 3852 4095 4057 - 3852 4095 4095 - 3852 4095 4095 - 3852 4095 4095 - 3852 4095 4095 - 3852 4095 4095 - 3852 4095 4095 - 3852 4095 4095 - 3852 4095 4095 - 3852 4095 4095 - 3852 4095 4095 - 3852 4095 4095 - 4075 3 0 - 4075 3 99 - 4075 3 209 - 4075 2 334 - 4075 2 470 - 4075 3 615 - 4075 4 762 - 4075 3 908 - 4075 2 1050 - 4075 2 1193 - 4075 2 1338 - 4075 0 1500 - 4074 2 1681 - 4074 2 1883 - 4074 3 2111 - 4074 3 2371 - 4073 3 2661 - 4073 2 2971 - 4072 3 3288 - 4071 0 3612 - 4070 1 3919 - 4069 2 4069 - 4068 3 4095 - 4066 1 4095 - 4064 2 4095 - 4062 2 4095 - 4060 3 4095 - 4058 1 4095 - 4057 0 4095 - 4057 0 4095 - 4057 0 4095 - 4057 0 4095 - 4057 0 4095 - 4075 99 2 - 4075 99 99 - 4075 99 209 - 4075 99 334 - 4075 99 470 - 4075 99 615 - 4075 99 762 - 4075 99 908 - 4075 99 1050 - 4075 98 1193 - 4075 98 1338 - 4074 98 1500 - 4074 98 1681 - 4074 97 1883 - 4074 97 2111 - 4074 96 2372 - 4073 95 2661 - 4073 94 2971 - 4072 93 3288 - 4071 91 3612 - 4070 89 3919 - 4069 86 4069 - 4068 82 4095 - 4066 77 4095 - 4064 70 4095 - 4062 61 4095 - 4060 51 4095 - 4058 40 4095 - 4057 36 4095 - 4057 36 4095 - 4057 36 4095 - 4057 36 4095 - 4057 36 4095 - 4075 208 1 - 4075 208 99 - 4075 208 208 - 4075 208 333 - 4075 208 470 - 4075 208 614 - 4075 208 762 - 4075 208 908 - 4075 208 1050 - 4075 207 1193 - 4074 207 1338 - 4074 207 1500 - 4074 206 1681 - 4074 205 1884 - 4074 205 2111 - 4073 203 2372 - 4073 202 2661 - 4073 200 2971 - 4072 198 3289 - 4071 195 3612 - 4070 191 3918 - 4069 187 4069 - 4068 180 4095 - 4066 172 4095 - 4064 162 4095 - 4062 150 4095 - 4060 136 4095 - 4058 123 4095 - 4057 119 4095 - 4057 119 4095 - 4057 119 4095 - 4057 119 4095 - 4057 119 4095 - 4075 333 1 - 4075 333 99 - 4075 333 208 - 4075 333 333 - 4075 332 469 - 4075 332 614 - 4075 332 762 - 4075 332 908 - 4074 332 1050 - 4074 331 1193 - 4074 331 1338 - 4074 331 1500 - 4074 330 1681 - 4074 329 1884 - 4074 328 2112 - 4073 327 2373 - 4073 326 2662 - 4072 324 2972 - 4072 321 3289 - 4071 318 3612 - 4070 314 3918 - 4069 309 4069 - 4067 302 4095 - 4066 293 4095 - 4064 282 4095 - 4062 270 4095 - 4060 256 4095 - 4058 245 4095 - 4057 242 4095 - 4057 242 4095 - 4057 242 4095 - 4057 242 4095 - 4057 242 4095 - 4074 469 2 - 4074 469 98 - 4074 468 207 - 4074 468 332 - 4074 468 468 - 4074 468 613 - 4074 468 761 - 4074 468 907 - 4074 468 1050 - 4074 467 1192 - 4074 467 1338 - 4074 467 1501 - 4074 466 1682 - 4074 465 1884 - 4073 465 2113 - 4073 463 2373 - 4073 462 2663 - 4072 460 2974 - 4071 458 3291 - 4071 455 3613 - 4070 451 3917 - 4069 446 4068 - 4067 440 4095 - 4066 432 4095 - 4064 422 4095 - 4062 410 4095 - 4059 398 4095 - 4058 389 4095 - 4057 387 4095 - 4057 387 4095 - 4057 387 4095 - 4057 387 4095 - 4057 387 4095 - 4074 612 3 - 4074 612 97 - 4074 612 206 - 4074 612 330 - 4074 612 467 - 4074 612 612 - 4074 612 760 - 4074 612 907 - 4074 612 1050 - 4074 611 1192 - 4074 611 1338 - 4073 611 1501 - 4073 610 1682 - 4073 610 1885 - 4073 609 2113 - 4073 608 2375 - 4072 607 2665 - 4072 605 2975 - 4071 603 3292 - 4070 601 3613 - 4069 598 3915 - 4068 593 4068 - 4067 588 4095 - 4065 581 4095 - 4063 572 4095 - 4061 562 4095 - 4059 552 4095 - 4058 545 4095 - 4057 543 4095 - 4057 543 4095 - 4057 543 4095 - 4057 543 4095 - 4057 543 4095 - 4074 760 3 - 4074 760 96 - 4074 760 204 - 4074 760 328 - 4074 760 465 - 4073 760 611 - 4073 759 759 - 4073 759 906 - 4073 759 1049 - 4073 759 1192 - 4073 759 1338 - 4073 759 1501 - 4073 758 1682 - 4073 758 1885 - 4072 757 2114 - 4072 757 2376 - 4072 756 2667 - 4071 754 2977 - 4071 753 3293 - 4070 751 3614 - 4069 748 3914 - 4068 744 4068 - 4067 740 4095 - 4065 734 4095 - 4063 727 4095 - 4061 718 4095 - 4059 710 4095 - 4058 705 4095 - 4057 704 4095 - 4057 704 4095 - 4057 704 4095 - 4057 704 4095 - 4057 704 4095 - 4073 906 3 - 4073 906 95 - 4073 906 202 - 4073 906 326 - 4073 905 463 - 4073 905 609 - 4073 905 758 - 4073 905 905 - 4073 905 1048 - 4073 905 1191 - 4073 905 1338 - 4072 905 1501 - 4072 904 1683 - 4072 904 1886 - 4072 904 2115 - 4072 903 2378 - 4071 902 2669 - 4071 901 2979 - 4070 900 3295 - 4069 898 3614 - 4068 896 3911 - 4067 893 4067 - 4066 889 4095 - 4064 884 4095 - 4063 877 4095 - 4061 870 4095 - 4059 863 4095 - 4057 859 4095 - 4057 858 4095 - 4057 858 4095 - 4057 858 4095 - 4057 858 4095 - 4057 858 4095 - 4072 1048 2 - 4072 1048 93 - 4072 1048 199 - 4072 1048 323 - 4072 1048 461 - 4072 1048 607 - 4072 1048 757 - 4072 1048 904 - 4072 1048 1048 - 4072 1048 1191 - 4072 1047 1338 - 4072 1047 1501 - 4072 1047 1683 - 4071 1047 1887 - 4071 1046 2116 - 4071 1046 2379 - 4071 1045 2671 - 4070 1044 2982 - 4069 1043 3297 - 4069 1042 3615 - 4068 1039 3909 - 4067 1037 4067 - 4065 1033 4095 - 4064 1028 4095 - 4062 1022 4095 - 4060 1016 4095 - 4059 1010 4095 - 4057 1006 4095 - 4057 1006 4095 - 4057 1006 4095 - 4057 1006 4095 - 4057 1006 4095 - 4057 1006 4095 - 4072 1190 2 - 4072 1190 92 - 4072 1190 196 - 4071 1190 320 - 4071 1190 458 - 4071 1190 604 - 4071 1190 755 - 4071 1190 903 - 4071 1190 1046 - 4071 1190 1190 - 4071 1190 1337 - 4071 1190 1500 - 4071 1189 1683 - 4071 1189 1887 - 4070 1189 2117 - 4070 1188 2380 - 4070 1188 2673 - 4069 1187 2984 - 4069 1186 3298 - 4068 1184 3614 - 4067 1182 3906 - 4066 1180 4066 - 4065 1176 4095 - 4063 1171 4095 - 4062 1166 4095 - 4060 1160 4095 - 4058 1155 4095 - 4057 1152 4095 - 4057 1152 4095 - 4057 1152 4095 - 4057 1152 4095 - 4057 1152 4095 - 4057 1152 4095 - 4071 1337 2 - 4071 1337 89 - 4071 1337 193 - 4071 1336 316 - 4071 1336 454 - 4071 1336 601 - 4070 1336 752 - 4070 1336 901 - 4070 1336 1045 - 4070 1336 1189 - 4070 1336 1336 - 4070 1336 1500 - 4070 1336 1682 - 4070 1335 1887 - 4070 1335 2118 - 4069 1335 2382 - 4069 1334 2675 - 4068 1333 2986 - 4068 1332 3300 - 4067 1331 3614 - 4066 1329 3902 - 4065 1326 4065 - 4064 1323 4095 - 4063 1319 4095 - 4061 1314 4095 - 4059 1309 4095 - 4058 1304 4095 - 4057 1303 4095 - 4057 1303 4095 - 4057 1303 4095 - 4057 1303 4095 - 4057 1303 4095 - 4057 1303 4095 - 4069 1499 2 - 4069 1499 86 - 4069 1499 188 - 4069 1499 311 - 4069 1499 449 - 4069 1499 597 - 4069 1499 749 - 4069 1499 898 - 4069 1499 1043 - 4069 1499 1187 - 4069 1498 1334 - 4069 1498 1498 - 4069 1498 1682 - 4069 1498 1886 - 4068 1498 2118 - 4068 1497 2383 - 4068 1497 2677 - 4067 1496 2988 - 4067 1495 3301 - 4066 1493 3613 - 4065 1492 3897 - 4064 1489 4064 - 4063 1486 4095 - 4062 1482 4095 - 4060 1478 4095 - 4059 1474 4095 - 4058 1470 4095 - 4057 1469 4095 - 4057 1469 4095 - 4057 1469 4095 - 4057 1469 4095 - 4057 1469 4095 - 4057 1469 4095 - 4068 1681 1 - 4068 1681 83 - 4068 1681 183 - 4068 1681 305 - 4068 1681 443 - 4068 1681 592 - 4068 1681 745 - 4068 1681 894 - 4068 1680 1039 - 4068 1680 1184 - 4068 1680 1332 - 4068 1680 1496 - 4067 1680 1680 - 4067 1680 1885 - 4067 1679 2117 - 4067 1679 2383 - 4067 1678 2678 - 4066 1678 2990 - 4066 1677 3301 - 4065 1675 3610 - 4064 1674 3891 - 4063 1671 4063 - 4062 1669 4095 - 4061 1665 4095 - 4060 1662 4095 - 4058 1658 4095 - 4057 1656 4095 - 4057 1656 4095 - 4057 1656 4095 - 4057 1656 4095 - 4057 1656 4095 - 4057 1656 4095 - 4057 1656 4095 - 4066 1884 2 - 4066 1884 78 - 4066 1884 175 - 4066 1884 297 - 4066 1884 436 - 4066 1884 586 - 4066 1884 739 - 4066 1884 890 - 4066 1884 1035 - 4066 1884 1180 - 4066 1884 1328 - 4066 1884 1493 - 4066 1883 1677 - 4066 1883 1883 - 4066 1883 2116 - 4065 1882 2383 - 4065 1882 2679 - 4065 1881 2991 - 4064 1880 3301 - 4064 1879 3607 - 4063 1877 3883 - 4062 1876 4062 - 4061 1873 4095 - 4060 1871 4095 - 4059 1868 4095 - 4058 1866 4095 - 4057 1865 4095 - 4057 1865 4095 - 4057 1865 4095 - 4057 1865 4095 - 4057 1865 4095 - 4057 1865 4095 - 4057 1865 4095 - 4065 2114 3 - 4065 2114 72 - 4065 2114 165 - 4065 2114 287 - 4065 2114 426 - 4065 2114 577 - 4064 2114 732 - 4064 2114 884 - 4064 2114 1029 - 4064 2114 1174 - 4064 2114 1323 - 4064 2114 1488 - 4064 2114 1673 - 4064 2113 1880 - 4064 2113 2113 - 4064 2113 2382 - 4063 2112 2679 - 4063 2112 2992 - 4062 2111 3300 - 4062 2110 3602 - 4061 2109 3875 - 4061 2107 4061 - 4060 2106 4095 - 4059 2104 4095 - 4058 2103 4095 - 4057 2102 4095 - 4057 2102 4095 - 4057 2102 4095 - 4057 2102 4095 - 4057 2102 4095 - 4057 2102 4095 - 4057 2102 4095 - 4057 2102 4095 - 4062 2381 2 - 4062 2381 64 - 4062 2381 153 - 4062 2381 274 - 4062 2381 415 - 4062 2381 567 - 4062 2381 724 - 4062 2381 876 - 4062 2380 1022 - 4062 2380 1168 - 4062 2380 1317 - 4062 2380 1483 - 4062 2380 1668 - 4062 2380 1875 - 4062 2380 2109 - 4062 2380 2379 - 4061 2379 2678 - 4061 2379 2991 - 4061 2378 3298 - 4060 2378 3596 - 4060 2377 3865 - 4059 2377 4059 - 4059 2376 4095 - 4058 2376 4095 - 4057 2375 4095 - 4057 2375 4095 - 4057 2375 4095 - 4057 2375 4095 - 4057 2375 4095 - 4057 2375 4095 - 4057 2375 4095 - 4057 2375 4095 - 4057 2375 4095 - 4060 2677 2 - 4060 2677 53 - 4060 2677 140 - 4060 2677 260 - 4060 2677 402 - 4060 2677 557 - 4060 2677 715 - 4060 2677 868 - 4060 2677 1015 - 4060 2677 1161 - 4060 2677 1310 - 4060 2677 1476 - 4060 2677 1662 - 4060 2677 1870 - 4060 2677 2105 - 4060 2677 2377 - 4059 2677 2677 - 4059 2677 2991 - 4059 2677 3296 - 4059 2677 3591 - 4058 2677 3857 - 4058 2677 4058 - 4058 2677 4095 - 4057 2677 4095 - 4057 2677 4095 - 4057 2677 4095 - 4057 2677 4095 - 4057 2677 4095 - 4057 2677 4095 - 4057 2677 4095 - 4057 2677 4095 - 4057 2677 4095 - 4057 2677 4095 - 4058 2991 0 - 4058 2991 42 - 4058 2991 126 - 4058 2991 248 - 4058 2991 391 - 4058 2991 547 - 4058 2991 707 - 4058 2991 861 - 4058 2991 1008 - 4058 2991 1155 - 4058 2991 1305 - 4058 2991 1471 - 4058 2991 1658 - 4058 2991 1866 - 4058 2991 2102 - 4058 2991 2375 - 4058 2991 2677 - 4058 2991 2991 - 4058 2991 3295 - 4057 2991 3588 - 4057 2991 3852 - 4057 2991 4057 - 4057 2991 4095 - 4057 2991 4095 - 4057 2991 4095 - 4057 2991 4095 - 4057 2991 4095 - 4057 2991 4095 - 4057 2991 4095 - 4057 2991 4095 - 4057 2991 4095 - 4057 2991 4095 - 4057 2991 4095 - 4057 3295 1 - 4057 3295 37 - 4057 3295 120 - 4057 3295 242 - 4057 3295 387 - 4057 3295 543 - 4057 3295 704 - 4057 3295 859 - 4057 3295 1006 - 4057 3295 1152 - 4057 3295 1303 - 4057 3295 1469 - 4057 3295 1656 - 4057 3295 1865 - 4057 3295 2102 - 4057 3295 2375 - 4057 3295 2677 - 4057 3295 2991 - 4057 3295 3295 - 4057 3295 3588 - 4057 3295 3852 - 4057 3295 4057 - 4057 3295 4095 - 4057 3295 4095 - 4057 3295 4095 - 4057 3295 4095 - 4057 3295 4095 - 4057 3295 4095 - 4057 3295 4095 - 4057 3295 4095 - 4057 3295 4095 - 4057 3295 4095 - 4057 3295 4095 - 4057 3588 0 - 4057 3588 36 - 4057 3588 119 - 4057 3588 242 - 4057 3588 387 - 4057 3588 543 - 4057 3588 704 - 4057 3588 858 - 4057 3588 1006 - 4057 3588 1152 - 4057 3588 1303 - 4057 3588 1469 - 4057 3588 1656 - 4057 3588 1865 - 4057 3588 2102 - 4057 3588 2375 - 4057 3588 2677 - 4057 3588 2991 - 4057 3588 3295 - 4057 3588 3588 - 4057 3588 3852 - 4057 3588 4057 - 4057 3588 4095 - 4057 3588 4095 - 4057 3588 4095 - 4057 3588 4095 - 4057 3588 4095 - 4057 3588 4095 - 4057 3588 4095 - 4057 3588 4095 - 4057 3588 4095 - 4057 3588 4095 - 4057 3588 4095 - 4057 3852 0 - 4057 3852 36 - 4057 3852 119 - 4057 3852 242 - 4057 3852 387 - 4057 3852 543 - 4057 3852 704 - 4057 3852 858 - 4057 3852 1006 - 4057 3852 1152 - 4057 3852 1303 - 4057 3852 1469 - 4057 3852 1656 - 4057 3852 1865 - 4057 3852 2102 - 4057 3852 2375 - 4057 3852 2677 - 4057 3852 2991 - 4057 3852 3295 - 4057 3852 3588 - 4057 3852 3852 - 4057 3852 4057 - 4057 3852 4095 - 4057 3852 4095 - 4057 3852 4095 - 4057 3852 4095 - 4057 3852 4095 - 4057 3852 4095 - 4057 3852 4095 - 4057 3852 4095 - 4057 3852 4095 - 4057 3852 4095 - 4057 3852 4095 - 4057 4057 0 - 4057 4057 36 - 4057 4057 119 - 4057 4057 242 - 4057 4057 387 - 4057 4057 543 - 4057 4057 704 - 4057 4057 858 - 4057 4057 1006 - 4057 4057 1152 - 4057 4057 1303 - 4057 4057 1469 - 4057 4057 1656 - 4057 4057 1865 - 4057 4057 2102 - 4057 4057 2375 - 4057 4057 2677 - 4057 4057 2991 - 4057 4057 3295 - 4057 4057 3588 - 4057 4057 3852 - 4057 4057 4057 - 4057 4057 4095 - 4057 4057 4095 - 4057 4057 4095 - 4057 4057 4095 - 4057 4057 4095 - 4057 4057 4095 - 4057 4057 4095 - 4057 4057 4095 - 4057 4057 4095 - 4057 4057 4095 - 4057 4057 4095 - 4057 4095 0 - 4057 4095 36 - 4057 4095 119 - 4057 4095 242 - 4057 4095 387 - 4057 4095 543 - 4057 4095 704 - 4057 4095 858 - 4057 4095 1006 - 4057 4095 1152 - 4057 4095 1303 - 4057 4095 1469 - 4057 4095 1656 - 4057 4095 1865 - 4057 4095 2102 - 4057 4095 2375 - 4057 4095 2677 - 4057 4095 2991 - 4057 4095 3295 - 4057 4095 3588 - 4057 4095 3852 - 4057 4095 4057 - 4057 4095 4095 - 4057 4095 4095 - 4057 4095 4095 - 4057 4095 4095 - 4057 4095 4095 - 4057 4095 4095 - 4057 4095 4095 - 4057 4095 4095 - 4057 4095 4095 - 4057 4095 4095 - 4057 4095 4095 - 4057 4095 0 - 4057 4095 36 - 4057 4095 119 - 4057 4095 242 - 4057 4095 387 - 4057 4095 543 - 4057 4095 704 - 4057 4095 858 - 4057 4095 1006 - 4057 4095 1152 - 4057 4095 1303 - 4057 4095 1469 - 4057 4095 1656 - 4057 4095 1865 - 4057 4095 2102 - 4057 4095 2375 - 4057 4095 2677 - 4057 4095 2991 - 4057 4095 3295 - 4057 4095 3588 - 4057 4095 3852 - 4057 4095 4057 - 4057 4095 4095 - 4057 4095 4095 - 4057 4095 4095 - 4057 4095 4095 - 4057 4095 4095 - 4057 4095 4095 - 4057 4095 4095 - 4057 4095 4095 - 4057 4095 4095 - 4057 4095 4095 - 4057 4095 4095 - 4057 4095 0 - 4057 4095 36 - 4057 4095 119 - 4057 4095 242 - 4057 4095 387 - 4057 4095 543 - 4057 4095 704 - 4057 4095 858 - 4057 4095 1006 - 4057 4095 1152 - 4057 4095 1303 - 4057 4095 1469 - 4057 4095 1656 - 4057 4095 1865 - 4057 4095 2102 - 4057 4095 2375 - 4057 4095 2677 - 4057 4095 2991 - 4057 4095 3295 - 4057 4095 3588 - 4057 4095 3852 - 4057 4095 4057 - 4057 4095 4095 - 4057 4095 4095 - 4057 4095 4095 - 4057 4095 4095 - 4057 4095 4095 - 4057 4095 4095 - 4057 4095 4095 - 4057 4095 4095 - 4057 4095 4095 - 4057 4095 4095 - 4057 4095 4095 - 4057 4095 0 - 4057 4095 36 - 4057 4095 119 - 4057 4095 242 - 4057 4095 387 - 4057 4095 543 - 4057 4095 704 - 4057 4095 858 - 4057 4095 1006 - 4057 4095 1152 - 4057 4095 1303 - 4057 4095 1469 - 4057 4095 1656 - 4057 4095 1865 - 4057 4095 2102 - 4057 4095 2375 - 4057 4095 2677 - 4057 4095 2991 - 4057 4095 3295 - 4057 4095 3588 - 4057 4095 3852 - 4057 4095 4057 - 4057 4095 4095 - 4057 4095 4095 - 4057 4095 4095 - 4057 4095 4095 - 4057 4095 4095 - 4057 4095 4095 - 4057 4095 4095 - 4057 4095 4095 - 4057 4095 4095 - 4057 4095 4095 - 4057 4095 4095 - 4057 4095 0 - 4057 4095 36 - 4057 4095 119 - 4057 4095 242 - 4057 4095 387 - 4057 4095 543 - 4057 4095 704 - 4057 4095 858 - 4057 4095 1006 - 4057 4095 1152 - 4057 4095 1303 - 4057 4095 1469 - 4057 4095 1656 - 4057 4095 1865 - 4057 4095 2102 - 4057 4095 2375 - 4057 4095 2677 - 4057 4095 2991 - 4057 4095 3295 - 4057 4095 3588 - 4057 4095 3852 - 4057 4095 4057 - 4057 4095 4095 - 4057 4095 4095 - 4057 4095 4095 - 4057 4095 4095 - 4057 4095 4095 - 4057 4095 4095 - 4057 4095 4095 - 4057 4095 4095 - 4057 4095 4095 - 4057 4095 4095 - 4057 4095 4095 - 4057 4095 0 - 4057 4095 36 - 4057 4095 119 - 4057 4095 242 - 4057 4095 387 - 4057 4095 543 - 4057 4095 704 - 4057 4095 858 - 4057 4095 1006 - 4057 4095 1152 - 4057 4095 1303 - 4057 4095 1469 - 4057 4095 1656 - 4057 4095 1865 - 4057 4095 2102 - 4057 4095 2375 - 4057 4095 2677 - 4057 4095 2991 - 4057 4095 3295 - 4057 4095 3588 - 4057 4095 3852 - 4057 4095 4057 - 4057 4095 4095 - 4057 4095 4095 - 4057 4095 4095 - 4057 4095 4095 - 4057 4095 4095 - 4057 4095 4095 - 4057 4095 4095 - 4057 4095 4095 - 4057 4095 4095 - 4057 4095 4095 - 4057 4095 4095 - 4057 4095 0 - 4057 4095 36 - 4057 4095 119 - 4057 4095 242 - 4057 4095 387 - 4057 4095 543 - 4057 4095 704 - 4057 4095 858 - 4057 4095 1006 - 4057 4095 1152 - 4057 4095 1303 - 4057 4095 1469 - 4057 4095 1656 - 4057 4095 1865 - 4057 4095 2102 - 4057 4095 2375 - 4057 4095 2677 - 4057 4095 2991 - 4057 4095 3295 - 4057 4095 3588 - 4057 4095 3852 - 4057 4095 4057 - 4057 4095 4095 - 4057 4095 4095 - 4057 4095 4095 - 4057 4095 4095 - 4057 4095 4095 - 4057 4095 4095 - 4057 4095 4095 - 4057 4095 4095 - 4057 4095 4095 - 4057 4095 4095 - 4057 4095 4095 - 4057 4095 0 - 4057 4095 36 - 4057 4095 119 - 4057 4095 242 - 4057 4095 387 - 4057 4095 543 - 4057 4095 704 - 4057 4095 858 - 4057 4095 1006 - 4057 4095 1152 - 4057 4095 1303 - 4057 4095 1469 - 4057 4095 1656 - 4057 4095 1865 - 4057 4095 2102 - 4057 4095 2375 - 4057 4095 2677 - 4057 4095 2991 - 4057 4095 3295 - 4057 4095 3588 - 4057 4095 3852 - 4057 4095 4057 - 4057 4095 4095 - 4057 4095 4095 - 4057 4095 4095 - 4057 4095 4095 - 4057 4095 4095 - 4057 4095 4095 - 4057 4095 4095 - 4057 4095 4095 - 4057 4095 4095 - 4057 4095 4095 - 4057 4095 4095 - 4057 4095 0 - 4057 4095 36 - 4057 4095 119 - 4057 4095 242 - 4057 4095 387 - 4057 4095 543 - 4057 4095 704 - 4057 4095 858 - 4057 4095 1006 - 4057 4095 1152 - 4057 4095 1303 - 4057 4095 1469 - 4057 4095 1656 - 4057 4095 1865 - 4057 4095 2102 - 4057 4095 2375 - 4057 4095 2677 - 4057 4095 2991 - 4057 4095 3295 - 4057 4095 3588 - 4057 4095 3852 - 4057 4095 4057 - 4057 4095 4095 - 4057 4095 4095 - 4057 4095 4095 - 4057 4095 4095 - 4057 4095 4095 - 4057 4095 4095 - 4057 4095 4095 - 4057 4095 4095 - 4057 4095 4095 - 4057 4095 4095 - 4057 4095 4095 - 4057 4095 0 - 4057 4095 36 - 4057 4095 119 - 4057 4095 242 - 4057 4095 387 - 4057 4095 543 - 4057 4095 704 - 4057 4095 858 - 4057 4095 1006 - 4057 4095 1152 - 4057 4095 1303 - 4057 4095 1469 - 4057 4095 1656 - 4057 4095 1865 - 4057 4095 2102 - 4057 4095 2375 - 4057 4095 2677 - 4057 4095 2991 - 4057 4095 3295 - 4057 4095 3588 - 4057 4095 3852 - 4057 4095 4057 - 4057 4095 4095 - 4057 4095 4095 - 4057 4095 4095 - 4057 4095 4095 - 4057 4095 4095 - 4057 4095 4095 - 4057 4095 4095 - 4057 4095 4095 - 4057 4095 4095 - 4057 4095 4095 - 4057 4095 4095 - 4057 4095 0 - 4057 4095 36 - 4057 4095 119 - 4057 4095 242 - 4057 4095 387 - 4057 4095 543 - 4057 4095 704 - 4057 4095 858 - 4057 4095 1006 - 4057 4095 1152 - 4057 4095 1303 - 4057 4095 1469 - 4057 4095 1656 - 4057 4095 1865 - 4057 4095 2102 - 4057 4095 2375 - 4057 4095 2677 - 4057 4095 2991 - 4057 4095 3295 - 4057 4095 3588 - 4057 4095 3852 - 4057 4095 4057 - 4057 4095 4095 - 4057 4095 4095 - 4057 4095 4095 - 4057 4095 4095 - 4057 4095 4095 - 4057 4095 4095 - 4057 4095 4095 - 4057 4095 4095 - 4057 4095 4095 - 4057 4095 4095 - 4057 4095 4095 - 4095 0 2 - 4095 0 89 - 4095 2 192 - 4095 2 315 - 4095 1 453 - 4095 2 601 - 4095 2 752 - 4095 0 900 - 4095 2 1044 - 4095 3 1188 - 4095 0 1336 - 4095 1 1499 - 4095 3 1682 - 4095 2 1887 - 4095 0 2118 - 4095 0 2382 - 4095 1 2675 - 4095 1 2987 - 4095 1 3300 - 4095 2 3614 - 4095 2 3901 - 4095 3 4065 - 4095 2 4095 - 4095 1 4095 - 4095 3 4095 - 4095 0 4095 - 4095 2 4095 - 4095 0 4095 - 4095 0 4095 - 4095 0 4095 - 4095 0 4095 - 4095 0 4095 - 4095 0 4095 - 4095 89 1 - 4095 89 89 - 4095 89 192 - 4095 89 315 - 4095 89 453 - 4095 89 601 - 4095 88 752 - 4095 88 900 - 4095 88 1044 - 4095 88 1188 - 4095 88 1336 - 4095 87 1499 - 4095 87 1682 - 4095 87 1887 - 4095 86 2118 - 4095 85 2382 - 4095 84 2675 - 4095 83 2987 - 4095 82 3300 - 4095 80 3614 - 4095 77 3901 - 4095 74 4065 - 4095 69 4095 - 4095 64 4095 - 4095 57 4095 - 4095 49 4095 - 4095 41 4095 - 4095 36 4095 - 4095 36 4095 - 4095 36 4095 - 4095 36 4095 - 4095 36 4095 - 4095 36 4095 - 4095 192 2 - 4095 192 89 - 4095 192 192 - 4095 192 315 - 4095 191 453 - 4095 191 600 - 4095 191 751 - 4095 191 900 - 4095 191 1044 - 4095 190 1188 - 4095 190 1336 - 4095 190 1499 - 4095 189 1682 - 4095 188 1887 - 4095 187 2118 - 4095 186 2382 - 4095 185 2675 - 4095 183 2987 - 4095 180 3300 - 4095 177 3614 - 4095 173 3901 - 4095 168 4065 - 4095 162 4095 - 4095 154 4095 - 4095 144 4095 - 4095 134 4095 - 4095 124 4095 - 4095 120 4095 - 4095 119 4095 - 4095 119 4095 - 4095 119 4095 - 4095 119 4095 - 4095 119 4095 - 4095 314 3 - 4095 314 88 - 4095 314 191 - 4095 314 314 - 4095 314 452 - 4095 314 600 - 4095 314 751 - 4095 313 900 - 4095 313 1044 - 4095 313 1188 - 4095 312 1335 - 4095 312 1499 - 4095 311 1682 - 4095 310 1887 - 4095 309 2118 - 4095 308 2382 - 4095 306 2676 - 4095 304 2987 - 4095 302 3300 - 4095 298 3613 - 4095 294 3900 - 4095 289 4065 - 4095 282 4095 - 4095 274 4095 - 4095 264 4095 - 4095 254 4095 - 4095 245 4095 - 4095 242 4095 - 4095 242 4095 - 4095 242 4095 - 4095 242 4095 - 4095 242 4095 - 4095 242 4095 - 4095 451 3 - 4095 451 87 - 4095 451 190 - 4095 451 313 - 4095 451 451 - 4095 451 599 - 4095 451 750 - 4095 450 899 - 4095 450 1043 - 4095 450 1187 - 4095 449 1335 - 4095 449 1499 - 4095 448 1682 - 4095 448 1887 - 4095 447 2118 - 4095 445 2382 - 4095 444 2676 - 4095 442 2988 - 4095 439 3301 - 4095 436 3613 - 4095 432 3899 - 4095 427 4064 - 4095 421 4095 - 4095 414 4095 - 4095 405 4095 - 4095 397 4095 - 4095 389 4095 - 4095 387 4095 - 4095 387 4095 - 4095 387 4095 - 4095 387 4095 - 4095 387 4095 - 4095 387 4095 - 4095 598 3 - 4095 598 86 - 4095 598 188 - 4095 598 311 - 4095 598 449 - 4095 597 597 - 4095 597 749 - 4095 597 898 - 4095 597 1043 - 4095 597 1187 - 4095 596 1334 - 4095 596 1498 - 4095 595 1682 - 4095 595 1886 - 4095 594 2118 - 4095 593 2383 - 4095 591 2677 - 4095 590 2988 - 4095 588 3301 - 4095 585 3613 - 4095 581 3897 - 4095 577 4064 - 4095 572 4095 - 4095 565 4095 - 4095 558 4095 - 4095 551 4095 - 4095 545 4095 - 4095 543 4095 - 4095 543 4095 - 4095 543 4095 - 4095 543 4095 - 4095 543 4095 - 4095 543 4095 - 4095 748 2 - 4095 748 85 - 4095 748 187 - 4095 748 309 - 4095 748 448 - 4095 748 596 - 4095 748 748 - 4095 748 897 - 4095 747 1042 - 4095 747 1186 - 4095 747 1334 - 4095 747 1498 - 4095 746 1681 - 4095 746 1886 - 4095 745 2118 - 4095 744 2383 - 4095 743 2677 - 4095 742 2989 - 4095 740 3301 - 4095 737 3612 - 4095 734 3895 - 4095 731 4064 - 4095 726 4095 - 4095 721 4095 - 4095 715 4095 - 4095 709 4095 - 4095 705 4095 - 4095 704 4095 - 4095 704 4095 - 4095 704 4095 - 4095 704 4095 - 4095 704 4095 - 4095 704 4095 - 4095 896 2 - 4095 896 84 - 4095 896 184 - 4095 896 307 - 4095 896 445 - 4095 896 594 - 4095 896 746 - 4095 896 896 - 4095 895 1040 - 4095 895 1185 - 4095 895 1333 - 4095 895 1497 - 4095 894 1680 - 4095 894 1886 - 4095 893 2117 - 4095 893 2383 - 4095 892 2678 - 4095 890 2990 - 4095 889 3301 - 4095 887 3611 - 4095 884 3893 - 4095 881 4063 - 4095 877 4095 - 4095 872 4095 - 4095 867 4095 - 4095 863 4095 - 4095 859 4095 - 4095 858 4095 - 4095 858 4095 - 4095 858 4095 - 4095 858 4095 - 4095 858 4095 - 4095 858 4095 - 4095 1039 3 - 4095 1039 82 - 4095 1039 182 - 4095 1039 304 - 4095 1039 442 - 4095 1039 591 - 4095 1039 744 - 4095 1039 894 - 4095 1039 1039 - 4095 1039 1183 - 4095 1038 1331 - 4095 1038 1496 - 4095 1038 1680 - 4095 1037 1885 - 4095 1037 2117 - 4095 1036 2383 - 4095 1035 2678 - 4095 1034 2990 - 4095 1033 3301 - 4095 1031 3610 - 4095 1028 3890 - 4095 1025 4063 - 4095 1022 4095 - 4095 1018 4095 - 4095 1013 4095 - 4095 1009 4095 - 4095 1006 4095 - 4095 1006 4095 - 4095 1006 4095 - 4095 1006 4095 - 4095 1006 4095 - 4095 1006 4095 - 4095 1006 4095 - 4095 1182 4 - 4095 1182 80 - 4095 1182 178 - 4095 1182 300 - 4095 1182 439 - 4095 1182 589 - 4095 1182 742 - 4095 1182 892 - 4095 1182 1037 - 4095 1182 1182 - 4095 1181 1330 - 4095 1181 1494 - 4095 1181 1678 - 4095 1180 1884 - 4095 1180 2116 - 4095 1179 2383 - 4095 1178 2679 - 4095 1177 2991 - 4095 1176 3301 - 4095 1174 3608 - 4095 1172 3887 - 4095 1169 4062 - 4095 1166 4095 - 4095 1162 4095 - 4095 1158 4095 - 4095 1154 4095 - 4095 1152 4095 - 4095 1152 4095 - 4095 1152 4095 - 4095 1152 4095 - 4095 1152 4095 - 4095 1152 4095 - 4095 1152 4095 - 4095 1329 3 - 4095 1329 78 - 4095 1329 175 - 4095 1329 296 - 4095 1329 435 - 4095 1329 585 - 4095 1329 739 - 4095 1329 890 - 4095 1328 1035 - 4095 1328 1180 - 4095 1328 1328 - 4095 1328 1493 - 4095 1327 1677 - 4095 1327 1883 - 4095 1327 2116 - 4095 1326 2383 - 4095 1325 2679 - 4095 1324 2991 - 4095 1323 3301 - 4095 1321 3606 - 4095 1319 3883 - 4095 1317 4062 - 4095 1314 4095 - 4095 1310 4095 - 4095 1307 4095 - 4095 1304 4095 - 4095 1303 4095 - 4095 1303 4095 - 4095 1303 4095 - 4095 1303 4095 - 4095 1303 4095 - 4095 1303 4095 - 4095 1303 4095 - 4095 1492 3 - 4095 1492 75 - 4095 1492 170 - 4095 1492 291 - 4095 1492 431 - 4095 1491 581 - 4095 1491 736 - 4095 1491 886 - 4095 1491 1032 - 4095 1491 1177 - 4095 1491 1326 - 4095 1491 1491 - 4095 1490 1675 - 4095 1490 1881 - 4095 1489 2114 - 4095 1489 2382 - 4095 1488 2679 - 4095 1487 2992 - 4095 1486 3300 - 4095 1484 3604 - 4095 1483 3879 - 4095 1480 4061 - 4095 1478 4095 - 4095 1475 4095 - 4095 1472 4095 - 4095 1470 4095 - 4095 1469 4095 - 4095 1469 4095 - 4095 1469 4095 - 4095 1469 4095 - 4095 1469 4095 - 4095 1469 4095 - 4095 1469 4095 - 4095 1674 3 - 4095 1674 71 - 4095 1674 164 - 4095 1674 285 - 4095 1674 425 - 4095 1674 576 - 4095 1673 731 - 4095 1673 883 - 4095 1673 1028 - 4095 1673 1174 - 4095 1673 1322 - 4095 1673 1488 - 4095 1672 1672 - 4095 1672 1879 - 4095 1672 2113 - 4095 1671 2381 - 4095 1670 2679 - 4095 1670 2992 - 4095 1669 3299 - 4095 1667 3601 - 4095 1666 3873 - 4095 1664 4060 - 4095 1662 4095 - 4095 1659 4095 - 4095 1657 4095 - 4095 1656 4095 - 4095 1656 4095 - 4095 1656 4095 - 4095 1656 4095 - 4095 1656 4095 - 4095 1656 4095 - 4095 1656 4095 - 4095 1656 4095 - 4095 1878 3 - 4095 1878 66 - 4095 1878 156 - 4095 1878 277 - 4095 1877 418 - 4095 1877 570 - 4095 1877 726 - 4095 1877 878 - 4095 1877 1024 - 4095 1877 1169 - 4095 1877 1318 - 4095 1877 1484 - 4095 1876 1669 - 4095 1876 1876 - 4095 1876 2110 - 4095 1875 2380 - 4095 1875 2678 - 4095 1874 2991 - 4095 1873 3298 - 4095 1872 3597 - 4095 1871 3867 - 4095 1869 4059 - 4095 1868 4095 - 4095 1866 4095 - 4095 1865 4095 - 4095 1865 4095 - 4095 1865 4095 - 4095 1865 4095 - 4095 1865 4095 - 4095 1865 4095 - 4095 1865 4095 - 4095 1865 4095 - 4095 1865 4095 - 4095 2109 2 - 4095 2109 59 - 4095 2109 147 - 4095 2109 268 - 4095 2109 409 - 4095 2109 562 - 4095 2109 720 - 4095 2109 872 - 4095 2108 1019 - 4095 2108 1164 - 4095 2108 1314 - 4095 2108 1480 - 4095 2108 1665 - 4095 2108 1873 - 4095 2107 2107 - 4095 2107 2378 - 4095 2107 2678 - 4095 2106 2991 - 4095 2106 3297 - 4095 2105 3593 - 4095 2104 3861 - 4095 2103 4058 - 4095 2102 4095 - 4095 2102 4095 - 4095 2102 4095 - 4095 2102 4095 - 4095 2102 4095 - 4095 2102 4095 - 4095 2102 4095 - 4095 2102 4095 - 4095 2102 4095 - 4095 2102 4095 - 4095 2102 4095 - 4095 2377 2 - 4095 2377 51 - 4095 2377 137 - 4095 2377 258 - 4095 2377 400 - 4095 2377 555 - 4095 2377 713 - 4095 2377 867 - 4095 2377 1013 - 4095 2377 1159 - 4095 2377 1309 - 4095 2377 1475 - 4095 2377 1661 - 4095 2377 1869 - 4095 2377 2105 - 4095 2377 2376 - 4095 2376 2677 - 4095 2376 2991 - 4095 2376 3295 - 4095 2376 3590 - 4095 2376 3855 - 4095 2375 4058 - 4095 2375 4095 - 4095 2375 4095 - 4095 2375 4095 - 4095 2375 4095 - 4095 2375 4095 - 4095 2375 4095 - 4095 2375 4095 - 4095 2375 4095 - 4095 2375 4095 - 4095 2375 4095 - 4095 2375 4095 - 4095 2677 0 - 4095 2677 43 - 4095 2677 127 - 4095 2677 248 - 4095 2677 392 - 4095 2677 548 - 4095 2677 707 - 4095 2677 861 - 4095 2677 1009 - 4095 2677 1155 - 4095 2677 1305 - 4095 2677 1471 - 4095 2677 1658 - 4095 2677 1866 - 4095 2677 2102 - 4095 2677 2375 - 4095 2677 2677 - 4095 2677 2991 - 4095 2677 3295 - 4095 2677 3588 - 4095 2677 3852 - 4095 2677 4057 - 4095 2677 4095 - 4095 2677 4095 - 4095 2677 4095 - 4095 2677 4095 - 4095 2677 4095 - 4095 2677 4095 - 4095 2677 4095 - 4095 2677 4095 - 4095 2677 4095 - 4095 2677 4095 - 4095 2677 4095 - 4095 2991 1 - 4095 2991 37 - 4095 2991 120 - 4095 2991 242 - 4095 2991 387 - 4095 2991 544 - 4095 2991 704 - 4095 2991 859 - 4095 2991 1006 - 4095 2991 1152 - 4095 2991 1303 - 4095 2991 1470 - 4095 2991 1656 - 4095 2991 1865 - 4095 2991 2102 - 4095 2991 2375 - 4095 2991 2677 - 4095 2991 2991 - 4095 2991 3295 - 4095 2991 3588 - 4095 2991 3852 - 4095 2991 4057 - 4095 2991 4095 - 4095 2991 4095 - 4095 2991 4095 - 4095 2991 4095 - 4095 2991 4095 - 4095 2991 4095 - 4095 2991 4095 - 4095 2991 4095 - 4095 2991 4095 - 4095 2991 4095 - 4095 2991 4095 - 4095 3295 0 - 4095 3295 36 - 4095 3295 119 - 4095 3295 242 - 4095 3295 387 - 4095 3295 543 - 4095 3295 704 - 4095 3295 858 - 4095 3295 1006 - 4095 3295 1152 - 4095 3295 1303 - 4095 3295 1469 - 4095 3295 1656 - 4095 3295 1865 - 4095 3295 2102 - 4095 3295 2375 - 4095 3295 2677 - 4095 3295 2991 - 4095 3295 3295 - 4095 3295 3588 - 4095 3295 3852 - 4095 3295 4057 - 4095 3295 4095 - 4095 3295 4095 - 4095 3295 4095 - 4095 3295 4095 - 4095 3295 4095 - 4095 3295 4095 - 4095 3295 4095 - 4095 3295 4095 - 4095 3295 4095 - 4095 3295 4095 - 4095 3295 4095 - 4095 3588 0 - 4095 3588 36 - 4095 3588 119 - 4095 3588 242 - 4095 3588 387 - 4095 3588 543 - 4095 3588 704 - 4095 3588 858 - 4095 3588 1006 - 4095 3588 1152 - 4095 3588 1303 - 4095 3588 1469 - 4095 3588 1656 - 4095 3588 1865 - 4095 3588 2102 - 4095 3588 2375 - 4095 3588 2677 - 4095 3588 2991 - 4095 3588 3295 - 4095 3588 3588 - 4095 3588 3852 - 4095 3588 4057 - 4095 3588 4095 - 4095 3588 4095 - 4095 3588 4095 - 4095 3588 4095 - 4095 3588 4095 - 4095 3588 4095 - 4095 3588 4095 - 4095 3588 4095 - 4095 3588 4095 - 4095 3588 4095 - 4095 3588 4095 - 4095 3852 0 - 4095 3852 36 - 4095 3852 119 - 4095 3852 242 - 4095 3852 387 - 4095 3852 543 - 4095 3852 704 - 4095 3852 858 - 4095 3852 1006 - 4095 3852 1152 - 4095 3852 1303 - 4095 3852 1469 - 4095 3852 1656 - 4095 3852 1865 - 4095 3852 2102 - 4095 3852 2375 - 4095 3852 2677 - 4095 3852 2991 - 4095 3852 3295 - 4095 3852 3588 - 4095 3852 3852 - 4095 3852 4057 - 4095 3852 4095 - 4095 3852 4095 - 4095 3852 4095 - 4095 3852 4095 - 4095 3852 4095 - 4095 3852 4095 - 4095 3852 4095 - 4095 3852 4095 - 4095 3852 4095 - 4095 3852 4095 - 4095 3852 4095 - 4095 4057 0 - 4095 4057 36 - 4095 4057 119 - 4095 4057 242 - 4095 4057 387 - 4095 4057 543 - 4095 4057 704 - 4095 4057 858 - 4095 4057 1006 - 4095 4057 1152 - 4095 4057 1303 - 4095 4057 1469 - 4095 4057 1656 - 4095 4057 1865 - 4095 4057 2102 - 4095 4057 2375 - 4095 4057 2677 - 4095 4057 2991 - 4095 4057 3295 - 4095 4057 3588 - 4095 4057 3852 - 4095 4057 4057 - 4095 4057 4095 - 4095 4057 4095 - 4095 4057 4095 - 4095 4057 4095 - 4095 4057 4095 - 4095 4057 4095 - 4095 4057 4095 - 4095 4057 4095 - 4095 4057 4095 - 4095 4057 4095 - 4095 4057 4095 - 4095 4095 0 - 4095 4095 36 - 4095 4095 119 - 4095 4095 242 - 4095 4095 387 - 4095 4095 543 - 4095 4095 704 - 4095 4095 858 - 4095 4095 1006 - 4095 4095 1152 - 4095 4095 1303 - 4095 4095 1469 - 4095 4095 1656 - 4095 4095 1865 - 4095 4095 2102 - 4095 4095 2375 - 4095 4095 2677 - 4095 4095 2991 - 4095 4095 3295 - 4095 4095 3588 - 4095 4095 3852 - 4095 4095 4057 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 0 - 4095 4095 36 - 4095 4095 119 - 4095 4095 242 - 4095 4095 387 - 4095 4095 543 - 4095 4095 704 - 4095 4095 858 - 4095 4095 1006 - 4095 4095 1152 - 4095 4095 1303 - 4095 4095 1469 - 4095 4095 1656 - 4095 4095 1865 - 4095 4095 2102 - 4095 4095 2375 - 4095 4095 2677 - 4095 4095 2991 - 4095 4095 3295 - 4095 4095 3588 - 4095 4095 3852 - 4095 4095 4057 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 0 - 4095 4095 36 - 4095 4095 119 - 4095 4095 242 - 4095 4095 387 - 4095 4095 543 - 4095 4095 704 - 4095 4095 858 - 4095 4095 1006 - 4095 4095 1152 - 4095 4095 1303 - 4095 4095 1469 - 4095 4095 1656 - 4095 4095 1865 - 4095 4095 2102 - 4095 4095 2375 - 4095 4095 2677 - 4095 4095 2991 - 4095 4095 3295 - 4095 4095 3588 - 4095 4095 3852 - 4095 4095 4057 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 0 - 4095 4095 36 - 4095 4095 119 - 4095 4095 242 - 4095 4095 387 - 4095 4095 543 - 4095 4095 704 - 4095 4095 858 - 4095 4095 1006 - 4095 4095 1152 - 4095 4095 1303 - 4095 4095 1469 - 4095 4095 1656 - 4095 4095 1865 - 4095 4095 2102 - 4095 4095 2375 - 4095 4095 2677 - 4095 4095 2991 - 4095 4095 3295 - 4095 4095 3588 - 4095 4095 3852 - 4095 4095 4057 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 0 - 4095 4095 36 - 4095 4095 119 - 4095 4095 242 - 4095 4095 387 - 4095 4095 543 - 4095 4095 704 - 4095 4095 858 - 4095 4095 1006 - 4095 4095 1152 - 4095 4095 1303 - 4095 4095 1469 - 4095 4095 1656 - 4095 4095 1865 - 4095 4095 2102 - 4095 4095 2375 - 4095 4095 2677 - 4095 4095 2991 - 4095 4095 3295 - 4095 4095 3588 - 4095 4095 3852 - 4095 4095 4057 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 0 - 4095 4095 36 - 4095 4095 119 - 4095 4095 242 - 4095 4095 387 - 4095 4095 543 - 4095 4095 704 - 4095 4095 858 - 4095 4095 1006 - 4095 4095 1152 - 4095 4095 1303 - 4095 4095 1469 - 4095 4095 1656 - 4095 4095 1865 - 4095 4095 2102 - 4095 4095 2375 - 4095 4095 2677 - 4095 4095 2991 - 4095 4095 3295 - 4095 4095 3588 - 4095 4095 3852 - 4095 4095 4057 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 0 - 4095 4095 36 - 4095 4095 119 - 4095 4095 242 - 4095 4095 387 - 4095 4095 543 - 4095 4095 704 - 4095 4095 858 - 4095 4095 1006 - 4095 4095 1152 - 4095 4095 1303 - 4095 4095 1469 - 4095 4095 1656 - 4095 4095 1865 - 4095 4095 2102 - 4095 4095 2375 - 4095 4095 2677 - 4095 4095 2991 - 4095 4095 3295 - 4095 4095 3588 - 4095 4095 3852 - 4095 4095 4057 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 0 - 4095 4095 36 - 4095 4095 119 - 4095 4095 242 - 4095 4095 387 - 4095 4095 543 - 4095 4095 704 - 4095 4095 858 - 4095 4095 1006 - 4095 4095 1152 - 4095 4095 1303 - 4095 4095 1469 - 4095 4095 1656 - 4095 4095 1865 - 4095 4095 2102 - 4095 4095 2375 - 4095 4095 2677 - 4095 4095 2991 - 4095 4095 3295 - 4095 4095 3588 - 4095 4095 3852 - 4095 4095 4057 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 0 - 4095 4095 36 - 4095 4095 119 - 4095 4095 242 - 4095 4095 387 - 4095 4095 543 - 4095 4095 704 - 4095 4095 858 - 4095 4095 1006 - 4095 4095 1152 - 4095 4095 1303 - 4095 4095 1469 - 4095 4095 1656 - 4095 4095 1865 - 4095 4095 2102 - 4095 4095 2375 - 4095 4095 2677 - 4095 4095 2991 - 4095 4095 3295 - 4095 4095 3588 - 4095 4095 3852 - 4095 4095 4057 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 0 - 4095 4095 36 - 4095 4095 119 - 4095 4095 242 - 4095 4095 387 - 4095 4095 543 - 4095 4095 704 - 4095 4095 858 - 4095 4095 1006 - 4095 4095 1152 - 4095 4095 1303 - 4095 4095 1469 - 4095 4095 1656 - 4095 4095 1865 - 4095 4095 2102 - 4095 4095 2375 - 4095 4095 2677 - 4095 4095 2991 - 4095 4095 3295 - 4095 4095 3588 - 4095 4095 3852 - 4095 4095 4057 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 0 - 4095 4095 36 - 4095 4095 119 - 4095 4095 242 - 4095 4095 387 - 4095 4095 543 - 4095 4095 704 - 4095 4095 858 - 4095 4095 1006 - 4095 4095 1152 - 4095 4095 1303 - 4095 4095 1469 - 4095 4095 1656 - 4095 4095 1865 - 4095 4095 2102 - 4095 4095 2375 - 4095 4095 2677 - 4095 4095 2991 - 4095 4095 3295 - 4095 4095 3588 - 4095 4095 3852 - 4095 4095 4057 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 3 2 - 4095 3 74 - 4095 3 169 - 4095 3 290 - 4095 2 430 - 4095 0 580 - 4095 0 735 - 4095 1 886 - 4095 2 1031 - 4095 2 1176 - 4095 1 1325 - 4095 1 1490 - 4095 3 1675 - 4095 2 1881 - 4095 3 2114 - 4095 2 2382 - 4095 2 2679 - 4095 2 2992 - 4095 3 3300 - 4095 3 3603 - 4095 2 3878 - 4095 2 4061 - 4095 1 4095 - 4095 2 4095 - 4095 1 4095 - 4095 0 4095 - 4095 0 4095 - 4095 0 4095 - 4095 0 4095 - 4095 0 4095 - 4095 0 4095 - 4095 0 4095 - 4095 0 4095 - 4095 74 1 - 4095 74 74 - 4095 74 169 - 4095 74 290 - 4095 74 430 - 4095 74 580 - 4095 74 735 - 4095 73 886 - 4095 73 1031 - 4095 73 1176 - 4095 73 1325 - 4095 72 1490 - 4095 72 1675 - 4095 71 1881 - 4095 71 2114 - 4095 70 2382 - 4095 69 2679 - 4095 68 2992 - 4095 66 3300 - 4095 64 3603 - 4095 61 3877 - 4095 58 4061 - 4095 54 4095 - 4095 49 4095 - 4095 43 4095 - 4095 38 4095 - 4095 36 4095 - 4095 36 4095 - 4095 36 4095 - 4095 36 4095 - 4095 36 4095 - 4095 36 4095 - 4095 36 4095 - 4095 168 3 - 4095 168 74 - 4095 168 168 - 4095 168 290 - 4095 168 429 - 4095 168 580 - 4095 168 734 - 4095 168 885 - 4095 167 1031 - 4095 167 1176 - 4095 167 1325 - 4095 166 1490 - 4095 165 1674 - 4095 165 1881 - 4095 164 2114 - 4095 162 2382 - 4095 161 2679 - 4095 159 2992 - 4095 157 3300 - 4095 154 3603 - 4095 150 3877 - 4095 145 4061 - 4095 140 4095 - 4095 133 4095 - 4095 127 4095 - 4095 121 4095 - 4095 119 4095 - 4095 119 4095 - 4095 119 4095 - 4095 119 4095 - 4095 119 4095 - 4095 119 4095 - 4095 119 4095 - 4095 289 3 - 4095 289 73 - 4095 289 168 - 4095 289 289 - 4095 289 428 - 4095 288 579 - 4095 288 734 - 4095 288 885 - 4095 288 1031 - 4095 287 1176 - 4095 287 1324 - 4095 286 1489 - 4095 286 1674 - 4095 285 1880 - 4095 284 2114 - 4095 283 2382 - 4095 281 2679 - 4095 279 2992 - 4095 277 3300 - 4095 274 3603 - 4095 270 3876 - 4095 265 4061 - 4095 260 4095 - 4095 254 4095 - 4095 248 4095 - 4095 243 4095 - 4095 242 4095 - 4095 242 4095 - 4095 242 4095 - 4095 242 4095 - 4095 242 4095 - 4095 242 4095 - 4095 242 4095 - 4095 428 3 - 4095 428 72 - 4095 428 166 - 4095 427 288 - 4095 427 427 - 4095 427 578 - 4095 427 733 - 4095 427 884 - 4095 427 1030 - 4095 426 1175 - 4095 426 1324 - 4095 425 1489 - 4095 425 1674 - 4095 424 1880 - 4095 423 2113 - 4095 422 2382 - 4095 420 2679 - 4095 419 2992 - 4095 416 3300 - 4095 414 3602 - 4095 410 3875 - 4095 406 4061 - 4095 401 4095 - 4095 396 4095 - 4095 391 4095 - 4095 387 4095 - 4095 387 4095 - 4095 387 4095 - 4095 387 4095 - 4095 387 4095 - 4095 387 4095 - 4095 387 4095 - 4095 387 4095 - 4095 577 3 - 4095 577 71 - 4095 577 165 - 4095 577 286 - 4095 577 426 - 4095 577 577 - 4095 577 732 - 4095 577 883 - 4095 576 1029 - 4095 576 1174 - 4095 576 1323 - 4095 575 1488 - 4095 575 1673 - 4095 574 1879 - 4095 573 2113 - 4095 572 2382 - 4095 571 2679 - 4095 570 2992 - 4095 568 3300 - 4095 565 3601 - 4095 562 3874 - 4095 559 4060 - 4095 555 4095 - 4095 551 4095 - 4095 547 4095 - 4095 544 4095 - 4095 543 4095 - 4095 543 4095 - 4095 543 4095 - 4095 543 4095 - 4095 543 4095 - 4095 543 4095 - 4095 543 4095 - 4095 731 3 - 4095 731 70 - 4095 731 163 - 4095 731 284 - 4095 731 424 - 4095 731 575 - 4095 731 731 - 4095 730 882 - 4095 730 1028 - 4095 730 1173 - 4095 730 1322 - 4095 729 1487 - 4095 729 1672 - 4095 728 1879 - 4095 728 2112 - 4095 727 2381 - 4095 726 2679 - 4095 724 2992 - 4095 723 3299 - 4095 721 3600 - 4095 718 3872 - 4095 716 4060 - 4095 712 4095 - 4095 709 4095 - 4095 706 4095 - 4095 704 4095 - 4095 704 4095 - 4095 704 4095 - 4095 704 4095 - 4095 704 4095 - 4095 704 4095 - 4095 704 4095 - 4095 704 4095 - 4095 881 2 - 4095 881 68 - 4095 881 161 - 4095 881 282 - 4095 881 422 - 4095 881 573 - 4095 881 729 - 4095 881 881 - 4095 880 1027 - 4095 880 1172 - 4095 880 1321 - 4095 880 1486 - 4095 879 1671 - 4095 879 1878 - 4095 878 2112 - 4095 878 2381 - 4095 877 2679 - 4095 875 2991 - 4095 874 3299 - 4095 872 3599 - 4095 870 3871 - 4095 868 4060 - 4095 865 4095 - 4095 862 4095 - 4095 860 4095 - 4095 859 4095 - 4095 858 4095 - 4095 858 4095 - 4095 858 4095 - 4095 858 4095 - 4095 858 4095 - 4095 858 4095 - 4095 858 4095 - 4095 1026 3 - 4095 1026 67 - 4095 1026 158 - 4095 1026 279 - 4095 1025 419 - 4095 1025 571 - 4095 1025 727 - 4095 1025 879 - 4095 1025 1025 - 4095 1025 1170 - 4095 1025 1319 - 4095 1024 1485 - 4095 1024 1670 - 4095 1023 1877 - 4095 1023 2111 - 4095 1022 2380 - 4095 1021 2678 - 4095 1020 2991 - 4095 1019 3298 - 4095 1017 3598 - 4095 1016 3868 - 4095 1013 4060 - 4095 1011 4095 - 4095 1009 4095 - 4095 1007 4095 - 4095 1006 4095 - 4095 1006 4095 - 4095 1006 4095 - 4095 1006 4095 - 4095 1006 4095 - 4095 1006 4095 - 4095 1006 4095 - 4095 1006 4095 - 4095 1169 3 - 4095 1169 65 - 4095 1169 155 - 4095 1169 276 - 4095 1169 416 - 4095 1169 569 - 4095 1169 725 - 4095 1169 877 - 4095 1169 1023 - 4095 1169 1168 - 4095 1168 1318 - 4095 1168 1483 - 4095 1168 1668 - 4095 1167 1876 - 4095 1167 2110 - 4095 1166 2380 - 4095 1165 2678 - 4095 1164 2991 - 4095 1163 3298 - 4095 1162 3596 - 4095 1160 3866 - 4095 1158 4059 - 4095 1156 4095 - 4095 1154 4095 - 4095 1153 4095 - 4095 1152 4095 - 4095 1152 4095 - 4095 1152 4095 - 4095 1152 4095 - 4095 1152 4095 - 4095 1152 4095 - 4095 1152 4095 - 4095 1152 4095 - 4095 1317 2 - 4095 1317 62 - 4095 1317 151 - 4095 1317 272 - 4095 1317 413 - 4095 1317 566 - 4095 1316 722 - 4095 1316 875 - 4095 1316 1021 - 4095 1316 1167 - 4095 1316 1316 - 4095 1316 1482 - 4095 1315 1667 - 4095 1315 1874 - 4095 1314 2109 - 4095 1314 2379 - 4095 1313 2678 - 4095 1312 2991 - 4095 1311 3297 - 4095 1310 3595 - 4095 1309 3863 - 4095 1307 4059 - 4095 1305 4095 - 4095 1304 4095 - 4095 1303 4095 - 4095 1303 4095 - 4095 1303 4095 - 4095 1303 4095 - 4095 1303 4095 - 4095 1303 4095 - 4095 1303 4095 - 4095 1303 4095 - 4095 1303 4095 - 4095 1480 3 - 4095 1480 59 - 4095 1480 147 - 4095 1480 267 - 4095 1480 409 - 4095 1480 562 - 4095 1480 719 - 4095 1480 872 - 4095 1480 1019 - 4095 1480 1164 - 4095 1480 1314 - 4095 1479 1479 - 4095 1479 1665 - 4095 1479 1872 - 4095 1479 2107 - 4095 1478 2378 - 4095 1477 2677 - 4095 1477 2991 - 4095 1476 3297 - 4095 1475 3593 - 4095 1474 3861 - 4095 1472 4058 - 4095 1471 4095 - 4095 1470 4095 - 4095 1470 4095 - 4095 1469 4095 - 4095 1469 4095 - 4095 1469 4095 - 4095 1469 4095 - 4095 1469 4095 - 4095 1469 4095 - 4095 1469 4095 - 4095 1469 4095 - 4095 1664 2 - 4095 1664 55 - 4095 1664 141 - 4095 1664 262 - 4095 1664 404 - 4095 1664 558 - 4095 1664 716 - 4095 1664 869 - 4095 1663 1016 - 4095 1663 1161 - 4095 1663 1311 - 4095 1663 1477 - 4095 1663 1663 - 4095 1663 1871 - 4095 1662 2106 - 4095 1662 2377 - 4095 1661 2677 - 4095 1661 2991 - 4095 1660 3296 - 4095 1659 3591 - 4095 1658 3858 - 4095 1658 4058 - 4095 1657 4095 - 4095 1656 4095 - 4095 1656 4095 - 4095 1656 4095 - 4095 1656 4095 - 4095 1656 4095 - 4095 1656 4095 - 4095 1656 4095 - 4095 1656 4095 - 4095 1656 4095 - 4095 1656 4095 - 4095 1869 0 - 4095 1869 50 - 4095 1869 135 - 4095 1869 256 - 4095 1869 399 - 4095 1869 554 - 4095 1869 712 - 4095 1869 866 - 4095 1869 1013 - 4095 1869 1158 - 4095 1869 1308 - 4095 1869 1474 - 4095 1869 1660 - 4095 1869 1869 - 4095 1868 2104 - 4095 1868 2376 - 4095 1868 2677 - 4095 1867 2991 - 4095 1867 3295 - 4095 1866 3589 - 4095 1866 3855 - 4095 1865 4058 - 4095 1865 4095 - 4095 1865 4095 - 4095 1865 4095 - 4095 1865 4095 - 4095 1865 4095 - 4095 1865 4095 - 4095 1865 4095 - 4095 1865 4095 - 4095 1865 4095 - 4095 1865 4095 - 4095 1865 4095 - 4095 2103 0 - 4095 2103 45 - 4095 2103 129 - 4095 2103 250 - 4095 2103 393 - 4095 2103 549 - 4095 2103 708 - 4095 2103 862 - 4095 2103 1009 - 4095 2103 1156 - 4095 2103 1305 - 4095 2103 1472 - 4095 2103 1658 - 4095 2103 1867 - 4095 2103 2103 - 4095 2103 2376 - 4095 2102 2677 - 4095 2102 2991 - 4095 2102 3295 - 4095 2102 3588 - 4095 2102 3853 - 4095 2102 4057 - 4095 2102 4095 - 4095 2102 4095 - 4095 2102 4095 - 4095 2102 4095 - 4095 2102 4095 - 4095 2102 4095 - 4095 2102 4095 - 4095 2102 4095 - 4095 2102 4095 - 4095 2102 4095 - 4095 2102 4095 - 4095 2375 2 - 4095 2375 40 - 4095 2375 123 - 4095 2375 245 - 4095 2375 389 - 4095 2375 545 - 4095 2375 705 - 4095 2375 860 - 4095 2375 1007 - 4095 2375 1153 - 4095 2375 1303 - 4095 2375 1470 - 4095 2375 1657 - 4095 2375 1865 - 4095 2375 2102 - 4095 2375 2375 - 4095 2375 2677 - 4095 2375 2991 - 4095 2375 3295 - 4095 2375 3588 - 4095 2375 3852 - 4095 2375 4057 - 4095 2375 4095 - 4095 2375 4095 - 4095 2375 4095 - 4095 2375 4095 - 4095 2375 4095 - 4095 2375 4095 - 4095 2375 4095 - 4095 2375 4095 - 4095 2375 4095 - 4095 2375 4095 - 4095 2375 4095 - 4095 2677 0 - 4095 2677 37 - 4095 2677 120 - 4095 2677 242 - 4095 2677 387 - 4095 2677 543 - 4095 2677 704 - 4095 2677 859 - 4095 2677 1006 - 4095 2677 1152 - 4095 2677 1303 - 4095 2677 1469 - 4095 2677 1656 - 4095 2677 1865 - 4095 2677 2102 - 4095 2677 2375 - 4095 2677 2677 - 4095 2677 2991 - 4095 2677 3295 - 4095 2677 3588 - 4095 2677 3852 - 4095 2677 4057 - 4095 2677 4095 - 4095 2677 4095 - 4095 2677 4095 - 4095 2677 4095 - 4095 2677 4095 - 4095 2677 4095 - 4095 2677 4095 - 4095 2677 4095 - 4095 2677 4095 - 4095 2677 4095 - 4095 2677 4095 - 4095 2991 0 - 4095 2991 36 - 4095 2991 119 - 4095 2991 242 - 4095 2991 387 - 4095 2991 543 - 4095 2991 704 - 4095 2991 858 - 4095 2991 1006 - 4095 2991 1152 - 4095 2991 1303 - 4095 2991 1469 - 4095 2991 1656 - 4095 2991 1865 - 4095 2991 2102 - 4095 2991 2375 - 4095 2991 2677 - 4095 2991 2991 - 4095 2991 3295 - 4095 2991 3588 - 4095 2991 3852 - 4095 2991 4057 - 4095 2991 4095 - 4095 2991 4095 - 4095 2991 4095 - 4095 2991 4095 - 4095 2991 4095 - 4095 2991 4095 - 4095 2991 4095 - 4095 2991 4095 - 4095 2991 4095 - 4095 2991 4095 - 4095 2991 4095 - 4095 3295 0 - 4095 3295 36 - 4095 3295 119 - 4095 3295 242 - 4095 3295 387 - 4095 3295 543 - 4095 3295 704 - 4095 3295 858 - 4095 3295 1006 - 4095 3295 1152 - 4095 3295 1303 - 4095 3295 1469 - 4095 3295 1656 - 4095 3295 1865 - 4095 3295 2102 - 4095 3295 2375 - 4095 3295 2677 - 4095 3295 2991 - 4095 3295 3295 - 4095 3295 3588 - 4095 3295 3852 - 4095 3295 4057 - 4095 3295 4095 - 4095 3295 4095 - 4095 3295 4095 - 4095 3295 4095 - 4095 3295 4095 - 4095 3295 4095 - 4095 3295 4095 - 4095 3295 4095 - 4095 3295 4095 - 4095 3295 4095 - 4095 3295 4095 - 4095 3588 0 - 4095 3588 36 - 4095 3588 119 - 4095 3588 242 - 4095 3588 387 - 4095 3588 543 - 4095 3588 704 - 4095 3588 858 - 4095 3588 1006 - 4095 3588 1152 - 4095 3588 1303 - 4095 3588 1469 - 4095 3588 1656 - 4095 3588 1865 - 4095 3588 2102 - 4095 3588 2375 - 4095 3588 2677 - 4095 3588 2991 - 4095 3588 3295 - 4095 3588 3588 - 4095 3588 3852 - 4095 3588 4057 - 4095 3588 4095 - 4095 3588 4095 - 4095 3588 4095 - 4095 3588 4095 - 4095 3588 4095 - 4095 3588 4095 - 4095 3588 4095 - 4095 3588 4095 - 4095 3588 4095 - 4095 3588 4095 - 4095 3588 4095 - 4095 3852 0 - 4095 3852 36 - 4095 3852 119 - 4095 3852 242 - 4095 3852 387 - 4095 3852 543 - 4095 3852 704 - 4095 3852 858 - 4095 3852 1006 - 4095 3852 1152 - 4095 3852 1303 - 4095 3852 1469 - 4095 3852 1656 - 4095 3852 1865 - 4095 3852 2102 - 4095 3852 2375 - 4095 3852 2677 - 4095 3852 2991 - 4095 3852 3295 - 4095 3852 3588 - 4095 3852 3852 - 4095 3852 4057 - 4095 3852 4095 - 4095 3852 4095 - 4095 3852 4095 - 4095 3852 4095 - 4095 3852 4095 - 4095 3852 4095 - 4095 3852 4095 - 4095 3852 4095 - 4095 3852 4095 - 4095 3852 4095 - 4095 3852 4095 - 4095 4057 0 - 4095 4057 36 - 4095 4057 119 - 4095 4057 242 - 4095 4057 387 - 4095 4057 543 - 4095 4057 704 - 4095 4057 858 - 4095 4057 1006 - 4095 4057 1152 - 4095 4057 1303 - 4095 4057 1469 - 4095 4057 1656 - 4095 4057 1865 - 4095 4057 2102 - 4095 4057 2375 - 4095 4057 2677 - 4095 4057 2991 - 4095 4057 3295 - 4095 4057 3588 - 4095 4057 3852 - 4095 4057 4057 - 4095 4057 4095 - 4095 4057 4095 - 4095 4057 4095 - 4095 4057 4095 - 4095 4057 4095 - 4095 4057 4095 - 4095 4057 4095 - 4095 4057 4095 - 4095 4057 4095 - 4095 4057 4095 - 4095 4057 4095 - 4095 4095 0 - 4095 4095 36 - 4095 4095 119 - 4095 4095 242 - 4095 4095 387 - 4095 4095 543 - 4095 4095 704 - 4095 4095 858 - 4095 4095 1006 - 4095 4095 1152 - 4095 4095 1303 - 4095 4095 1469 - 4095 4095 1656 - 4095 4095 1865 - 4095 4095 2102 - 4095 4095 2375 - 4095 4095 2677 - 4095 4095 2991 - 4095 4095 3295 - 4095 4095 3588 - 4095 4095 3852 - 4095 4095 4057 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 0 - 4095 4095 36 - 4095 4095 119 - 4095 4095 242 - 4095 4095 387 - 4095 4095 543 - 4095 4095 704 - 4095 4095 858 - 4095 4095 1006 - 4095 4095 1152 - 4095 4095 1303 - 4095 4095 1469 - 4095 4095 1656 - 4095 4095 1865 - 4095 4095 2102 - 4095 4095 2375 - 4095 4095 2677 - 4095 4095 2991 - 4095 4095 3295 - 4095 4095 3588 - 4095 4095 3852 - 4095 4095 4057 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 0 - 4095 4095 36 - 4095 4095 119 - 4095 4095 242 - 4095 4095 387 - 4095 4095 543 - 4095 4095 704 - 4095 4095 858 - 4095 4095 1006 - 4095 4095 1152 - 4095 4095 1303 - 4095 4095 1469 - 4095 4095 1656 - 4095 4095 1865 - 4095 4095 2102 - 4095 4095 2375 - 4095 4095 2677 - 4095 4095 2991 - 4095 4095 3295 - 4095 4095 3588 - 4095 4095 3852 - 4095 4095 4057 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 0 - 4095 4095 36 - 4095 4095 119 - 4095 4095 242 - 4095 4095 387 - 4095 4095 543 - 4095 4095 704 - 4095 4095 858 - 4095 4095 1006 - 4095 4095 1152 - 4095 4095 1303 - 4095 4095 1469 - 4095 4095 1656 - 4095 4095 1865 - 4095 4095 2102 - 4095 4095 2375 - 4095 4095 2677 - 4095 4095 2991 - 4095 4095 3295 - 4095 4095 3588 - 4095 4095 3852 - 4095 4095 4057 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 0 - 4095 4095 36 - 4095 4095 119 - 4095 4095 242 - 4095 4095 387 - 4095 4095 543 - 4095 4095 704 - 4095 4095 858 - 4095 4095 1006 - 4095 4095 1152 - 4095 4095 1303 - 4095 4095 1469 - 4095 4095 1656 - 4095 4095 1865 - 4095 4095 2102 - 4095 4095 2375 - 4095 4095 2677 - 4095 4095 2991 - 4095 4095 3295 - 4095 4095 3588 - 4095 4095 3852 - 4095 4095 4057 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 0 - 4095 4095 36 - 4095 4095 119 - 4095 4095 242 - 4095 4095 387 - 4095 4095 543 - 4095 4095 704 - 4095 4095 858 - 4095 4095 1006 - 4095 4095 1152 - 4095 4095 1303 - 4095 4095 1469 - 4095 4095 1656 - 4095 4095 1865 - 4095 4095 2102 - 4095 4095 2375 - 4095 4095 2677 - 4095 4095 2991 - 4095 4095 3295 - 4095 4095 3588 - 4095 4095 3852 - 4095 4095 4057 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 0 - 4095 4095 36 - 4095 4095 119 - 4095 4095 242 - 4095 4095 387 - 4095 4095 543 - 4095 4095 704 - 4095 4095 858 - 4095 4095 1006 - 4095 4095 1152 - 4095 4095 1303 - 4095 4095 1469 - 4095 4095 1656 - 4095 4095 1865 - 4095 4095 2102 - 4095 4095 2375 - 4095 4095 2677 - 4095 4095 2991 - 4095 4095 3295 - 4095 4095 3588 - 4095 4095 3852 - 4095 4095 4057 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 0 - 4095 4095 36 - 4095 4095 119 - 4095 4095 242 - 4095 4095 387 - 4095 4095 543 - 4095 4095 704 - 4095 4095 858 - 4095 4095 1006 - 4095 4095 1152 - 4095 4095 1303 - 4095 4095 1469 - 4095 4095 1656 - 4095 4095 1865 - 4095 4095 2102 - 4095 4095 2375 - 4095 4095 2677 - 4095 4095 2991 - 4095 4095 3295 - 4095 4095 3588 - 4095 4095 3852 - 4095 4095 4057 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 0 - 4095 4095 36 - 4095 4095 119 - 4095 4095 242 - 4095 4095 387 - 4095 4095 543 - 4095 4095 704 - 4095 4095 858 - 4095 4095 1006 - 4095 4095 1152 - 4095 4095 1303 - 4095 4095 1469 - 4095 4095 1656 - 4095 4095 1865 - 4095 4095 2102 - 4095 4095 2375 - 4095 4095 2677 - 4095 4095 2991 - 4095 4095 3295 - 4095 4095 3588 - 4095 4095 3852 - 4095 4095 4057 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 0 - 4095 4095 36 - 4095 4095 119 - 4095 4095 242 - 4095 4095 387 - 4095 4095 543 - 4095 4095 704 - 4095 4095 858 - 4095 4095 1006 - 4095 4095 1152 - 4095 4095 1303 - 4095 4095 1469 - 4095 4095 1656 - 4095 4095 1865 - 4095 4095 2102 - 4095 4095 2375 - 4095 4095 2677 - 4095 4095 2991 - 4095 4095 3295 - 4095 4095 3588 - 4095 4095 3852 - 4095 4095 4057 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 0 - 4095 4095 36 - 4095 4095 119 - 4095 4095 242 - 4095 4095 387 - 4095 4095 543 - 4095 4095 704 - 4095 4095 858 - 4095 4095 1006 - 4095 4095 1152 - 4095 4095 1303 - 4095 4095 1469 - 4095 4095 1656 - 4095 4095 1865 - 4095 4095 2102 - 4095 4095 2375 - 4095 4095 2677 - 4095 4095 2991 - 4095 4095 3295 - 4095 4095 3588 - 4095 4095 3852 - 4095 4095 4057 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 3 0 - 4095 3 54 - 4095 3 140 - 4095 2 261 - 4095 0 403 - 4095 2 557 - 4095 2 715 - 4095 2 868 - 4095 1 1015 - 4095 1 1161 - 4095 1 1310 - 4095 2 1477 - 4095 3 1662 - 4095 2 1870 - 4095 0 2105 - 4095 1 2377 - 4095 2 2677 - 4095 2 2991 - 4095 2 3296 - 4095 1 3591 - 4095 1 3857 - 4095 1 4058 - 4095 1 4095 - 4095 1 4095 - 4095 0 4095 - 4095 0 4095 - 4095 0 4095 - 4095 0 4095 - 4095 0 4095 - 4095 0 4095 - 4095 0 4095 - 4095 0 4095 - 4095 0 4095 - 4095 54 2 - 4095 54 54 - 4095 54 140 - 4095 54 261 - 4095 54 403 - 4095 54 557 - 4095 54 715 - 4095 53 868 - 4095 53 1015 - 4095 53 1161 - 4095 53 1310 - 4095 52 1477 - 4095 52 1662 - 4095 52 1870 - 4095 51 2105 - 4095 50 2377 - 4095 49 2677 - 4095 48 2991 - 4095 47 3296 - 4095 45 3591 - 4095 43 3857 - 4095 41 4058 - 4095 39 4095 - 4095 37 4095 - 4095 36 4095 - 4095 36 4095 - 4095 36 4095 - 4095 36 4095 - 4095 36 4095 - 4095 36 4095 - 4095 36 4095 - 4095 36 4095 - 4095 36 4095 - 4095 140 2 - 4095 140 54 - 4095 140 140 - 4095 140 261 - 4095 140 403 - 4095 140 557 - 4095 139 715 - 4095 139 868 - 4095 139 1015 - 4095 139 1161 - 4095 138 1310 - 4095 138 1476 - 4095 138 1662 - 4095 137 1870 - 4095 136 2105 - 4095 135 2377 - 4095 134 2677 - 4095 133 2991 - 4095 131 3296 - 4095 129 3591 - 4095 126 3857 - 4095 124 4058 - 4095 121 4095 - 4095 120 4095 - 4095 119 4095 - 4095 119 4095 - 4095 119 4095 - 4095 119 4095 - 4095 119 4095 - 4095 119 4095 - 4095 119 4095 - 4095 119 4095 - 4095 119 4095 - 4095 260 2 - 4095 260 53 - 4095 260 139 - 4095 260 260 - 4095 260 402 - 4095 260 556 - 4095 260 714 - 4095 259 868 - 4095 259 1015 - 4095 259 1160 - 4095 259 1310 - 4095 258 1476 - 4095 258 1662 - 4095 257 1870 - 4095 257 2105 - 4095 256 2377 - 4095 255 2677 - 4095 253 2991 - 4095 252 3296 - 4095 250 3590 - 4095 248 3856 - 4095 245 4058 - 4095 243 4095 - 4095 242 4095 - 4095 242 4095 - 4095 242 4095 - 4095 242 4095 - 4095 242 4095 - 4095 242 4095 - 4095 242 4095 - 4095 242 4095 - 4095 242 4095 - 4095 242 4095 - 4095 402 2 - 4095 402 52 - 4095 402 138 - 4095 401 259 - 4095 401 401 - 4095 401 556 - 4095 401 714 - 4095 401 867 - 4095 401 1014 - 4095 401 1160 - 4095 400 1310 - 4095 400 1476 - 4095 400 1662 - 4095 399 1869 - 4095 398 2105 - 4095 398 2377 - 4095 397 2677 - 4095 396 2991 - 4095 394 3296 - 4095 393 3590 - 4095 391 3856 - 4095 389 4058 - 4095 388 4095 - 4095 387 4095 - 4095 387 4095 - 4095 387 4095 - 4095 387 4095 - 4095 387 4095 - 4095 387 4095 - 4095 387 4095 - 4095 387 4095 - 4095 387 4095 - 4095 387 4095 - 4095 555 1 - 4095 555 51 - 4095 555 137 - 4095 555 258 - 4095 555 400 - 4095 555 555 - 4095 555 713 - 4095 555 867 - 4095 555 1013 - 4095 554 1159 - 4095 554 1309 - 4095 554 1475 - 4095 554 1661 - 4095 553 1869 - 4095 553 2105 - 4095 552 2377 - 4095 551 2677 - 4095 550 2991 - 4095 549 3295 - 4095 548 3590 - 4095 547 3855 - 4095 545 4058 - 4095 544 4095 - 4095 543 4095 - 4095 543 4095 - 4095 543 4095 - 4095 543 4095 - 4095 543 4095 - 4095 543 4095 - 4095 543 4095 - 4095 543 4095 - 4095 543 4095 - 4095 543 4095 - 4095 713 1 - 4095 713 50 - 4095 713 136 - 4095 712 256 - 4095 712 399 - 4095 712 554 - 4095 712 712 - 4095 712 866 - 4095 712 1013 - 4095 712 1159 - 4095 712 1308 - 4095 711 1475 - 4095 711 1661 - 4095 711 1869 - 4095 710 2104 - 4095 710 2376 - 4095 709 2677 - 4095 709 2991 - 4095 708 3295 - 4095 707 3589 - 4095 706 3855 - 4095 705 4058 - 4095 704 4095 - 4095 704 4095 - 4095 704 4095 - 4095 704 4095 - 4095 704 4095 - 4095 704 4095 - 4095 704 4095 - 4095 704 4095 - 4095 704 4095 - 4095 704 4095 - 4095 704 4095 - 4095 865 0 - 4095 865 49 - 4095 865 134 - 4095 865 255 - 4095 865 398 - 4095 865 553 - 4095 865 711 - 4095 865 865 - 4095 865 1012 - 4095 865 1158 - 4095 865 1308 - 4095 864 1474 - 4095 864 1660 - 4095 864 1868 - 4095 864 2104 - 4095 863 2376 - 4095 863 2677 - 4095 862 2991 - 4095 861 3295 - 4095 861 3589 - 4095 860 3854 - 4095 859 4057 - 4095 859 4095 - 4095 858 4095 - 4095 858 4095 - 4095 858 4095 - 4095 858 4095 - 4095 858 4095 - 4095 858 4095 - 4095 858 4095 - 4095 858 4095 - 4095 858 4095 - 4095 858 4095 - 4095 1011 0 - 4095 1011 47 - 4095 1011 132 - 4095 1011 253 - 4095 1011 396 - 4095 1011 551 - 4095 1011 710 - 4095 1011 864 - 4095 1011 1011 - 4095 1011 1157 - 4095 1011 1307 - 4095 1011 1473 - 4095 1010 1659 - 4095 1010 1867 - 4095 1010 2103 - 4095 1009 2376 - 4095 1009 2677 - 4095 1009 2991 - 4095 1008 3295 - 4095 1007 3589 - 4095 1007 3853 - 4095 1006 4057 - 4095 1006 4095 - 4095 1006 4095 - 4095 1006 4095 - 4095 1006 4095 - 4095 1006 4095 - 4095 1006 4095 - 4095 1006 4095 - 4095 1006 4095 - 4095 1006 4095 - 4095 1006 4095 - 4095 1006 4095 - 4095 1156 1 - 4095 1156 46 - 4095 1156 130 - 4095 1156 251 - 4095 1156 394 - 4095 1156 550 - 4095 1156 709 - 4095 1156 863 - 4095 1156 1010 - 4095 1156 1156 - 4095 1156 1306 - 4095 1156 1472 - 4095 1156 1659 - 4095 1155 1867 - 4095 1155 2103 - 4095 1155 2376 - 4095 1155 2677 - 4095 1154 2991 - 4095 1154 3295 - 4095 1153 3588 - 4095 1153 3853 - 4095 1153 4057 - 4095 1152 4095 - 4095 1152 4095 - 4095 1152 4095 - 4095 1152 4095 - 4095 1152 4095 - 4095 1152 4095 - 4095 1152 4095 - 4095 1152 4095 - 4095 1152 4095 - 4095 1152 4095 - 4095 1152 4095 - 4095 1305 2 - 4095 1305 43 - 4095 1305 127 - 4095 1305 249 - 4095 1305 392 - 4095 1305 548 - 4095 1305 708 - 4095 1305 862 - 4095 1305 1009 - 4095 1305 1155 - 4095 1305 1305 - 4095 1305 1472 - 4095 1305 1658 - 4095 1305 1866 - 4095 1304 2103 - 4095 1304 2375 - 4095 1304 2677 - 4095 1304 2991 - 4095 1303 3295 - 4095 1303 3588 - 4095 1303 3852 - 4095 1303 4057 - 4095 1303 4095 - 4095 1303 4095 - 4095 1303 4095 - 4095 1303 4095 - 4095 1303 4095 - 4095 1303 4095 - 4095 1303 4095 - 4095 1303 4095 - 4095 1303 4095 - 4095 1303 4095 - 4095 1303 4095 - 4095 1471 1 - 4095 1471 41 - 4095 1471 125 - 4095 1471 247 - 4095 1471 390 - 4095 1471 547 - 4095 1471 706 - 4095 1471 861 - 4095 1471 1008 - 4095 1471 1154 - 4095 1471 1304 - 4095 1471 1471 - 4095 1471 1657 - 4095 1471 1866 - 4095 1470 2102 - 4095 1470 2375 - 4095 1470 2677 - 4095 1470 2991 - 4095 1470 3295 - 4095 1470 3588 - 4095 1470 3852 - 4095 1469 4057 - 4095 1469 4095 - 4095 1469 4095 - 4095 1469 4095 - 4095 1469 4095 - 4095 1469 4095 - 4095 1469 4095 - 4095 1469 4095 - 4095 1469 4095 - 4095 1469 4095 - 4095 1469 4095 - 4095 1469 4095 - 4095 1657 2 - 4095 1657 39 - 4095 1657 122 - 4095 1657 244 - 4095 1657 389 - 4095 1657 545 - 4095 1657 705 - 4095 1657 860 - 4095 1657 1007 - 4095 1657 1153 - 4095 1657 1303 - 4095 1657 1470 - 4095 1657 1657 - 4095 1657 1865 - 4095 1656 2102 - 4095 1656 2375 - 4095 1656 2677 - 4095 1656 2991 - 4095 1656 3295 - 4095 1656 3588 - 4095 1656 3852 - 4095 1656 4057 - 4095 1656 4095 - 4095 1656 4095 - 4095 1656 4095 - 4095 1656 4095 - 4095 1656 4095 - 4095 1656 4095 - 4095 1656 4095 - 4095 1656 4095 - 4095 1656 4095 - 4095 1656 4095 - 4095 1656 4095 - 4095 1865 1 - 4095 1865 37 - 4095 1865 120 - 4095 1865 243 - 4095 1865 387 - 4095 1865 544 - 4095 1865 704 - 4095 1865 859 - 4095 1865 1006 - 4095 1865 1153 - 4095 1865 1303 - 4095 1865 1470 - 4095 1865 1656 - 4095 1865 1865 - 4095 1865 2102 - 4095 1865 2375 - 4095 1865 2677 - 4095 1865 2991 - 4095 1865 3295 - 4095 1865 3588 - 4095 1865 3852 - 4095 1865 4057 - 4095 1865 4095 - 4095 1865 4095 - 4095 1865 4095 - 4095 1865 4095 - 4095 1865 4095 - 4095 1865 4095 - 4095 1865 4095 - 4095 1865 4095 - 4095 1865 4095 - 4095 1865 4095 - 4095 1865 4095 - 4095 2102 0 - 4095 2102 36 - 4095 2102 120 - 4095 2102 242 - 4095 2102 387 - 4095 2102 543 - 4095 2102 704 - 4095 2102 858 - 4095 2102 1006 - 4095 2102 1152 - 4095 2102 1303 - 4095 2102 1469 - 4095 2102 1656 - 4095 2102 1865 - 4095 2102 2102 - 4095 2102 2375 - 4095 2102 2677 - 4095 2102 2991 - 4095 2102 3295 - 4095 2102 3588 - 4095 2102 3852 - 4095 2102 4057 - 4095 2102 4095 - 4095 2102 4095 - 4095 2102 4095 - 4095 2102 4095 - 4095 2102 4095 - 4095 2102 4095 - 4095 2102 4095 - 4095 2102 4095 - 4095 2102 4095 - 4095 2102 4095 - 4095 2102 4095 - 4095 2375 0 - 4095 2375 36 - 4095 2375 119 - 4095 2375 242 - 4095 2375 387 - 4095 2375 543 - 4095 2375 704 - 4095 2375 858 - 4095 2375 1006 - 4095 2375 1152 - 4095 2375 1303 - 4095 2375 1469 - 4095 2375 1656 - 4095 2375 1865 - 4095 2375 2102 - 4095 2375 2375 - 4095 2375 2677 - 4095 2375 2991 - 4095 2375 3295 - 4095 2375 3588 - 4095 2375 3852 - 4095 2375 4057 - 4095 2375 4095 - 4095 2375 4095 - 4095 2375 4095 - 4095 2375 4095 - 4095 2375 4095 - 4095 2375 4095 - 4095 2375 4095 - 4095 2375 4095 - 4095 2375 4095 - 4095 2375 4095 - 4095 2375 4095 - 4095 2677 0 - 4095 2677 36 - 4095 2677 119 - 4095 2677 242 - 4095 2677 387 - 4095 2677 543 - 4095 2677 704 - 4095 2677 858 - 4095 2677 1006 - 4095 2677 1152 - 4095 2677 1303 - 4095 2677 1469 - 4095 2677 1656 - 4095 2677 1865 - 4095 2677 2102 - 4095 2677 2375 - 4095 2677 2677 - 4095 2677 2991 - 4095 2677 3295 - 4095 2677 3588 - 4095 2677 3852 - 4095 2677 4057 - 4095 2677 4095 - 4095 2677 4095 - 4095 2677 4095 - 4095 2677 4095 - 4095 2677 4095 - 4095 2677 4095 - 4095 2677 4095 - 4095 2677 4095 - 4095 2677 4095 - 4095 2677 4095 - 4095 2677 4095 - 4095 2991 0 - 4095 2991 36 - 4095 2991 119 - 4095 2991 242 - 4095 2991 387 - 4095 2991 543 - 4095 2991 704 - 4095 2991 858 - 4095 2991 1006 - 4095 2991 1152 - 4095 2991 1303 - 4095 2991 1469 - 4095 2991 1656 - 4095 2991 1865 - 4095 2991 2102 - 4095 2991 2375 - 4095 2991 2677 - 4095 2991 2991 - 4095 2991 3295 - 4095 2991 3588 - 4095 2991 3852 - 4095 2991 4057 - 4095 2991 4095 - 4095 2991 4095 - 4095 2991 4095 - 4095 2991 4095 - 4095 2991 4095 - 4095 2991 4095 - 4095 2991 4095 - 4095 2991 4095 - 4095 2991 4095 - 4095 2991 4095 - 4095 2991 4095 - 4095 3295 0 - 4095 3295 36 - 4095 3295 119 - 4095 3295 242 - 4095 3295 387 - 4095 3295 543 - 4095 3295 704 - 4095 3295 858 - 4095 3295 1006 - 4095 3295 1152 - 4095 3295 1303 - 4095 3295 1469 - 4095 3295 1656 - 4095 3295 1865 - 4095 3295 2102 - 4095 3295 2375 - 4095 3295 2677 - 4095 3295 2991 - 4095 3295 3295 - 4095 3295 3588 - 4095 3295 3852 - 4095 3295 4057 - 4095 3295 4095 - 4095 3295 4095 - 4095 3295 4095 - 4095 3295 4095 - 4095 3295 4095 - 4095 3295 4095 - 4095 3295 4095 - 4095 3295 4095 - 4095 3295 4095 - 4095 3295 4095 - 4095 3295 4095 - 4095 3588 0 - 4095 3588 36 - 4095 3588 119 - 4095 3588 242 - 4095 3588 387 - 4095 3588 543 - 4095 3588 704 - 4095 3588 858 - 4095 3588 1006 - 4095 3588 1152 - 4095 3588 1303 - 4095 3588 1469 - 4095 3588 1656 - 4095 3588 1865 - 4095 3588 2102 - 4095 3588 2375 - 4095 3588 2677 - 4095 3588 2991 - 4095 3588 3295 - 4095 3588 3588 - 4095 3588 3852 - 4095 3588 4057 - 4095 3588 4095 - 4095 3588 4095 - 4095 3588 4095 - 4095 3588 4095 - 4095 3588 4095 - 4095 3588 4095 - 4095 3588 4095 - 4095 3588 4095 - 4095 3588 4095 - 4095 3588 4095 - 4095 3588 4095 - 4095 3852 0 - 4095 3852 36 - 4095 3852 119 - 4095 3852 242 - 4095 3852 387 - 4095 3852 543 - 4095 3852 704 - 4095 3852 858 - 4095 3852 1006 - 4095 3852 1152 - 4095 3852 1303 - 4095 3852 1469 - 4095 3852 1656 - 4095 3852 1865 - 4095 3852 2102 - 4095 3852 2375 - 4095 3852 2677 - 4095 3852 2991 - 4095 3852 3295 - 4095 3852 3588 - 4095 3852 3852 - 4095 3852 4057 - 4095 3852 4095 - 4095 3852 4095 - 4095 3852 4095 - 4095 3852 4095 - 4095 3852 4095 - 4095 3852 4095 - 4095 3852 4095 - 4095 3852 4095 - 4095 3852 4095 - 4095 3852 4095 - 4095 3852 4095 - 4095 4057 0 - 4095 4057 36 - 4095 4057 119 - 4095 4057 242 - 4095 4057 387 - 4095 4057 543 - 4095 4057 704 - 4095 4057 858 - 4095 4057 1006 - 4095 4057 1152 - 4095 4057 1303 - 4095 4057 1469 - 4095 4057 1656 - 4095 4057 1865 - 4095 4057 2102 - 4095 4057 2375 - 4095 4057 2677 - 4095 4057 2991 - 4095 4057 3295 - 4095 4057 3588 - 4095 4057 3852 - 4095 4057 4057 - 4095 4057 4095 - 4095 4057 4095 - 4095 4057 4095 - 4095 4057 4095 - 4095 4057 4095 - 4095 4057 4095 - 4095 4057 4095 - 4095 4057 4095 - 4095 4057 4095 - 4095 4057 4095 - 4095 4057 4095 - 4095 4095 0 - 4095 4095 36 - 4095 4095 119 - 4095 4095 242 - 4095 4095 387 - 4095 4095 543 - 4095 4095 704 - 4095 4095 858 - 4095 4095 1006 - 4095 4095 1152 - 4095 4095 1303 - 4095 4095 1469 - 4095 4095 1656 - 4095 4095 1865 - 4095 4095 2102 - 4095 4095 2375 - 4095 4095 2677 - 4095 4095 2991 - 4095 4095 3295 - 4095 4095 3588 - 4095 4095 3852 - 4095 4095 4057 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 0 - 4095 4095 36 - 4095 4095 119 - 4095 4095 242 - 4095 4095 387 - 4095 4095 543 - 4095 4095 704 - 4095 4095 858 - 4095 4095 1006 - 4095 4095 1152 - 4095 4095 1303 - 4095 4095 1469 - 4095 4095 1656 - 4095 4095 1865 - 4095 4095 2102 - 4095 4095 2375 - 4095 4095 2677 - 4095 4095 2991 - 4095 4095 3295 - 4095 4095 3588 - 4095 4095 3852 - 4095 4095 4057 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 0 - 4095 4095 36 - 4095 4095 119 - 4095 4095 242 - 4095 4095 387 - 4095 4095 543 - 4095 4095 704 - 4095 4095 858 - 4095 4095 1006 - 4095 4095 1152 - 4095 4095 1303 - 4095 4095 1469 - 4095 4095 1656 - 4095 4095 1865 - 4095 4095 2102 - 4095 4095 2375 - 4095 4095 2677 - 4095 4095 2991 - 4095 4095 3295 - 4095 4095 3588 - 4095 4095 3852 - 4095 4095 4057 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 0 - 4095 4095 36 - 4095 4095 119 - 4095 4095 242 - 4095 4095 387 - 4095 4095 543 - 4095 4095 704 - 4095 4095 858 - 4095 4095 1006 - 4095 4095 1152 - 4095 4095 1303 - 4095 4095 1469 - 4095 4095 1656 - 4095 4095 1865 - 4095 4095 2102 - 4095 4095 2375 - 4095 4095 2677 - 4095 4095 2991 - 4095 4095 3295 - 4095 4095 3588 - 4095 4095 3852 - 4095 4095 4057 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 0 - 4095 4095 36 - 4095 4095 119 - 4095 4095 242 - 4095 4095 387 - 4095 4095 543 - 4095 4095 704 - 4095 4095 858 - 4095 4095 1006 - 4095 4095 1152 - 4095 4095 1303 - 4095 4095 1469 - 4095 4095 1656 - 4095 4095 1865 - 4095 4095 2102 - 4095 4095 2375 - 4095 4095 2677 - 4095 4095 2991 - 4095 4095 3295 - 4095 4095 3588 - 4095 4095 3852 - 4095 4095 4057 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 0 - 4095 4095 36 - 4095 4095 119 - 4095 4095 242 - 4095 4095 387 - 4095 4095 543 - 4095 4095 704 - 4095 4095 858 - 4095 4095 1006 - 4095 4095 1152 - 4095 4095 1303 - 4095 4095 1469 - 4095 4095 1656 - 4095 4095 1865 - 4095 4095 2102 - 4095 4095 2375 - 4095 4095 2677 - 4095 4095 2991 - 4095 4095 3295 - 4095 4095 3588 - 4095 4095 3852 - 4095 4095 4057 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 0 - 4095 4095 36 - 4095 4095 119 - 4095 4095 242 - 4095 4095 387 - 4095 4095 543 - 4095 4095 704 - 4095 4095 858 - 4095 4095 1006 - 4095 4095 1152 - 4095 4095 1303 - 4095 4095 1469 - 4095 4095 1656 - 4095 4095 1865 - 4095 4095 2102 - 4095 4095 2375 - 4095 4095 2677 - 4095 4095 2991 - 4095 4095 3295 - 4095 4095 3588 - 4095 4095 3852 - 4095 4095 4057 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 0 - 4095 4095 36 - 4095 4095 119 - 4095 4095 242 - 4095 4095 387 - 4095 4095 543 - 4095 4095 704 - 4095 4095 858 - 4095 4095 1006 - 4095 4095 1152 - 4095 4095 1303 - 4095 4095 1469 - 4095 4095 1656 - 4095 4095 1865 - 4095 4095 2102 - 4095 4095 2375 - 4095 4095 2677 - 4095 4095 2991 - 4095 4095 3295 - 4095 4095 3588 - 4095 4095 3852 - 4095 4095 4057 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 0 - 4095 4095 36 - 4095 4095 119 - 4095 4095 242 - 4095 4095 387 - 4095 4095 543 - 4095 4095 704 - 4095 4095 858 - 4095 4095 1006 - 4095 4095 1152 - 4095 4095 1303 - 4095 4095 1469 - 4095 4095 1656 - 4095 4095 1865 - 4095 4095 2102 - 4095 4095 2375 - 4095 4095 2677 - 4095 4095 2991 - 4095 4095 3295 - 4095 4095 3588 - 4095 4095 3852 - 4095 4095 4057 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 0 - 4095 4095 36 - 4095 4095 119 - 4095 4095 242 - 4095 4095 387 - 4095 4095 543 - 4095 4095 704 - 4095 4095 858 - 4095 4095 1006 - 4095 4095 1152 - 4095 4095 1303 - 4095 4095 1469 - 4095 4095 1656 - 4095 4095 1865 - 4095 4095 2102 - 4095 4095 2375 - 4095 4095 2677 - 4095 4095 2991 - 4095 4095 3295 - 4095 4095 3588 - 4095 4095 3852 - 4095 4095 4057 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 0 - 4095 4095 36 - 4095 4095 119 - 4095 4095 242 - 4095 4095 387 - 4095 4095 543 - 4095 4095 704 - 4095 4095 858 - 4095 4095 1006 - 4095 4095 1152 - 4095 4095 1303 - 4095 4095 1469 - 4095 4095 1656 - 4095 4095 1865 - 4095 4095 2102 - 4095 4095 2375 - 4095 4095 2677 - 4095 4095 2991 - 4095 4095 3295 - 4095 4095 3588 - 4095 4095 3852 - 4095 4095 4057 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 1 1 - 4095 1 37 - 4095 1 120 - 4095 1 242 - 4095 1 387 - 4095 1 544 - 4095 1 704 - 4095 1 859 - 4095 1 1006 - 4095 1 1152 - 4095 1 1303 - 4095 1 1470 - 4095 0 1656 - 4095 1 1865 - 4095 1 2102 - 4095 0 2375 - 4095 0 2677 - 4095 0 2991 - 4095 0 3295 - 4095 0 3588 - 4095 0 3852 - 4095 0 4057 - 4095 0 4095 - 4095 0 4095 - 4095 0 4095 - 4095 0 4095 - 4095 0 4095 - 4095 0 4095 - 4095 0 4095 - 4095 0 4095 - 4095 0 4095 - 4095 0 4095 - 4095 0 4095 - 4095 37 1 - 4095 37 37 - 4095 37 120 - 4095 37 242 - 4095 37 387 - 4095 37 544 - 4095 37 704 - 4095 37 859 - 4095 37 1006 - 4095 37 1152 - 4095 37 1303 - 4095 37 1469 - 4095 37 1656 - 4095 36 1865 - 4095 36 2102 - 4095 36 2375 - 4095 36 2677 - 4095 36 2991 - 4095 36 3295 - 4095 36 3588 - 4095 36 3852 - 4095 36 4057 - 4095 36 4095 - 4095 36 4095 - 4095 36 4095 - 4095 36 4095 - 4095 36 4095 - 4095 36 4095 - 4095 36 4095 - 4095 36 4095 - 4095 36 4095 - 4095 36 4095 - 4095 36 4095 - 4095 120 0 - 4095 120 37 - 4095 120 120 - 4095 120 242 - 4095 120 387 - 4095 120 544 - 4095 120 704 - 4095 120 859 - 4095 120 1006 - 4095 120 1152 - 4095 120 1303 - 4095 120 1469 - 4095 120 1656 - 4095 120 1865 - 4095 120 2102 - 4095 120 2375 - 4095 120 2677 - 4095 119 2991 - 4095 119 3295 - 4095 119 3588 - 4095 119 3852 - 4095 119 4057 - 4095 119 4095 - 4095 119 4095 - 4095 119 4095 - 4095 119 4095 - 4095 119 4095 - 4095 119 4095 - 4095 119 4095 - 4095 119 4095 - 4095 119 4095 - 4095 119 4095 - 4095 119 4095 - 4095 242 1 - 4095 242 37 - 4095 242 120 - 4095 242 242 - 4095 242 387 - 4095 242 544 - 4095 242 704 - 4095 242 859 - 4095 242 1006 - 4095 242 1152 - 4095 242 1303 - 4095 242 1469 - 4095 242 1656 - 4095 242 1865 - 4095 242 2102 - 4095 242 2375 - 4095 242 2677 - 4095 242 2991 - 4095 242 3295 - 4095 242 3588 - 4095 242 3852 - 4095 242 4057 - 4095 242 4095 - 4095 242 4095 - 4095 242 4095 - 4095 242 4095 - 4095 242 4095 - 4095 242 4095 - 4095 242 4095 - 4095 242 4095 - 4095 242 4095 - 4095 242 4095 - 4095 242 4095 - 4095 387 1 - 4095 387 37 - 4095 387 120 - 4095 387 242 - 4095 387 387 - 4095 387 543 - 4095 387 704 - 4095 387 859 - 4095 387 1006 - 4095 387 1152 - 4095 387 1303 - 4095 387 1469 - 4095 387 1656 - 4095 387 1865 - 4095 387 2102 - 4095 387 2375 - 4095 387 2677 - 4095 387 2991 - 4095 387 3295 - 4095 387 3588 - 4095 387 3852 - 4095 387 4057 - 4095 387 4095 - 4095 387 4095 - 4095 387 4095 - 4095 387 4095 - 4095 387 4095 - 4095 387 4095 - 4095 387 4095 - 4095 387 4095 - 4095 387 4095 - 4095 387 4095 - 4095 387 4095 - 4095 543 1 - 4095 543 36 - 4095 543 120 - 4095 543 242 - 4095 543 387 - 4095 543 543 - 4095 543 704 - 4095 543 858 - 4095 543 1006 - 4095 543 1152 - 4095 543 1303 - 4095 543 1469 - 4095 543 1656 - 4095 543 1865 - 4095 543 2102 - 4095 543 2375 - 4095 543 2677 - 4095 543 2991 - 4095 543 3295 - 4095 543 3588 - 4095 543 3852 - 4095 543 4057 - 4095 543 4095 - 4095 543 4095 - 4095 543 4095 - 4095 543 4095 - 4095 543 4095 - 4095 543 4095 - 4095 543 4095 - 4095 543 4095 - 4095 543 4095 - 4095 543 4095 - 4095 543 4095 - 4095 704 0 - 4095 704 36 - 4095 704 120 - 4095 704 242 - 4095 704 387 - 4095 704 543 - 4095 704 704 - 4095 704 858 - 4095 704 1006 - 4095 704 1152 - 4095 704 1303 - 4095 704 1469 - 4095 704 1656 - 4095 704 1865 - 4095 704 2102 - 4095 704 2375 - 4095 704 2677 - 4095 704 2991 - 4095 704 3295 - 4095 704 3588 - 4095 704 3852 - 4095 704 4057 - 4095 704 4095 - 4095 704 4095 - 4095 704 4095 - 4095 704 4095 - 4095 704 4095 - 4095 704 4095 - 4095 704 4095 - 4095 704 4095 - 4095 704 4095 - 4095 704 4095 - 4095 704 4095 - 4095 858 0 - 4095 858 36 - 4095 858 120 - 4095 858 242 - 4095 858 387 - 4095 858 543 - 4095 858 704 - 4095 858 858 - 4095 858 1006 - 4095 858 1152 - 4095 858 1303 - 4095 858 1469 - 4095 858 1656 - 4095 858 1865 - 4095 858 2102 - 4095 858 2375 - 4095 858 2677 - 4095 858 2991 - 4095 858 3295 - 4095 858 3588 - 4095 858 3852 - 4095 858 4057 - 4095 858 4095 - 4095 858 4095 - 4095 858 4095 - 4095 858 4095 - 4095 858 4095 - 4095 858 4095 - 4095 858 4095 - 4095 858 4095 - 4095 858 4095 - 4095 858 4095 - 4095 858 4095 - 4095 1006 0 - 4095 1006 36 - 4095 1006 119 - 4095 1006 242 - 4095 1006 387 - 4095 1006 543 - 4095 1006 704 - 4095 1006 858 - 4095 1006 1006 - 4095 1006 1152 - 4095 1006 1303 - 4095 1006 1469 - 4095 1006 1656 - 4095 1006 1865 - 4095 1006 2102 - 4095 1006 2375 - 4095 1006 2677 - 4095 1006 2991 - 4095 1006 3295 - 4095 1006 3588 - 4095 1006 3852 - 4095 1006 4057 - 4095 1006 4095 - 4095 1006 4095 - 4095 1006 4095 - 4095 1006 4095 - 4095 1006 4095 - 4095 1006 4095 - 4095 1006 4095 - 4095 1006 4095 - 4095 1006 4095 - 4095 1006 4095 - 4095 1006 4095 - 4095 1152 0 - 4095 1152 36 - 4095 1152 119 - 4095 1152 242 - 4095 1152 387 - 4095 1152 543 - 4095 1152 704 - 4095 1152 858 - 4095 1152 1006 - 4095 1152 1152 - 4095 1152 1303 - 4095 1152 1469 - 4095 1152 1656 - 4095 1152 1865 - 4095 1152 2102 - 4095 1152 2375 - 4095 1152 2677 - 4095 1152 2991 - 4095 1152 3295 - 4095 1152 3588 - 4095 1152 3852 - 4095 1152 4057 - 4095 1152 4095 - 4095 1152 4095 - 4095 1152 4095 - 4095 1152 4095 - 4095 1152 4095 - 4095 1152 4095 - 4095 1152 4095 - 4095 1152 4095 - 4095 1152 4095 - 4095 1152 4095 - 4095 1152 4095 - 4095 1303 0 - 4095 1303 36 - 4095 1303 119 - 4095 1303 242 - 4095 1303 387 - 4095 1303 543 - 4095 1303 704 - 4095 1303 858 - 4095 1303 1006 - 4095 1303 1152 - 4095 1303 1303 - 4095 1303 1469 - 4095 1303 1656 - 4095 1303 1865 - 4095 1303 2102 - 4095 1303 2375 - 4095 1303 2677 - 4095 1303 2991 - 4095 1303 3295 - 4095 1303 3588 - 4095 1303 3852 - 4095 1303 4057 - 4095 1303 4095 - 4095 1303 4095 - 4095 1303 4095 - 4095 1303 4095 - 4095 1303 4095 - 4095 1303 4095 - 4095 1303 4095 - 4095 1303 4095 - 4095 1303 4095 - 4095 1303 4095 - 4095 1303 4095 - 4095 1469 0 - 4095 1469 36 - 4095 1469 119 - 4095 1469 242 - 4095 1469 387 - 4095 1469 543 - 4095 1469 704 - 4095 1469 858 - 4095 1469 1006 - 4095 1469 1152 - 4095 1469 1303 - 4095 1469 1469 - 4095 1469 1656 - 4095 1469 1865 - 4095 1469 2102 - 4095 1469 2375 - 4095 1469 2677 - 4095 1469 2991 - 4095 1469 3295 - 4095 1469 3588 - 4095 1469 3852 - 4095 1469 4057 - 4095 1469 4095 - 4095 1469 4095 - 4095 1469 4095 - 4095 1469 4095 - 4095 1469 4095 - 4095 1469 4095 - 4095 1469 4095 - 4095 1469 4095 - 4095 1469 4095 - 4095 1469 4095 - 4095 1469 4095 - 4095 1656 0 - 4095 1656 36 - 4095 1656 119 - 4095 1656 242 - 4095 1656 387 - 4095 1656 543 - 4095 1656 704 - 4095 1656 858 - 4095 1656 1006 - 4095 1656 1152 - 4095 1656 1303 - 4095 1656 1469 - 4095 1656 1656 - 4095 1656 1865 - 4095 1656 2102 - 4095 1656 2375 - 4095 1656 2677 - 4095 1656 2991 - 4095 1656 3295 - 4095 1656 3588 - 4095 1656 3852 - 4095 1656 4057 - 4095 1656 4095 - 4095 1656 4095 - 4095 1656 4095 - 4095 1656 4095 - 4095 1656 4095 - 4095 1656 4095 - 4095 1656 4095 - 4095 1656 4095 - 4095 1656 4095 - 4095 1656 4095 - 4095 1656 4095 - 4095 1865 0 - 4095 1865 36 - 4095 1865 119 - 4095 1865 242 - 4095 1865 387 - 4095 1865 543 - 4095 1865 704 - 4095 1865 858 - 4095 1865 1006 - 4095 1865 1152 - 4095 1865 1303 - 4095 1865 1469 - 4095 1865 1656 - 4095 1865 1865 - 4095 1865 2102 - 4095 1865 2375 - 4095 1865 2677 - 4095 1865 2991 - 4095 1865 3295 - 4095 1865 3588 - 4095 1865 3852 - 4095 1865 4057 - 4095 1865 4095 - 4095 1865 4095 - 4095 1865 4095 - 4095 1865 4095 - 4095 1865 4095 - 4095 1865 4095 - 4095 1865 4095 - 4095 1865 4095 - 4095 1865 4095 - 4095 1865 4095 - 4095 1865 4095 - 4095 2102 0 - 4095 2102 36 - 4095 2102 119 - 4095 2102 242 - 4095 2102 387 - 4095 2102 543 - 4095 2102 704 - 4095 2102 858 - 4095 2102 1006 - 4095 2102 1152 - 4095 2102 1303 - 4095 2102 1469 - 4095 2102 1656 - 4095 2102 1865 - 4095 2102 2102 - 4095 2102 2375 - 4095 2102 2677 - 4095 2102 2991 - 4095 2102 3295 - 4095 2102 3588 - 4095 2102 3852 - 4095 2102 4057 - 4095 2102 4095 - 4095 2102 4095 - 4095 2102 4095 - 4095 2102 4095 - 4095 2102 4095 - 4095 2102 4095 - 4095 2102 4095 - 4095 2102 4095 - 4095 2102 4095 - 4095 2102 4095 - 4095 2102 4095 - 4095 2375 0 - 4095 2375 36 - 4095 2375 119 - 4095 2375 242 - 4095 2375 387 - 4095 2375 543 - 4095 2375 704 - 4095 2375 858 - 4095 2375 1006 - 4095 2375 1152 - 4095 2375 1303 - 4095 2375 1469 - 4095 2375 1656 - 4095 2375 1865 - 4095 2375 2102 - 4095 2375 2375 - 4095 2375 2677 - 4095 2375 2991 - 4095 2375 3295 - 4095 2375 3588 - 4095 2375 3852 - 4095 2375 4057 - 4095 2375 4095 - 4095 2375 4095 - 4095 2375 4095 - 4095 2375 4095 - 4095 2375 4095 - 4095 2375 4095 - 4095 2375 4095 - 4095 2375 4095 - 4095 2375 4095 - 4095 2375 4095 - 4095 2375 4095 - 4095 2677 0 - 4095 2677 36 - 4095 2677 119 - 4095 2677 242 - 4095 2677 387 - 4095 2677 543 - 4095 2677 704 - 4095 2677 858 - 4095 2677 1006 - 4095 2677 1152 - 4095 2677 1303 - 4095 2677 1469 - 4095 2677 1656 - 4095 2677 1865 - 4095 2677 2102 - 4095 2677 2375 - 4095 2677 2677 - 4095 2677 2991 - 4095 2677 3295 - 4095 2677 3588 - 4095 2677 3852 - 4095 2677 4057 - 4095 2677 4095 - 4095 2677 4095 - 4095 2677 4095 - 4095 2677 4095 - 4095 2677 4095 - 4095 2677 4095 - 4095 2677 4095 - 4095 2677 4095 - 4095 2677 4095 - 4095 2677 4095 - 4095 2677 4095 - 4095 2991 0 - 4095 2991 36 - 4095 2991 119 - 4095 2991 242 - 4095 2991 387 - 4095 2991 543 - 4095 2991 704 - 4095 2991 858 - 4095 2991 1006 - 4095 2991 1152 - 4095 2991 1303 - 4095 2991 1469 - 4095 2991 1656 - 4095 2991 1865 - 4095 2991 2102 - 4095 2991 2375 - 4095 2991 2677 - 4095 2991 2991 - 4095 2991 3295 - 4095 2991 3588 - 4095 2991 3852 - 4095 2991 4057 - 4095 2991 4095 - 4095 2991 4095 - 4095 2991 4095 - 4095 2991 4095 - 4095 2991 4095 - 4095 2991 4095 - 4095 2991 4095 - 4095 2991 4095 - 4095 2991 4095 - 4095 2991 4095 - 4095 2991 4095 - 4095 3295 0 - 4095 3295 36 - 4095 3295 119 - 4095 3295 242 - 4095 3295 387 - 4095 3295 543 - 4095 3295 704 - 4095 3295 858 - 4095 3295 1006 - 4095 3295 1152 - 4095 3295 1303 - 4095 3295 1469 - 4095 3295 1656 - 4095 3295 1865 - 4095 3295 2102 - 4095 3295 2375 - 4095 3295 2677 - 4095 3295 2991 - 4095 3295 3295 - 4095 3295 3588 - 4095 3295 3852 - 4095 3295 4057 - 4095 3295 4095 - 4095 3295 4095 - 4095 3295 4095 - 4095 3295 4095 - 4095 3295 4095 - 4095 3295 4095 - 4095 3295 4095 - 4095 3295 4095 - 4095 3295 4095 - 4095 3295 4095 - 4095 3295 4095 - 4095 3588 0 - 4095 3588 36 - 4095 3588 119 - 4095 3588 242 - 4095 3588 387 - 4095 3588 543 - 4095 3588 704 - 4095 3588 858 - 4095 3588 1006 - 4095 3588 1152 - 4095 3588 1303 - 4095 3588 1469 - 4095 3588 1656 - 4095 3588 1865 - 4095 3588 2102 - 4095 3588 2375 - 4095 3588 2677 - 4095 3588 2991 - 4095 3588 3295 - 4095 3588 3588 - 4095 3588 3852 - 4095 3588 4057 - 4095 3588 4095 - 4095 3588 4095 - 4095 3588 4095 - 4095 3588 4095 - 4095 3588 4095 - 4095 3588 4095 - 4095 3588 4095 - 4095 3588 4095 - 4095 3588 4095 - 4095 3588 4095 - 4095 3588 4095 - 4095 3852 0 - 4095 3852 36 - 4095 3852 119 - 4095 3852 242 - 4095 3852 387 - 4095 3852 543 - 4095 3852 704 - 4095 3852 858 - 4095 3852 1006 - 4095 3852 1152 - 4095 3852 1303 - 4095 3852 1469 - 4095 3852 1656 - 4095 3852 1865 - 4095 3852 2102 - 4095 3852 2375 - 4095 3852 2677 - 4095 3852 2991 - 4095 3852 3295 - 4095 3852 3588 - 4095 3852 3852 - 4095 3852 4057 - 4095 3852 4095 - 4095 3852 4095 - 4095 3852 4095 - 4095 3852 4095 - 4095 3852 4095 - 4095 3852 4095 - 4095 3852 4095 - 4095 3852 4095 - 4095 3852 4095 - 4095 3852 4095 - 4095 3852 4095 - 4095 4057 0 - 4095 4057 36 - 4095 4057 119 - 4095 4057 242 - 4095 4057 387 - 4095 4057 543 - 4095 4057 704 - 4095 4057 858 - 4095 4057 1006 - 4095 4057 1152 - 4095 4057 1303 - 4095 4057 1469 - 4095 4057 1656 - 4095 4057 1865 - 4095 4057 2102 - 4095 4057 2375 - 4095 4057 2677 - 4095 4057 2991 - 4095 4057 3295 - 4095 4057 3588 - 4095 4057 3852 - 4095 4057 4057 - 4095 4057 4095 - 4095 4057 4095 - 4095 4057 4095 - 4095 4057 4095 - 4095 4057 4095 - 4095 4057 4095 - 4095 4057 4095 - 4095 4057 4095 - 4095 4057 4095 - 4095 4057 4095 - 4095 4057 4095 - 4095 4095 0 - 4095 4095 36 - 4095 4095 119 - 4095 4095 242 - 4095 4095 387 - 4095 4095 543 - 4095 4095 704 - 4095 4095 858 - 4095 4095 1006 - 4095 4095 1152 - 4095 4095 1303 - 4095 4095 1469 - 4095 4095 1656 - 4095 4095 1865 - 4095 4095 2102 - 4095 4095 2375 - 4095 4095 2677 - 4095 4095 2991 - 4095 4095 3295 - 4095 4095 3588 - 4095 4095 3852 - 4095 4095 4057 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 0 - 4095 4095 36 - 4095 4095 119 - 4095 4095 242 - 4095 4095 387 - 4095 4095 543 - 4095 4095 704 - 4095 4095 858 - 4095 4095 1006 - 4095 4095 1152 - 4095 4095 1303 - 4095 4095 1469 - 4095 4095 1656 - 4095 4095 1865 - 4095 4095 2102 - 4095 4095 2375 - 4095 4095 2677 - 4095 4095 2991 - 4095 4095 3295 - 4095 4095 3588 - 4095 4095 3852 - 4095 4095 4057 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 0 - 4095 4095 36 - 4095 4095 119 - 4095 4095 242 - 4095 4095 387 - 4095 4095 543 - 4095 4095 704 - 4095 4095 858 - 4095 4095 1006 - 4095 4095 1152 - 4095 4095 1303 - 4095 4095 1469 - 4095 4095 1656 - 4095 4095 1865 - 4095 4095 2102 - 4095 4095 2375 - 4095 4095 2677 - 4095 4095 2991 - 4095 4095 3295 - 4095 4095 3588 - 4095 4095 3852 - 4095 4095 4057 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 0 - 4095 4095 36 - 4095 4095 119 - 4095 4095 242 - 4095 4095 387 - 4095 4095 543 - 4095 4095 704 - 4095 4095 858 - 4095 4095 1006 - 4095 4095 1152 - 4095 4095 1303 - 4095 4095 1469 - 4095 4095 1656 - 4095 4095 1865 - 4095 4095 2102 - 4095 4095 2375 - 4095 4095 2677 - 4095 4095 2991 - 4095 4095 3295 - 4095 4095 3588 - 4095 4095 3852 - 4095 4095 4057 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 0 - 4095 4095 36 - 4095 4095 119 - 4095 4095 242 - 4095 4095 387 - 4095 4095 543 - 4095 4095 704 - 4095 4095 858 - 4095 4095 1006 - 4095 4095 1152 - 4095 4095 1303 - 4095 4095 1469 - 4095 4095 1656 - 4095 4095 1865 - 4095 4095 2102 - 4095 4095 2375 - 4095 4095 2677 - 4095 4095 2991 - 4095 4095 3295 - 4095 4095 3588 - 4095 4095 3852 - 4095 4095 4057 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 0 - 4095 4095 36 - 4095 4095 119 - 4095 4095 242 - 4095 4095 387 - 4095 4095 543 - 4095 4095 704 - 4095 4095 858 - 4095 4095 1006 - 4095 4095 1152 - 4095 4095 1303 - 4095 4095 1469 - 4095 4095 1656 - 4095 4095 1865 - 4095 4095 2102 - 4095 4095 2375 - 4095 4095 2677 - 4095 4095 2991 - 4095 4095 3295 - 4095 4095 3588 - 4095 4095 3852 - 4095 4095 4057 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 0 - 4095 4095 36 - 4095 4095 119 - 4095 4095 242 - 4095 4095 387 - 4095 4095 543 - 4095 4095 704 - 4095 4095 858 - 4095 4095 1006 - 4095 4095 1152 - 4095 4095 1303 - 4095 4095 1469 - 4095 4095 1656 - 4095 4095 1865 - 4095 4095 2102 - 4095 4095 2375 - 4095 4095 2677 - 4095 4095 2991 - 4095 4095 3295 - 4095 4095 3588 - 4095 4095 3852 - 4095 4095 4057 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 0 - 4095 4095 36 - 4095 4095 119 - 4095 4095 242 - 4095 4095 387 - 4095 4095 543 - 4095 4095 704 - 4095 4095 858 - 4095 4095 1006 - 4095 4095 1152 - 4095 4095 1303 - 4095 4095 1469 - 4095 4095 1656 - 4095 4095 1865 - 4095 4095 2102 - 4095 4095 2375 - 4095 4095 2677 - 4095 4095 2991 - 4095 4095 3295 - 4095 4095 3588 - 4095 4095 3852 - 4095 4095 4057 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 0 - 4095 4095 36 - 4095 4095 119 - 4095 4095 242 - 4095 4095 387 - 4095 4095 543 - 4095 4095 704 - 4095 4095 858 - 4095 4095 1006 - 4095 4095 1152 - 4095 4095 1303 - 4095 4095 1469 - 4095 4095 1656 - 4095 4095 1865 - 4095 4095 2102 - 4095 4095 2375 - 4095 4095 2677 - 4095 4095 2991 - 4095 4095 3295 - 4095 4095 3588 - 4095 4095 3852 - 4095 4095 4057 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 0 - 4095 4095 36 - 4095 4095 119 - 4095 4095 242 - 4095 4095 387 - 4095 4095 543 - 4095 4095 704 - 4095 4095 858 - 4095 4095 1006 - 4095 4095 1152 - 4095 4095 1303 - 4095 4095 1469 - 4095 4095 1656 - 4095 4095 1865 - 4095 4095 2102 - 4095 4095 2375 - 4095 4095 2677 - 4095 4095 2991 - 4095 4095 3295 - 4095 4095 3588 - 4095 4095 3852 - 4095 4095 4057 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 0 - 4095 4095 36 - 4095 4095 119 - 4095 4095 242 - 4095 4095 387 - 4095 4095 543 - 4095 4095 704 - 4095 4095 858 - 4095 4095 1006 - 4095 4095 1152 - 4095 4095 1303 - 4095 4095 1469 - 4095 4095 1656 - 4095 4095 1865 - 4095 4095 2102 - 4095 4095 2375 - 4095 4095 2677 - 4095 4095 2991 - 4095 4095 3295 - 4095 4095 3588 - 4095 4095 3852 - 4095 4095 4057 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 0 0 - 4095 0 36 - 4095 0 119 - 4095 0 242 - 4095 0 387 - 4095 0 543 - 4095 0 704 - 4095 0 858 - 4095 0 1006 - 4095 0 1152 - 4095 0 1303 - 4095 0 1469 - 4095 0 1656 - 4095 0 1865 - 4095 0 2102 - 4095 0 2375 - 4095 0 2677 - 4095 0 2991 - 4095 0 3295 - 4095 0 3588 - 4095 0 3852 - 4095 0 4057 - 4095 0 4095 - 4095 0 4095 - 4095 0 4095 - 4095 0 4095 - 4095 0 4095 - 4095 0 4095 - 4095 0 4095 - 4095 0 4095 - 4095 0 4095 - 4095 0 4095 - 4095 0 4095 - 4095 36 0 - 4095 36 36 - 4095 36 119 - 4095 36 242 - 4095 36 387 - 4095 36 543 - 4095 36 704 - 4095 36 858 - 4095 36 1006 - 4095 36 1152 - 4095 36 1303 - 4095 36 1469 - 4095 36 1656 - 4095 36 1865 - 4095 36 2102 - 4095 36 2375 - 4095 36 2677 - 4095 36 2991 - 4095 36 3295 - 4095 36 3588 - 4095 36 3852 - 4095 36 4057 - 4095 36 4095 - 4095 36 4095 - 4095 36 4095 - 4095 36 4095 - 4095 36 4095 - 4095 36 4095 - 4095 36 4095 - 4095 36 4095 - 4095 36 4095 - 4095 36 4095 - 4095 36 4095 - 4095 119 0 - 4095 119 36 - 4095 119 119 - 4095 119 242 - 4095 119 387 - 4095 119 543 - 4095 119 704 - 4095 119 858 - 4095 119 1006 - 4095 119 1152 - 4095 119 1303 - 4095 119 1469 - 4095 119 1656 - 4095 119 1865 - 4095 119 2102 - 4095 119 2375 - 4095 119 2677 - 4095 119 2991 - 4095 119 3295 - 4095 119 3588 - 4095 119 3852 - 4095 119 4057 - 4095 119 4095 - 4095 119 4095 - 4095 119 4095 - 4095 119 4095 - 4095 119 4095 - 4095 119 4095 - 4095 119 4095 - 4095 119 4095 - 4095 119 4095 - 4095 119 4095 - 4095 119 4095 - 4095 242 0 - 4095 242 36 - 4095 242 119 - 4095 242 242 - 4095 242 387 - 4095 242 543 - 4095 242 704 - 4095 242 858 - 4095 242 1006 - 4095 242 1152 - 4095 242 1303 - 4095 242 1469 - 4095 242 1656 - 4095 242 1865 - 4095 242 2102 - 4095 242 2375 - 4095 242 2677 - 4095 242 2991 - 4095 242 3295 - 4095 242 3588 - 4095 242 3852 - 4095 242 4057 - 4095 242 4095 - 4095 242 4095 - 4095 242 4095 - 4095 242 4095 - 4095 242 4095 - 4095 242 4095 - 4095 242 4095 - 4095 242 4095 - 4095 242 4095 - 4095 242 4095 - 4095 242 4095 - 4095 387 0 - 4095 387 36 - 4095 387 119 - 4095 387 242 - 4095 387 387 - 4095 387 543 - 4095 387 704 - 4095 387 858 - 4095 387 1006 - 4095 387 1152 - 4095 387 1303 - 4095 387 1469 - 4095 387 1656 - 4095 387 1865 - 4095 387 2102 - 4095 387 2375 - 4095 387 2677 - 4095 387 2991 - 4095 387 3295 - 4095 387 3588 - 4095 387 3852 - 4095 387 4057 - 4095 387 4095 - 4095 387 4095 - 4095 387 4095 - 4095 387 4095 - 4095 387 4095 - 4095 387 4095 - 4095 387 4095 - 4095 387 4095 - 4095 387 4095 - 4095 387 4095 - 4095 387 4095 - 4095 543 0 - 4095 543 36 - 4095 543 119 - 4095 543 242 - 4095 543 387 - 4095 543 543 - 4095 543 704 - 4095 543 858 - 4095 543 1006 - 4095 543 1152 - 4095 543 1303 - 4095 543 1469 - 4095 543 1656 - 4095 543 1865 - 4095 543 2102 - 4095 543 2375 - 4095 543 2677 - 4095 543 2991 - 4095 543 3295 - 4095 543 3588 - 4095 543 3852 - 4095 543 4057 - 4095 543 4095 - 4095 543 4095 - 4095 543 4095 - 4095 543 4095 - 4095 543 4095 - 4095 543 4095 - 4095 543 4095 - 4095 543 4095 - 4095 543 4095 - 4095 543 4095 - 4095 543 4095 - 4095 704 0 - 4095 704 36 - 4095 704 119 - 4095 704 242 - 4095 704 387 - 4095 704 543 - 4095 704 704 - 4095 704 858 - 4095 704 1006 - 4095 704 1152 - 4095 704 1303 - 4095 704 1469 - 4095 704 1656 - 4095 704 1865 - 4095 704 2102 - 4095 704 2375 - 4095 704 2677 - 4095 704 2991 - 4095 704 3295 - 4095 704 3588 - 4095 704 3852 - 4095 704 4057 - 4095 704 4095 - 4095 704 4095 - 4095 704 4095 - 4095 704 4095 - 4095 704 4095 - 4095 704 4095 - 4095 704 4095 - 4095 704 4095 - 4095 704 4095 - 4095 704 4095 - 4095 704 4095 - 4095 858 0 - 4095 858 36 - 4095 858 119 - 4095 858 242 - 4095 858 387 - 4095 858 543 - 4095 858 704 - 4095 858 858 - 4095 858 1006 - 4095 858 1152 - 4095 858 1303 - 4095 858 1469 - 4095 858 1656 - 4095 858 1865 - 4095 858 2102 - 4095 858 2375 - 4095 858 2677 - 4095 858 2991 - 4095 858 3295 - 4095 858 3588 - 4095 858 3852 - 4095 858 4057 - 4095 858 4095 - 4095 858 4095 - 4095 858 4095 - 4095 858 4095 - 4095 858 4095 - 4095 858 4095 - 4095 858 4095 - 4095 858 4095 - 4095 858 4095 - 4095 858 4095 - 4095 858 4095 - 4095 1006 0 - 4095 1006 36 - 4095 1006 119 - 4095 1006 242 - 4095 1006 387 - 4095 1006 543 - 4095 1006 704 - 4095 1006 858 - 4095 1006 1006 - 4095 1006 1152 - 4095 1006 1303 - 4095 1006 1469 - 4095 1006 1656 - 4095 1006 1865 - 4095 1006 2102 - 4095 1006 2375 - 4095 1006 2677 - 4095 1006 2991 - 4095 1006 3295 - 4095 1006 3588 - 4095 1006 3852 - 4095 1006 4057 - 4095 1006 4095 - 4095 1006 4095 - 4095 1006 4095 - 4095 1006 4095 - 4095 1006 4095 - 4095 1006 4095 - 4095 1006 4095 - 4095 1006 4095 - 4095 1006 4095 - 4095 1006 4095 - 4095 1006 4095 - 4095 1152 0 - 4095 1152 36 - 4095 1152 119 - 4095 1152 242 - 4095 1152 387 - 4095 1152 543 - 4095 1152 704 - 4095 1152 858 - 4095 1152 1006 - 4095 1152 1152 - 4095 1152 1303 - 4095 1152 1469 - 4095 1152 1656 - 4095 1152 1865 - 4095 1152 2102 - 4095 1152 2375 - 4095 1152 2677 - 4095 1152 2991 - 4095 1152 3295 - 4095 1152 3588 - 4095 1152 3852 - 4095 1152 4057 - 4095 1152 4095 - 4095 1152 4095 - 4095 1152 4095 - 4095 1152 4095 - 4095 1152 4095 - 4095 1152 4095 - 4095 1152 4095 - 4095 1152 4095 - 4095 1152 4095 - 4095 1152 4095 - 4095 1152 4095 - 4095 1303 0 - 4095 1303 36 - 4095 1303 119 - 4095 1303 242 - 4095 1303 387 - 4095 1303 543 - 4095 1303 704 - 4095 1303 858 - 4095 1303 1006 - 4095 1303 1152 - 4095 1303 1303 - 4095 1303 1469 - 4095 1303 1656 - 4095 1303 1865 - 4095 1303 2102 - 4095 1303 2375 - 4095 1303 2677 - 4095 1303 2991 - 4095 1303 3295 - 4095 1303 3588 - 4095 1303 3852 - 4095 1303 4057 - 4095 1303 4095 - 4095 1303 4095 - 4095 1303 4095 - 4095 1303 4095 - 4095 1303 4095 - 4095 1303 4095 - 4095 1303 4095 - 4095 1303 4095 - 4095 1303 4095 - 4095 1303 4095 - 4095 1303 4095 - 4095 1469 0 - 4095 1469 36 - 4095 1469 119 - 4095 1469 242 - 4095 1469 387 - 4095 1469 543 - 4095 1469 704 - 4095 1469 858 - 4095 1469 1006 - 4095 1469 1152 - 4095 1469 1303 - 4095 1469 1469 - 4095 1469 1656 - 4095 1469 1865 - 4095 1469 2102 - 4095 1469 2375 - 4095 1469 2677 - 4095 1469 2991 - 4095 1469 3295 - 4095 1469 3588 - 4095 1469 3852 - 4095 1469 4057 - 4095 1469 4095 - 4095 1469 4095 - 4095 1469 4095 - 4095 1469 4095 - 4095 1469 4095 - 4095 1469 4095 - 4095 1469 4095 - 4095 1469 4095 - 4095 1469 4095 - 4095 1469 4095 - 4095 1469 4095 - 4095 1656 0 - 4095 1656 36 - 4095 1656 119 - 4095 1656 242 - 4095 1656 387 - 4095 1656 543 - 4095 1656 704 - 4095 1656 858 - 4095 1656 1006 - 4095 1656 1152 - 4095 1656 1303 - 4095 1656 1469 - 4095 1656 1656 - 4095 1656 1865 - 4095 1656 2102 - 4095 1656 2375 - 4095 1656 2677 - 4095 1656 2991 - 4095 1656 3295 - 4095 1656 3588 - 4095 1656 3852 - 4095 1656 4057 - 4095 1656 4095 - 4095 1656 4095 - 4095 1656 4095 - 4095 1656 4095 - 4095 1656 4095 - 4095 1656 4095 - 4095 1656 4095 - 4095 1656 4095 - 4095 1656 4095 - 4095 1656 4095 - 4095 1656 4095 - 4095 1865 0 - 4095 1865 36 - 4095 1865 119 - 4095 1865 242 - 4095 1865 387 - 4095 1865 543 - 4095 1865 704 - 4095 1865 858 - 4095 1865 1006 - 4095 1865 1152 - 4095 1865 1303 - 4095 1865 1469 - 4095 1865 1656 - 4095 1865 1865 - 4095 1865 2102 - 4095 1865 2375 - 4095 1865 2677 - 4095 1865 2991 - 4095 1865 3295 - 4095 1865 3588 - 4095 1865 3852 - 4095 1865 4057 - 4095 1865 4095 - 4095 1865 4095 - 4095 1865 4095 - 4095 1865 4095 - 4095 1865 4095 - 4095 1865 4095 - 4095 1865 4095 - 4095 1865 4095 - 4095 1865 4095 - 4095 1865 4095 - 4095 1865 4095 - 4095 2102 0 - 4095 2102 36 - 4095 2102 119 - 4095 2102 242 - 4095 2102 387 - 4095 2102 543 - 4095 2102 704 - 4095 2102 858 - 4095 2102 1006 - 4095 2102 1152 - 4095 2102 1303 - 4095 2102 1469 - 4095 2102 1656 - 4095 2102 1865 - 4095 2102 2102 - 4095 2102 2375 - 4095 2102 2677 - 4095 2102 2991 - 4095 2102 3295 - 4095 2102 3588 - 4095 2102 3852 - 4095 2102 4057 - 4095 2102 4095 - 4095 2102 4095 - 4095 2102 4095 - 4095 2102 4095 - 4095 2102 4095 - 4095 2102 4095 - 4095 2102 4095 - 4095 2102 4095 - 4095 2102 4095 - 4095 2102 4095 - 4095 2102 4095 - 4095 2375 0 - 4095 2375 36 - 4095 2375 119 - 4095 2375 242 - 4095 2375 387 - 4095 2375 543 - 4095 2375 704 - 4095 2375 858 - 4095 2375 1006 - 4095 2375 1152 - 4095 2375 1303 - 4095 2375 1469 - 4095 2375 1656 - 4095 2375 1865 - 4095 2375 2102 - 4095 2375 2375 - 4095 2375 2677 - 4095 2375 2991 - 4095 2375 3295 - 4095 2375 3588 - 4095 2375 3852 - 4095 2375 4057 - 4095 2375 4095 - 4095 2375 4095 - 4095 2375 4095 - 4095 2375 4095 - 4095 2375 4095 - 4095 2375 4095 - 4095 2375 4095 - 4095 2375 4095 - 4095 2375 4095 - 4095 2375 4095 - 4095 2375 4095 - 4095 2677 0 - 4095 2677 36 - 4095 2677 119 - 4095 2677 242 - 4095 2677 387 - 4095 2677 543 - 4095 2677 704 - 4095 2677 858 - 4095 2677 1006 - 4095 2677 1152 - 4095 2677 1303 - 4095 2677 1469 - 4095 2677 1656 - 4095 2677 1865 - 4095 2677 2102 - 4095 2677 2375 - 4095 2677 2677 - 4095 2677 2991 - 4095 2677 3295 - 4095 2677 3588 - 4095 2677 3852 - 4095 2677 4057 - 4095 2677 4095 - 4095 2677 4095 - 4095 2677 4095 - 4095 2677 4095 - 4095 2677 4095 - 4095 2677 4095 - 4095 2677 4095 - 4095 2677 4095 - 4095 2677 4095 - 4095 2677 4095 - 4095 2677 4095 - 4095 2991 0 - 4095 2991 36 - 4095 2991 119 - 4095 2991 242 - 4095 2991 387 - 4095 2991 543 - 4095 2991 704 - 4095 2991 858 - 4095 2991 1006 - 4095 2991 1152 - 4095 2991 1303 - 4095 2991 1469 - 4095 2991 1656 - 4095 2991 1865 - 4095 2991 2102 - 4095 2991 2375 - 4095 2991 2677 - 4095 2991 2991 - 4095 2991 3295 - 4095 2991 3588 - 4095 2991 3852 - 4095 2991 4057 - 4095 2991 4095 - 4095 2991 4095 - 4095 2991 4095 - 4095 2991 4095 - 4095 2991 4095 - 4095 2991 4095 - 4095 2991 4095 - 4095 2991 4095 - 4095 2991 4095 - 4095 2991 4095 - 4095 2991 4095 - 4095 3295 0 - 4095 3295 36 - 4095 3295 119 - 4095 3295 242 - 4095 3295 387 - 4095 3295 543 - 4095 3295 704 - 4095 3295 858 - 4095 3295 1006 - 4095 3295 1152 - 4095 3295 1303 - 4095 3295 1469 - 4095 3295 1656 - 4095 3295 1865 - 4095 3295 2102 - 4095 3295 2375 - 4095 3295 2677 - 4095 3295 2991 - 4095 3295 3295 - 4095 3295 3588 - 4095 3295 3852 - 4095 3295 4057 - 4095 3295 4095 - 4095 3295 4095 - 4095 3295 4095 - 4095 3295 4095 - 4095 3295 4095 - 4095 3295 4095 - 4095 3295 4095 - 4095 3295 4095 - 4095 3295 4095 - 4095 3295 4095 - 4095 3295 4095 - 4095 3588 0 - 4095 3588 36 - 4095 3588 119 - 4095 3588 242 - 4095 3588 387 - 4095 3588 543 - 4095 3588 704 - 4095 3588 858 - 4095 3588 1006 - 4095 3588 1152 - 4095 3588 1303 - 4095 3588 1469 - 4095 3588 1656 - 4095 3588 1865 - 4095 3588 2102 - 4095 3588 2375 - 4095 3588 2677 - 4095 3588 2991 - 4095 3588 3295 - 4095 3588 3588 - 4095 3588 3852 - 4095 3588 4057 - 4095 3588 4095 - 4095 3588 4095 - 4095 3588 4095 - 4095 3588 4095 - 4095 3588 4095 - 4095 3588 4095 - 4095 3588 4095 - 4095 3588 4095 - 4095 3588 4095 - 4095 3588 4095 - 4095 3588 4095 - 4095 3852 0 - 4095 3852 36 - 4095 3852 119 - 4095 3852 242 - 4095 3852 387 - 4095 3852 543 - 4095 3852 704 - 4095 3852 858 - 4095 3852 1006 - 4095 3852 1152 - 4095 3852 1303 - 4095 3852 1469 - 4095 3852 1656 - 4095 3852 1865 - 4095 3852 2102 - 4095 3852 2375 - 4095 3852 2677 - 4095 3852 2991 - 4095 3852 3295 - 4095 3852 3588 - 4095 3852 3852 - 4095 3852 4057 - 4095 3852 4095 - 4095 3852 4095 - 4095 3852 4095 - 4095 3852 4095 - 4095 3852 4095 - 4095 3852 4095 - 4095 3852 4095 - 4095 3852 4095 - 4095 3852 4095 - 4095 3852 4095 - 4095 3852 4095 - 4095 4057 0 - 4095 4057 36 - 4095 4057 119 - 4095 4057 242 - 4095 4057 387 - 4095 4057 543 - 4095 4057 704 - 4095 4057 858 - 4095 4057 1006 - 4095 4057 1152 - 4095 4057 1303 - 4095 4057 1469 - 4095 4057 1656 - 4095 4057 1865 - 4095 4057 2102 - 4095 4057 2375 - 4095 4057 2677 - 4095 4057 2991 - 4095 4057 3295 - 4095 4057 3588 - 4095 4057 3852 - 4095 4057 4057 - 4095 4057 4095 - 4095 4057 4095 - 4095 4057 4095 - 4095 4057 4095 - 4095 4057 4095 - 4095 4057 4095 - 4095 4057 4095 - 4095 4057 4095 - 4095 4057 4095 - 4095 4057 4095 - 4095 4057 4095 - 4095 4095 0 - 4095 4095 36 - 4095 4095 119 - 4095 4095 242 - 4095 4095 387 - 4095 4095 543 - 4095 4095 704 - 4095 4095 858 - 4095 4095 1006 - 4095 4095 1152 - 4095 4095 1303 - 4095 4095 1469 - 4095 4095 1656 - 4095 4095 1865 - 4095 4095 2102 - 4095 4095 2375 - 4095 4095 2677 - 4095 4095 2991 - 4095 4095 3295 - 4095 4095 3588 - 4095 4095 3852 - 4095 4095 4057 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 0 - 4095 4095 36 - 4095 4095 119 - 4095 4095 242 - 4095 4095 387 - 4095 4095 543 - 4095 4095 704 - 4095 4095 858 - 4095 4095 1006 - 4095 4095 1152 - 4095 4095 1303 - 4095 4095 1469 - 4095 4095 1656 - 4095 4095 1865 - 4095 4095 2102 - 4095 4095 2375 - 4095 4095 2677 - 4095 4095 2991 - 4095 4095 3295 - 4095 4095 3588 - 4095 4095 3852 - 4095 4095 4057 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 0 - 4095 4095 36 - 4095 4095 119 - 4095 4095 242 - 4095 4095 387 - 4095 4095 543 - 4095 4095 704 - 4095 4095 858 - 4095 4095 1006 - 4095 4095 1152 - 4095 4095 1303 - 4095 4095 1469 - 4095 4095 1656 - 4095 4095 1865 - 4095 4095 2102 - 4095 4095 2375 - 4095 4095 2677 - 4095 4095 2991 - 4095 4095 3295 - 4095 4095 3588 - 4095 4095 3852 - 4095 4095 4057 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 0 - 4095 4095 36 - 4095 4095 119 - 4095 4095 242 - 4095 4095 387 - 4095 4095 543 - 4095 4095 704 - 4095 4095 858 - 4095 4095 1006 - 4095 4095 1152 - 4095 4095 1303 - 4095 4095 1469 - 4095 4095 1656 - 4095 4095 1865 - 4095 4095 2102 - 4095 4095 2375 - 4095 4095 2677 - 4095 4095 2991 - 4095 4095 3295 - 4095 4095 3588 - 4095 4095 3852 - 4095 4095 4057 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 0 - 4095 4095 36 - 4095 4095 119 - 4095 4095 242 - 4095 4095 387 - 4095 4095 543 - 4095 4095 704 - 4095 4095 858 - 4095 4095 1006 - 4095 4095 1152 - 4095 4095 1303 - 4095 4095 1469 - 4095 4095 1656 - 4095 4095 1865 - 4095 4095 2102 - 4095 4095 2375 - 4095 4095 2677 - 4095 4095 2991 - 4095 4095 3295 - 4095 4095 3588 - 4095 4095 3852 - 4095 4095 4057 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 0 - 4095 4095 36 - 4095 4095 119 - 4095 4095 242 - 4095 4095 387 - 4095 4095 543 - 4095 4095 704 - 4095 4095 858 - 4095 4095 1006 - 4095 4095 1152 - 4095 4095 1303 - 4095 4095 1469 - 4095 4095 1656 - 4095 4095 1865 - 4095 4095 2102 - 4095 4095 2375 - 4095 4095 2677 - 4095 4095 2991 - 4095 4095 3295 - 4095 4095 3588 - 4095 4095 3852 - 4095 4095 4057 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 0 - 4095 4095 36 - 4095 4095 119 - 4095 4095 242 - 4095 4095 387 - 4095 4095 543 - 4095 4095 704 - 4095 4095 858 - 4095 4095 1006 - 4095 4095 1152 - 4095 4095 1303 - 4095 4095 1469 - 4095 4095 1656 - 4095 4095 1865 - 4095 4095 2102 - 4095 4095 2375 - 4095 4095 2677 - 4095 4095 2991 - 4095 4095 3295 - 4095 4095 3588 - 4095 4095 3852 - 4095 4095 4057 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 0 - 4095 4095 36 - 4095 4095 119 - 4095 4095 242 - 4095 4095 387 - 4095 4095 543 - 4095 4095 704 - 4095 4095 858 - 4095 4095 1006 - 4095 4095 1152 - 4095 4095 1303 - 4095 4095 1469 - 4095 4095 1656 - 4095 4095 1865 - 4095 4095 2102 - 4095 4095 2375 - 4095 4095 2677 - 4095 4095 2991 - 4095 4095 3295 - 4095 4095 3588 - 4095 4095 3852 - 4095 4095 4057 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 0 - 4095 4095 36 - 4095 4095 119 - 4095 4095 242 - 4095 4095 387 - 4095 4095 543 - 4095 4095 704 - 4095 4095 858 - 4095 4095 1006 - 4095 4095 1152 - 4095 4095 1303 - 4095 4095 1469 - 4095 4095 1656 - 4095 4095 1865 - 4095 4095 2102 - 4095 4095 2375 - 4095 4095 2677 - 4095 4095 2991 - 4095 4095 3295 - 4095 4095 3588 - 4095 4095 3852 - 4095 4095 4057 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 0 - 4095 4095 36 - 4095 4095 119 - 4095 4095 242 - 4095 4095 387 - 4095 4095 543 - 4095 4095 704 - 4095 4095 858 - 4095 4095 1006 - 4095 4095 1152 - 4095 4095 1303 - 4095 4095 1469 - 4095 4095 1656 - 4095 4095 1865 - 4095 4095 2102 - 4095 4095 2375 - 4095 4095 2677 - 4095 4095 2991 - 4095 4095 3295 - 4095 4095 3588 - 4095 4095 3852 - 4095 4095 4057 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 0 - 4095 4095 36 - 4095 4095 119 - 4095 4095 242 - 4095 4095 387 - 4095 4095 543 - 4095 4095 704 - 4095 4095 858 - 4095 4095 1006 - 4095 4095 1152 - 4095 4095 1303 - 4095 4095 1469 - 4095 4095 1656 - 4095 4095 1865 - 4095 4095 2102 - 4095 4095 2375 - 4095 4095 2677 - 4095 4095 2991 - 4095 4095 3295 - 4095 4095 3588 - 4095 4095 3852 - 4095 4095 4057 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 0 0 - 4095 0 36 - 4095 0 119 - 4095 0 242 - 4095 0 387 - 4095 0 543 - 4095 0 704 - 4095 0 858 - 4095 0 1006 - 4095 0 1152 - 4095 0 1303 - 4095 0 1469 - 4095 0 1656 - 4095 0 1865 - 4095 0 2102 - 4095 0 2375 - 4095 0 2677 - 4095 0 2991 - 4095 0 3295 - 4095 0 3588 - 4095 0 3852 - 4095 0 4057 - 4095 0 4095 - 4095 0 4095 - 4095 0 4095 - 4095 0 4095 - 4095 0 4095 - 4095 0 4095 - 4095 0 4095 - 4095 0 4095 - 4095 0 4095 - 4095 0 4095 - 4095 0 4095 - 4095 36 0 - 4095 36 36 - 4095 36 119 - 4095 36 242 - 4095 36 387 - 4095 36 543 - 4095 36 704 - 4095 36 858 - 4095 36 1006 - 4095 36 1152 - 4095 36 1303 - 4095 36 1469 - 4095 36 1656 - 4095 36 1865 - 4095 36 2102 - 4095 36 2375 - 4095 36 2677 - 4095 36 2991 - 4095 36 3295 - 4095 36 3588 - 4095 36 3852 - 4095 36 4057 - 4095 36 4095 - 4095 36 4095 - 4095 36 4095 - 4095 36 4095 - 4095 36 4095 - 4095 36 4095 - 4095 36 4095 - 4095 36 4095 - 4095 36 4095 - 4095 36 4095 - 4095 36 4095 - 4095 119 0 - 4095 119 36 - 4095 119 119 - 4095 119 242 - 4095 119 387 - 4095 119 543 - 4095 119 704 - 4095 119 858 - 4095 119 1006 - 4095 119 1152 - 4095 119 1303 - 4095 119 1469 - 4095 119 1656 - 4095 119 1865 - 4095 119 2102 - 4095 119 2375 - 4095 119 2677 - 4095 119 2991 - 4095 119 3295 - 4095 119 3588 - 4095 119 3852 - 4095 119 4057 - 4095 119 4095 - 4095 119 4095 - 4095 119 4095 - 4095 119 4095 - 4095 119 4095 - 4095 119 4095 - 4095 119 4095 - 4095 119 4095 - 4095 119 4095 - 4095 119 4095 - 4095 119 4095 - 4095 242 0 - 4095 242 36 - 4095 242 119 - 4095 242 242 - 4095 242 387 - 4095 242 543 - 4095 242 704 - 4095 242 858 - 4095 242 1006 - 4095 242 1152 - 4095 242 1303 - 4095 242 1469 - 4095 242 1656 - 4095 242 1865 - 4095 242 2102 - 4095 242 2375 - 4095 242 2677 - 4095 242 2991 - 4095 242 3295 - 4095 242 3588 - 4095 242 3852 - 4095 242 4057 - 4095 242 4095 - 4095 242 4095 - 4095 242 4095 - 4095 242 4095 - 4095 242 4095 - 4095 242 4095 - 4095 242 4095 - 4095 242 4095 - 4095 242 4095 - 4095 242 4095 - 4095 242 4095 - 4095 387 0 - 4095 387 36 - 4095 387 119 - 4095 387 242 - 4095 387 387 - 4095 387 543 - 4095 387 704 - 4095 387 858 - 4095 387 1006 - 4095 387 1152 - 4095 387 1303 - 4095 387 1469 - 4095 387 1656 - 4095 387 1865 - 4095 387 2102 - 4095 387 2375 - 4095 387 2677 - 4095 387 2991 - 4095 387 3295 - 4095 387 3588 - 4095 387 3852 - 4095 387 4057 - 4095 387 4095 - 4095 387 4095 - 4095 387 4095 - 4095 387 4095 - 4095 387 4095 - 4095 387 4095 - 4095 387 4095 - 4095 387 4095 - 4095 387 4095 - 4095 387 4095 - 4095 387 4095 - 4095 543 0 - 4095 543 36 - 4095 543 119 - 4095 543 242 - 4095 543 387 - 4095 543 543 - 4095 543 704 - 4095 543 858 - 4095 543 1006 - 4095 543 1152 - 4095 543 1303 - 4095 543 1469 - 4095 543 1656 - 4095 543 1865 - 4095 543 2102 - 4095 543 2375 - 4095 543 2677 - 4095 543 2991 - 4095 543 3295 - 4095 543 3588 - 4095 543 3852 - 4095 543 4057 - 4095 543 4095 - 4095 543 4095 - 4095 543 4095 - 4095 543 4095 - 4095 543 4095 - 4095 543 4095 - 4095 543 4095 - 4095 543 4095 - 4095 543 4095 - 4095 543 4095 - 4095 543 4095 - 4095 704 0 - 4095 704 36 - 4095 704 119 - 4095 704 242 - 4095 704 387 - 4095 704 543 - 4095 704 704 - 4095 704 858 - 4095 704 1006 - 4095 704 1152 - 4095 704 1303 - 4095 704 1469 - 4095 704 1656 - 4095 704 1865 - 4095 704 2102 - 4095 704 2375 - 4095 704 2677 - 4095 704 2991 - 4095 704 3295 - 4095 704 3588 - 4095 704 3852 - 4095 704 4057 - 4095 704 4095 - 4095 704 4095 - 4095 704 4095 - 4095 704 4095 - 4095 704 4095 - 4095 704 4095 - 4095 704 4095 - 4095 704 4095 - 4095 704 4095 - 4095 704 4095 - 4095 704 4095 - 4095 858 0 - 4095 858 36 - 4095 858 119 - 4095 858 242 - 4095 858 387 - 4095 858 543 - 4095 858 704 - 4095 858 858 - 4095 858 1006 - 4095 858 1152 - 4095 858 1303 - 4095 858 1469 - 4095 858 1656 - 4095 858 1865 - 4095 858 2102 - 4095 858 2375 - 4095 858 2677 - 4095 858 2991 - 4095 858 3295 - 4095 858 3588 - 4095 858 3852 - 4095 858 4057 - 4095 858 4095 - 4095 858 4095 - 4095 858 4095 - 4095 858 4095 - 4095 858 4095 - 4095 858 4095 - 4095 858 4095 - 4095 858 4095 - 4095 858 4095 - 4095 858 4095 - 4095 858 4095 - 4095 1006 0 - 4095 1006 36 - 4095 1006 119 - 4095 1006 242 - 4095 1006 387 - 4095 1006 543 - 4095 1006 704 - 4095 1006 858 - 4095 1006 1006 - 4095 1006 1152 - 4095 1006 1303 - 4095 1006 1469 - 4095 1006 1656 - 4095 1006 1865 - 4095 1006 2102 - 4095 1006 2375 - 4095 1006 2677 - 4095 1006 2991 - 4095 1006 3295 - 4095 1006 3588 - 4095 1006 3852 - 4095 1006 4057 - 4095 1006 4095 - 4095 1006 4095 - 4095 1006 4095 - 4095 1006 4095 - 4095 1006 4095 - 4095 1006 4095 - 4095 1006 4095 - 4095 1006 4095 - 4095 1006 4095 - 4095 1006 4095 - 4095 1006 4095 - 4095 1152 0 - 4095 1152 36 - 4095 1152 119 - 4095 1152 242 - 4095 1152 387 - 4095 1152 543 - 4095 1152 704 - 4095 1152 858 - 4095 1152 1006 - 4095 1152 1152 - 4095 1152 1303 - 4095 1152 1469 - 4095 1152 1656 - 4095 1152 1865 - 4095 1152 2102 - 4095 1152 2375 - 4095 1152 2677 - 4095 1152 2991 - 4095 1152 3295 - 4095 1152 3588 - 4095 1152 3852 - 4095 1152 4057 - 4095 1152 4095 - 4095 1152 4095 - 4095 1152 4095 - 4095 1152 4095 - 4095 1152 4095 - 4095 1152 4095 - 4095 1152 4095 - 4095 1152 4095 - 4095 1152 4095 - 4095 1152 4095 - 4095 1152 4095 - 4095 1303 0 - 4095 1303 36 - 4095 1303 119 - 4095 1303 242 - 4095 1303 387 - 4095 1303 543 - 4095 1303 704 - 4095 1303 858 - 4095 1303 1006 - 4095 1303 1152 - 4095 1303 1303 - 4095 1303 1469 - 4095 1303 1656 - 4095 1303 1865 - 4095 1303 2102 - 4095 1303 2375 - 4095 1303 2677 - 4095 1303 2991 - 4095 1303 3295 - 4095 1303 3588 - 4095 1303 3852 - 4095 1303 4057 - 4095 1303 4095 - 4095 1303 4095 - 4095 1303 4095 - 4095 1303 4095 - 4095 1303 4095 - 4095 1303 4095 - 4095 1303 4095 - 4095 1303 4095 - 4095 1303 4095 - 4095 1303 4095 - 4095 1303 4095 - 4095 1469 0 - 4095 1469 36 - 4095 1469 119 - 4095 1469 242 - 4095 1469 387 - 4095 1469 543 - 4095 1469 704 - 4095 1469 858 - 4095 1469 1006 - 4095 1469 1152 - 4095 1469 1303 - 4095 1469 1469 - 4095 1469 1656 - 4095 1469 1865 - 4095 1469 2102 - 4095 1469 2375 - 4095 1469 2677 - 4095 1469 2991 - 4095 1469 3295 - 4095 1469 3588 - 4095 1469 3852 - 4095 1469 4057 - 4095 1469 4095 - 4095 1469 4095 - 4095 1469 4095 - 4095 1469 4095 - 4095 1469 4095 - 4095 1469 4095 - 4095 1469 4095 - 4095 1469 4095 - 4095 1469 4095 - 4095 1469 4095 - 4095 1469 4095 - 4095 1656 0 - 4095 1656 36 - 4095 1656 119 - 4095 1656 242 - 4095 1656 387 - 4095 1656 543 - 4095 1656 704 - 4095 1656 858 - 4095 1656 1006 - 4095 1656 1152 - 4095 1656 1303 - 4095 1656 1469 - 4095 1656 1656 - 4095 1656 1865 - 4095 1656 2102 - 4095 1656 2375 - 4095 1656 2677 - 4095 1656 2991 - 4095 1656 3295 - 4095 1656 3588 - 4095 1656 3852 - 4095 1656 4057 - 4095 1656 4095 - 4095 1656 4095 - 4095 1656 4095 - 4095 1656 4095 - 4095 1656 4095 - 4095 1656 4095 - 4095 1656 4095 - 4095 1656 4095 - 4095 1656 4095 - 4095 1656 4095 - 4095 1656 4095 - 4095 1865 0 - 4095 1865 36 - 4095 1865 119 - 4095 1865 242 - 4095 1865 387 - 4095 1865 543 - 4095 1865 704 - 4095 1865 858 - 4095 1865 1006 - 4095 1865 1152 - 4095 1865 1303 - 4095 1865 1469 - 4095 1865 1656 - 4095 1865 1865 - 4095 1865 2102 - 4095 1865 2375 - 4095 1865 2677 - 4095 1865 2991 - 4095 1865 3295 - 4095 1865 3588 - 4095 1865 3852 - 4095 1865 4057 - 4095 1865 4095 - 4095 1865 4095 - 4095 1865 4095 - 4095 1865 4095 - 4095 1865 4095 - 4095 1865 4095 - 4095 1865 4095 - 4095 1865 4095 - 4095 1865 4095 - 4095 1865 4095 - 4095 1865 4095 - 4095 2102 0 - 4095 2102 36 - 4095 2102 119 - 4095 2102 242 - 4095 2102 387 - 4095 2102 543 - 4095 2102 704 - 4095 2102 858 - 4095 2102 1006 - 4095 2102 1152 - 4095 2102 1303 - 4095 2102 1469 - 4095 2102 1656 - 4095 2102 1865 - 4095 2102 2102 - 4095 2102 2375 - 4095 2102 2677 - 4095 2102 2991 - 4095 2102 3295 - 4095 2102 3588 - 4095 2102 3852 - 4095 2102 4057 - 4095 2102 4095 - 4095 2102 4095 - 4095 2102 4095 - 4095 2102 4095 - 4095 2102 4095 - 4095 2102 4095 - 4095 2102 4095 - 4095 2102 4095 - 4095 2102 4095 - 4095 2102 4095 - 4095 2102 4095 - 4095 2375 0 - 4095 2375 36 - 4095 2375 119 - 4095 2375 242 - 4095 2375 387 - 4095 2375 543 - 4095 2375 704 - 4095 2375 858 - 4095 2375 1006 - 4095 2375 1152 - 4095 2375 1303 - 4095 2375 1469 - 4095 2375 1656 - 4095 2375 1865 - 4095 2375 2102 - 4095 2375 2375 - 4095 2375 2677 - 4095 2375 2991 - 4095 2375 3295 - 4095 2375 3588 - 4095 2375 3852 - 4095 2375 4057 - 4095 2375 4095 - 4095 2375 4095 - 4095 2375 4095 - 4095 2375 4095 - 4095 2375 4095 - 4095 2375 4095 - 4095 2375 4095 - 4095 2375 4095 - 4095 2375 4095 - 4095 2375 4095 - 4095 2375 4095 - 4095 2677 0 - 4095 2677 36 - 4095 2677 119 - 4095 2677 242 - 4095 2677 387 - 4095 2677 543 - 4095 2677 704 - 4095 2677 858 - 4095 2677 1006 - 4095 2677 1152 - 4095 2677 1303 - 4095 2677 1469 - 4095 2677 1656 - 4095 2677 1865 - 4095 2677 2102 - 4095 2677 2375 - 4095 2677 2677 - 4095 2677 2991 - 4095 2677 3295 - 4095 2677 3588 - 4095 2677 3852 - 4095 2677 4057 - 4095 2677 4095 - 4095 2677 4095 - 4095 2677 4095 - 4095 2677 4095 - 4095 2677 4095 - 4095 2677 4095 - 4095 2677 4095 - 4095 2677 4095 - 4095 2677 4095 - 4095 2677 4095 - 4095 2677 4095 - 4095 2991 0 - 4095 2991 36 - 4095 2991 119 - 4095 2991 242 - 4095 2991 387 - 4095 2991 543 - 4095 2991 704 - 4095 2991 858 - 4095 2991 1006 - 4095 2991 1152 - 4095 2991 1303 - 4095 2991 1469 - 4095 2991 1656 - 4095 2991 1865 - 4095 2991 2102 - 4095 2991 2375 - 4095 2991 2677 - 4095 2991 2991 - 4095 2991 3295 - 4095 2991 3588 - 4095 2991 3852 - 4095 2991 4057 - 4095 2991 4095 - 4095 2991 4095 - 4095 2991 4095 - 4095 2991 4095 - 4095 2991 4095 - 4095 2991 4095 - 4095 2991 4095 - 4095 2991 4095 - 4095 2991 4095 - 4095 2991 4095 - 4095 2991 4095 - 4095 3295 0 - 4095 3295 36 - 4095 3295 119 - 4095 3295 242 - 4095 3295 387 - 4095 3295 543 - 4095 3295 704 - 4095 3295 858 - 4095 3295 1006 - 4095 3295 1152 - 4095 3295 1303 - 4095 3295 1469 - 4095 3295 1656 - 4095 3295 1865 - 4095 3295 2102 - 4095 3295 2375 - 4095 3295 2677 - 4095 3295 2991 - 4095 3295 3295 - 4095 3295 3588 - 4095 3295 3852 - 4095 3295 4057 - 4095 3295 4095 - 4095 3295 4095 - 4095 3295 4095 - 4095 3295 4095 - 4095 3295 4095 - 4095 3295 4095 - 4095 3295 4095 - 4095 3295 4095 - 4095 3295 4095 - 4095 3295 4095 - 4095 3295 4095 - 4095 3588 0 - 4095 3588 36 - 4095 3588 119 - 4095 3588 242 - 4095 3588 387 - 4095 3588 543 - 4095 3588 704 - 4095 3588 858 - 4095 3588 1006 - 4095 3588 1152 - 4095 3588 1303 - 4095 3588 1469 - 4095 3588 1656 - 4095 3588 1865 - 4095 3588 2102 - 4095 3588 2375 - 4095 3588 2677 - 4095 3588 2991 - 4095 3588 3295 - 4095 3588 3588 - 4095 3588 3852 - 4095 3588 4057 - 4095 3588 4095 - 4095 3588 4095 - 4095 3588 4095 - 4095 3588 4095 - 4095 3588 4095 - 4095 3588 4095 - 4095 3588 4095 - 4095 3588 4095 - 4095 3588 4095 - 4095 3588 4095 - 4095 3588 4095 - 4095 3852 0 - 4095 3852 36 - 4095 3852 119 - 4095 3852 242 - 4095 3852 387 - 4095 3852 543 - 4095 3852 704 - 4095 3852 858 - 4095 3852 1006 - 4095 3852 1152 - 4095 3852 1303 - 4095 3852 1469 - 4095 3852 1656 - 4095 3852 1865 - 4095 3852 2102 - 4095 3852 2375 - 4095 3852 2677 - 4095 3852 2991 - 4095 3852 3295 - 4095 3852 3588 - 4095 3852 3852 - 4095 3852 4057 - 4095 3852 4095 - 4095 3852 4095 - 4095 3852 4095 - 4095 3852 4095 - 4095 3852 4095 - 4095 3852 4095 - 4095 3852 4095 - 4095 3852 4095 - 4095 3852 4095 - 4095 3852 4095 - 4095 3852 4095 - 4095 4057 0 - 4095 4057 36 - 4095 4057 119 - 4095 4057 242 - 4095 4057 387 - 4095 4057 543 - 4095 4057 704 - 4095 4057 858 - 4095 4057 1006 - 4095 4057 1152 - 4095 4057 1303 - 4095 4057 1469 - 4095 4057 1656 - 4095 4057 1865 - 4095 4057 2102 - 4095 4057 2375 - 4095 4057 2677 - 4095 4057 2991 - 4095 4057 3295 - 4095 4057 3588 - 4095 4057 3852 - 4095 4057 4057 - 4095 4057 4095 - 4095 4057 4095 - 4095 4057 4095 - 4095 4057 4095 - 4095 4057 4095 - 4095 4057 4095 - 4095 4057 4095 - 4095 4057 4095 - 4095 4057 4095 - 4095 4057 4095 - 4095 4057 4095 - 4095 4095 0 - 4095 4095 36 - 4095 4095 119 - 4095 4095 242 - 4095 4095 387 - 4095 4095 543 - 4095 4095 704 - 4095 4095 858 - 4095 4095 1006 - 4095 4095 1152 - 4095 4095 1303 - 4095 4095 1469 - 4095 4095 1656 - 4095 4095 1865 - 4095 4095 2102 - 4095 4095 2375 - 4095 4095 2677 - 4095 4095 2991 - 4095 4095 3295 - 4095 4095 3588 - 4095 4095 3852 - 4095 4095 4057 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 0 - 4095 4095 36 - 4095 4095 119 - 4095 4095 242 - 4095 4095 387 - 4095 4095 543 - 4095 4095 704 - 4095 4095 858 - 4095 4095 1006 - 4095 4095 1152 - 4095 4095 1303 - 4095 4095 1469 - 4095 4095 1656 - 4095 4095 1865 - 4095 4095 2102 - 4095 4095 2375 - 4095 4095 2677 - 4095 4095 2991 - 4095 4095 3295 - 4095 4095 3588 - 4095 4095 3852 - 4095 4095 4057 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 0 - 4095 4095 36 - 4095 4095 119 - 4095 4095 242 - 4095 4095 387 - 4095 4095 543 - 4095 4095 704 - 4095 4095 858 - 4095 4095 1006 - 4095 4095 1152 - 4095 4095 1303 - 4095 4095 1469 - 4095 4095 1656 - 4095 4095 1865 - 4095 4095 2102 - 4095 4095 2375 - 4095 4095 2677 - 4095 4095 2991 - 4095 4095 3295 - 4095 4095 3588 - 4095 4095 3852 - 4095 4095 4057 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 0 - 4095 4095 36 - 4095 4095 119 - 4095 4095 242 - 4095 4095 387 - 4095 4095 543 - 4095 4095 704 - 4095 4095 858 - 4095 4095 1006 - 4095 4095 1152 - 4095 4095 1303 - 4095 4095 1469 - 4095 4095 1656 - 4095 4095 1865 - 4095 4095 2102 - 4095 4095 2375 - 4095 4095 2677 - 4095 4095 2991 - 4095 4095 3295 - 4095 4095 3588 - 4095 4095 3852 - 4095 4095 4057 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 0 - 4095 4095 36 - 4095 4095 119 - 4095 4095 242 - 4095 4095 387 - 4095 4095 543 - 4095 4095 704 - 4095 4095 858 - 4095 4095 1006 - 4095 4095 1152 - 4095 4095 1303 - 4095 4095 1469 - 4095 4095 1656 - 4095 4095 1865 - 4095 4095 2102 - 4095 4095 2375 - 4095 4095 2677 - 4095 4095 2991 - 4095 4095 3295 - 4095 4095 3588 - 4095 4095 3852 - 4095 4095 4057 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 0 - 4095 4095 36 - 4095 4095 119 - 4095 4095 242 - 4095 4095 387 - 4095 4095 543 - 4095 4095 704 - 4095 4095 858 - 4095 4095 1006 - 4095 4095 1152 - 4095 4095 1303 - 4095 4095 1469 - 4095 4095 1656 - 4095 4095 1865 - 4095 4095 2102 - 4095 4095 2375 - 4095 4095 2677 - 4095 4095 2991 - 4095 4095 3295 - 4095 4095 3588 - 4095 4095 3852 - 4095 4095 4057 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 0 - 4095 4095 36 - 4095 4095 119 - 4095 4095 242 - 4095 4095 387 - 4095 4095 543 - 4095 4095 704 - 4095 4095 858 - 4095 4095 1006 - 4095 4095 1152 - 4095 4095 1303 - 4095 4095 1469 - 4095 4095 1656 - 4095 4095 1865 - 4095 4095 2102 - 4095 4095 2375 - 4095 4095 2677 - 4095 4095 2991 - 4095 4095 3295 - 4095 4095 3588 - 4095 4095 3852 - 4095 4095 4057 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 0 - 4095 4095 36 - 4095 4095 119 - 4095 4095 242 - 4095 4095 387 - 4095 4095 543 - 4095 4095 704 - 4095 4095 858 - 4095 4095 1006 - 4095 4095 1152 - 4095 4095 1303 - 4095 4095 1469 - 4095 4095 1656 - 4095 4095 1865 - 4095 4095 2102 - 4095 4095 2375 - 4095 4095 2677 - 4095 4095 2991 - 4095 4095 3295 - 4095 4095 3588 - 4095 4095 3852 - 4095 4095 4057 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 0 - 4095 4095 36 - 4095 4095 119 - 4095 4095 242 - 4095 4095 387 - 4095 4095 543 - 4095 4095 704 - 4095 4095 858 - 4095 4095 1006 - 4095 4095 1152 - 4095 4095 1303 - 4095 4095 1469 - 4095 4095 1656 - 4095 4095 1865 - 4095 4095 2102 - 4095 4095 2375 - 4095 4095 2677 - 4095 4095 2991 - 4095 4095 3295 - 4095 4095 3588 - 4095 4095 3852 - 4095 4095 4057 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 0 - 4095 4095 36 - 4095 4095 119 - 4095 4095 242 - 4095 4095 387 - 4095 4095 543 - 4095 4095 704 - 4095 4095 858 - 4095 4095 1006 - 4095 4095 1152 - 4095 4095 1303 - 4095 4095 1469 - 4095 4095 1656 - 4095 4095 1865 - 4095 4095 2102 - 4095 4095 2375 - 4095 4095 2677 - 4095 4095 2991 - 4095 4095 3295 - 4095 4095 3588 - 4095 4095 3852 - 4095 4095 4057 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 0 - 4095 4095 36 - 4095 4095 119 - 4095 4095 242 - 4095 4095 387 - 4095 4095 543 - 4095 4095 704 - 4095 4095 858 - 4095 4095 1006 - 4095 4095 1152 - 4095 4095 1303 - 4095 4095 1469 - 4095 4095 1656 - 4095 4095 1865 - 4095 4095 2102 - 4095 4095 2375 - 4095 4095 2677 - 4095 4095 2991 - 4095 4095 3295 - 4095 4095 3588 - 4095 4095 3852 - 4095 4095 4057 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 0 0 - 4095 0 36 - 4095 0 119 - 4095 0 242 - 4095 0 387 - 4095 0 543 - 4095 0 704 - 4095 0 858 - 4095 0 1006 - 4095 0 1152 - 4095 0 1303 - 4095 0 1469 - 4095 0 1656 - 4095 0 1865 - 4095 0 2102 - 4095 0 2375 - 4095 0 2677 - 4095 0 2991 - 4095 0 3295 - 4095 0 3588 - 4095 0 3852 - 4095 0 4057 - 4095 0 4095 - 4095 0 4095 - 4095 0 4095 - 4095 0 4095 - 4095 0 4095 - 4095 0 4095 - 4095 0 4095 - 4095 0 4095 - 4095 0 4095 - 4095 0 4095 - 4095 0 4095 - 4095 36 0 - 4095 36 36 - 4095 36 119 - 4095 36 242 - 4095 36 387 - 4095 36 543 - 4095 36 704 - 4095 36 858 - 4095 36 1006 - 4095 36 1152 - 4095 36 1303 - 4095 36 1469 - 4095 36 1656 - 4095 36 1865 - 4095 36 2102 - 4095 36 2375 - 4095 36 2677 - 4095 36 2991 - 4095 36 3295 - 4095 36 3588 - 4095 36 3852 - 4095 36 4057 - 4095 36 4095 - 4095 36 4095 - 4095 36 4095 - 4095 36 4095 - 4095 36 4095 - 4095 36 4095 - 4095 36 4095 - 4095 36 4095 - 4095 36 4095 - 4095 36 4095 - 4095 36 4095 - 4095 119 0 - 4095 119 36 - 4095 119 119 - 4095 119 242 - 4095 119 387 - 4095 119 543 - 4095 119 704 - 4095 119 858 - 4095 119 1006 - 4095 119 1152 - 4095 119 1303 - 4095 119 1469 - 4095 119 1656 - 4095 119 1865 - 4095 119 2102 - 4095 119 2375 - 4095 119 2677 - 4095 119 2991 - 4095 119 3295 - 4095 119 3588 - 4095 119 3852 - 4095 119 4057 - 4095 119 4095 - 4095 119 4095 - 4095 119 4095 - 4095 119 4095 - 4095 119 4095 - 4095 119 4095 - 4095 119 4095 - 4095 119 4095 - 4095 119 4095 - 4095 119 4095 - 4095 119 4095 - 4095 242 0 - 4095 242 36 - 4095 242 119 - 4095 242 242 - 4095 242 387 - 4095 242 543 - 4095 242 704 - 4095 242 858 - 4095 242 1006 - 4095 242 1152 - 4095 242 1303 - 4095 242 1469 - 4095 242 1656 - 4095 242 1865 - 4095 242 2102 - 4095 242 2375 - 4095 242 2677 - 4095 242 2991 - 4095 242 3295 - 4095 242 3588 - 4095 242 3852 - 4095 242 4057 - 4095 242 4095 - 4095 242 4095 - 4095 242 4095 - 4095 242 4095 - 4095 242 4095 - 4095 242 4095 - 4095 242 4095 - 4095 242 4095 - 4095 242 4095 - 4095 242 4095 - 4095 242 4095 - 4095 387 0 - 4095 387 36 - 4095 387 119 - 4095 387 242 - 4095 387 387 - 4095 387 543 - 4095 387 704 - 4095 387 858 - 4095 387 1006 - 4095 387 1152 - 4095 387 1303 - 4095 387 1469 - 4095 387 1656 - 4095 387 1865 - 4095 387 2102 - 4095 387 2375 - 4095 387 2677 - 4095 387 2991 - 4095 387 3295 - 4095 387 3588 - 4095 387 3852 - 4095 387 4057 - 4095 387 4095 - 4095 387 4095 - 4095 387 4095 - 4095 387 4095 - 4095 387 4095 - 4095 387 4095 - 4095 387 4095 - 4095 387 4095 - 4095 387 4095 - 4095 387 4095 - 4095 387 4095 - 4095 543 0 - 4095 543 36 - 4095 543 119 - 4095 543 242 - 4095 543 387 - 4095 543 543 - 4095 543 704 - 4095 543 858 - 4095 543 1006 - 4095 543 1152 - 4095 543 1303 - 4095 543 1469 - 4095 543 1656 - 4095 543 1865 - 4095 543 2102 - 4095 543 2375 - 4095 543 2677 - 4095 543 2991 - 4095 543 3295 - 4095 543 3588 - 4095 543 3852 - 4095 543 4057 - 4095 543 4095 - 4095 543 4095 - 4095 543 4095 - 4095 543 4095 - 4095 543 4095 - 4095 543 4095 - 4095 543 4095 - 4095 543 4095 - 4095 543 4095 - 4095 543 4095 - 4095 543 4095 - 4095 704 0 - 4095 704 36 - 4095 704 119 - 4095 704 242 - 4095 704 387 - 4095 704 543 - 4095 704 704 - 4095 704 858 - 4095 704 1006 - 4095 704 1152 - 4095 704 1303 - 4095 704 1469 - 4095 704 1656 - 4095 704 1865 - 4095 704 2102 - 4095 704 2375 - 4095 704 2677 - 4095 704 2991 - 4095 704 3295 - 4095 704 3588 - 4095 704 3852 - 4095 704 4057 - 4095 704 4095 - 4095 704 4095 - 4095 704 4095 - 4095 704 4095 - 4095 704 4095 - 4095 704 4095 - 4095 704 4095 - 4095 704 4095 - 4095 704 4095 - 4095 704 4095 - 4095 704 4095 - 4095 858 0 - 4095 858 36 - 4095 858 119 - 4095 858 242 - 4095 858 387 - 4095 858 543 - 4095 858 704 - 4095 858 858 - 4095 858 1006 - 4095 858 1152 - 4095 858 1303 - 4095 858 1469 - 4095 858 1656 - 4095 858 1865 - 4095 858 2102 - 4095 858 2375 - 4095 858 2677 - 4095 858 2991 - 4095 858 3295 - 4095 858 3588 - 4095 858 3852 - 4095 858 4057 - 4095 858 4095 - 4095 858 4095 - 4095 858 4095 - 4095 858 4095 - 4095 858 4095 - 4095 858 4095 - 4095 858 4095 - 4095 858 4095 - 4095 858 4095 - 4095 858 4095 - 4095 858 4095 - 4095 1006 0 - 4095 1006 36 - 4095 1006 119 - 4095 1006 242 - 4095 1006 387 - 4095 1006 543 - 4095 1006 704 - 4095 1006 858 - 4095 1006 1006 - 4095 1006 1152 - 4095 1006 1303 - 4095 1006 1469 - 4095 1006 1656 - 4095 1006 1865 - 4095 1006 2102 - 4095 1006 2375 - 4095 1006 2677 - 4095 1006 2991 - 4095 1006 3295 - 4095 1006 3588 - 4095 1006 3852 - 4095 1006 4057 - 4095 1006 4095 - 4095 1006 4095 - 4095 1006 4095 - 4095 1006 4095 - 4095 1006 4095 - 4095 1006 4095 - 4095 1006 4095 - 4095 1006 4095 - 4095 1006 4095 - 4095 1006 4095 - 4095 1006 4095 - 4095 1152 0 - 4095 1152 36 - 4095 1152 119 - 4095 1152 242 - 4095 1152 387 - 4095 1152 543 - 4095 1152 704 - 4095 1152 858 - 4095 1152 1006 - 4095 1152 1152 - 4095 1152 1303 - 4095 1152 1469 - 4095 1152 1656 - 4095 1152 1865 - 4095 1152 2102 - 4095 1152 2375 - 4095 1152 2677 - 4095 1152 2991 - 4095 1152 3295 - 4095 1152 3588 - 4095 1152 3852 - 4095 1152 4057 - 4095 1152 4095 - 4095 1152 4095 - 4095 1152 4095 - 4095 1152 4095 - 4095 1152 4095 - 4095 1152 4095 - 4095 1152 4095 - 4095 1152 4095 - 4095 1152 4095 - 4095 1152 4095 - 4095 1152 4095 - 4095 1303 0 - 4095 1303 36 - 4095 1303 119 - 4095 1303 242 - 4095 1303 387 - 4095 1303 543 - 4095 1303 704 - 4095 1303 858 - 4095 1303 1006 - 4095 1303 1152 - 4095 1303 1303 - 4095 1303 1469 - 4095 1303 1656 - 4095 1303 1865 - 4095 1303 2102 - 4095 1303 2375 - 4095 1303 2677 - 4095 1303 2991 - 4095 1303 3295 - 4095 1303 3588 - 4095 1303 3852 - 4095 1303 4057 - 4095 1303 4095 - 4095 1303 4095 - 4095 1303 4095 - 4095 1303 4095 - 4095 1303 4095 - 4095 1303 4095 - 4095 1303 4095 - 4095 1303 4095 - 4095 1303 4095 - 4095 1303 4095 - 4095 1303 4095 - 4095 1469 0 - 4095 1469 36 - 4095 1469 119 - 4095 1469 242 - 4095 1469 387 - 4095 1469 543 - 4095 1469 704 - 4095 1469 858 - 4095 1469 1006 - 4095 1469 1152 - 4095 1469 1303 - 4095 1469 1469 - 4095 1469 1656 - 4095 1469 1865 - 4095 1469 2102 - 4095 1469 2375 - 4095 1469 2677 - 4095 1469 2991 - 4095 1469 3295 - 4095 1469 3588 - 4095 1469 3852 - 4095 1469 4057 - 4095 1469 4095 - 4095 1469 4095 - 4095 1469 4095 - 4095 1469 4095 - 4095 1469 4095 - 4095 1469 4095 - 4095 1469 4095 - 4095 1469 4095 - 4095 1469 4095 - 4095 1469 4095 - 4095 1469 4095 - 4095 1656 0 - 4095 1656 36 - 4095 1656 119 - 4095 1656 242 - 4095 1656 387 - 4095 1656 543 - 4095 1656 704 - 4095 1656 858 - 4095 1656 1006 - 4095 1656 1152 - 4095 1656 1303 - 4095 1656 1469 - 4095 1656 1656 - 4095 1656 1865 - 4095 1656 2102 - 4095 1656 2375 - 4095 1656 2677 - 4095 1656 2991 - 4095 1656 3295 - 4095 1656 3588 - 4095 1656 3852 - 4095 1656 4057 - 4095 1656 4095 - 4095 1656 4095 - 4095 1656 4095 - 4095 1656 4095 - 4095 1656 4095 - 4095 1656 4095 - 4095 1656 4095 - 4095 1656 4095 - 4095 1656 4095 - 4095 1656 4095 - 4095 1656 4095 - 4095 1865 0 - 4095 1865 36 - 4095 1865 119 - 4095 1865 242 - 4095 1865 387 - 4095 1865 543 - 4095 1865 704 - 4095 1865 858 - 4095 1865 1006 - 4095 1865 1152 - 4095 1865 1303 - 4095 1865 1469 - 4095 1865 1656 - 4095 1865 1865 - 4095 1865 2102 - 4095 1865 2375 - 4095 1865 2677 - 4095 1865 2991 - 4095 1865 3295 - 4095 1865 3588 - 4095 1865 3852 - 4095 1865 4057 - 4095 1865 4095 - 4095 1865 4095 - 4095 1865 4095 - 4095 1865 4095 - 4095 1865 4095 - 4095 1865 4095 - 4095 1865 4095 - 4095 1865 4095 - 4095 1865 4095 - 4095 1865 4095 - 4095 1865 4095 - 4095 2102 0 - 4095 2102 36 - 4095 2102 119 - 4095 2102 242 - 4095 2102 387 - 4095 2102 543 - 4095 2102 704 - 4095 2102 858 - 4095 2102 1006 - 4095 2102 1152 - 4095 2102 1303 - 4095 2102 1469 - 4095 2102 1656 - 4095 2102 1865 - 4095 2102 2102 - 4095 2102 2375 - 4095 2102 2677 - 4095 2102 2991 - 4095 2102 3295 - 4095 2102 3588 - 4095 2102 3852 - 4095 2102 4057 - 4095 2102 4095 - 4095 2102 4095 - 4095 2102 4095 - 4095 2102 4095 - 4095 2102 4095 - 4095 2102 4095 - 4095 2102 4095 - 4095 2102 4095 - 4095 2102 4095 - 4095 2102 4095 - 4095 2102 4095 - 4095 2375 0 - 4095 2375 36 - 4095 2375 119 - 4095 2375 242 - 4095 2375 387 - 4095 2375 543 - 4095 2375 704 - 4095 2375 858 - 4095 2375 1006 - 4095 2375 1152 - 4095 2375 1303 - 4095 2375 1469 - 4095 2375 1656 - 4095 2375 1865 - 4095 2375 2102 - 4095 2375 2375 - 4095 2375 2677 - 4095 2375 2991 - 4095 2375 3295 - 4095 2375 3588 - 4095 2375 3852 - 4095 2375 4057 - 4095 2375 4095 - 4095 2375 4095 - 4095 2375 4095 - 4095 2375 4095 - 4095 2375 4095 - 4095 2375 4095 - 4095 2375 4095 - 4095 2375 4095 - 4095 2375 4095 - 4095 2375 4095 - 4095 2375 4095 - 4095 2677 0 - 4095 2677 36 - 4095 2677 119 - 4095 2677 242 - 4095 2677 387 - 4095 2677 543 - 4095 2677 704 - 4095 2677 858 - 4095 2677 1006 - 4095 2677 1152 - 4095 2677 1303 - 4095 2677 1469 - 4095 2677 1656 - 4095 2677 1865 - 4095 2677 2102 - 4095 2677 2375 - 4095 2677 2677 - 4095 2677 2991 - 4095 2677 3295 - 4095 2677 3588 - 4095 2677 3852 - 4095 2677 4057 - 4095 2677 4095 - 4095 2677 4095 - 4095 2677 4095 - 4095 2677 4095 - 4095 2677 4095 - 4095 2677 4095 - 4095 2677 4095 - 4095 2677 4095 - 4095 2677 4095 - 4095 2677 4095 - 4095 2677 4095 - 4095 2991 0 - 4095 2991 36 - 4095 2991 119 - 4095 2991 242 - 4095 2991 387 - 4095 2991 543 - 4095 2991 704 - 4095 2991 858 - 4095 2991 1006 - 4095 2991 1152 - 4095 2991 1303 - 4095 2991 1469 - 4095 2991 1656 - 4095 2991 1865 - 4095 2991 2102 - 4095 2991 2375 - 4095 2991 2677 - 4095 2991 2991 - 4095 2991 3295 - 4095 2991 3588 - 4095 2991 3852 - 4095 2991 4057 - 4095 2991 4095 - 4095 2991 4095 - 4095 2991 4095 - 4095 2991 4095 - 4095 2991 4095 - 4095 2991 4095 - 4095 2991 4095 - 4095 2991 4095 - 4095 2991 4095 - 4095 2991 4095 - 4095 2991 4095 - 4095 3295 0 - 4095 3295 36 - 4095 3295 119 - 4095 3295 242 - 4095 3295 387 - 4095 3295 543 - 4095 3295 704 - 4095 3295 858 - 4095 3295 1006 - 4095 3295 1152 - 4095 3295 1303 - 4095 3295 1469 - 4095 3295 1656 - 4095 3295 1865 - 4095 3295 2102 - 4095 3295 2375 - 4095 3295 2677 - 4095 3295 2991 - 4095 3295 3295 - 4095 3295 3588 - 4095 3295 3852 - 4095 3295 4057 - 4095 3295 4095 - 4095 3295 4095 - 4095 3295 4095 - 4095 3295 4095 - 4095 3295 4095 - 4095 3295 4095 - 4095 3295 4095 - 4095 3295 4095 - 4095 3295 4095 - 4095 3295 4095 - 4095 3295 4095 - 4095 3588 0 - 4095 3588 36 - 4095 3588 119 - 4095 3588 242 - 4095 3588 387 - 4095 3588 543 - 4095 3588 704 - 4095 3588 858 - 4095 3588 1006 - 4095 3588 1152 - 4095 3588 1303 - 4095 3588 1469 - 4095 3588 1656 - 4095 3588 1865 - 4095 3588 2102 - 4095 3588 2375 - 4095 3588 2677 - 4095 3588 2991 - 4095 3588 3295 - 4095 3588 3588 - 4095 3588 3852 - 4095 3588 4057 - 4095 3588 4095 - 4095 3588 4095 - 4095 3588 4095 - 4095 3588 4095 - 4095 3588 4095 - 4095 3588 4095 - 4095 3588 4095 - 4095 3588 4095 - 4095 3588 4095 - 4095 3588 4095 - 4095 3588 4095 - 4095 3852 0 - 4095 3852 36 - 4095 3852 119 - 4095 3852 242 - 4095 3852 387 - 4095 3852 543 - 4095 3852 704 - 4095 3852 858 - 4095 3852 1006 - 4095 3852 1152 - 4095 3852 1303 - 4095 3852 1469 - 4095 3852 1656 - 4095 3852 1865 - 4095 3852 2102 - 4095 3852 2375 - 4095 3852 2677 - 4095 3852 2991 - 4095 3852 3295 - 4095 3852 3588 - 4095 3852 3852 - 4095 3852 4057 - 4095 3852 4095 - 4095 3852 4095 - 4095 3852 4095 - 4095 3852 4095 - 4095 3852 4095 - 4095 3852 4095 - 4095 3852 4095 - 4095 3852 4095 - 4095 3852 4095 - 4095 3852 4095 - 4095 3852 4095 - 4095 4057 0 - 4095 4057 36 - 4095 4057 119 - 4095 4057 242 - 4095 4057 387 - 4095 4057 543 - 4095 4057 704 - 4095 4057 858 - 4095 4057 1006 - 4095 4057 1152 - 4095 4057 1303 - 4095 4057 1469 - 4095 4057 1656 - 4095 4057 1865 - 4095 4057 2102 - 4095 4057 2375 - 4095 4057 2677 - 4095 4057 2991 - 4095 4057 3295 - 4095 4057 3588 - 4095 4057 3852 - 4095 4057 4057 - 4095 4057 4095 - 4095 4057 4095 - 4095 4057 4095 - 4095 4057 4095 - 4095 4057 4095 - 4095 4057 4095 - 4095 4057 4095 - 4095 4057 4095 - 4095 4057 4095 - 4095 4057 4095 - 4095 4057 4095 - 4095 4095 0 - 4095 4095 36 - 4095 4095 119 - 4095 4095 242 - 4095 4095 387 - 4095 4095 543 - 4095 4095 704 - 4095 4095 858 - 4095 4095 1006 - 4095 4095 1152 - 4095 4095 1303 - 4095 4095 1469 - 4095 4095 1656 - 4095 4095 1865 - 4095 4095 2102 - 4095 4095 2375 - 4095 4095 2677 - 4095 4095 2991 - 4095 4095 3295 - 4095 4095 3588 - 4095 4095 3852 - 4095 4095 4057 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 0 - 4095 4095 36 - 4095 4095 119 - 4095 4095 242 - 4095 4095 387 - 4095 4095 543 - 4095 4095 704 - 4095 4095 858 - 4095 4095 1006 - 4095 4095 1152 - 4095 4095 1303 - 4095 4095 1469 - 4095 4095 1656 - 4095 4095 1865 - 4095 4095 2102 - 4095 4095 2375 - 4095 4095 2677 - 4095 4095 2991 - 4095 4095 3295 - 4095 4095 3588 - 4095 4095 3852 - 4095 4095 4057 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 0 - 4095 4095 36 - 4095 4095 119 - 4095 4095 242 - 4095 4095 387 - 4095 4095 543 - 4095 4095 704 - 4095 4095 858 - 4095 4095 1006 - 4095 4095 1152 - 4095 4095 1303 - 4095 4095 1469 - 4095 4095 1656 - 4095 4095 1865 - 4095 4095 2102 - 4095 4095 2375 - 4095 4095 2677 - 4095 4095 2991 - 4095 4095 3295 - 4095 4095 3588 - 4095 4095 3852 - 4095 4095 4057 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 0 - 4095 4095 36 - 4095 4095 119 - 4095 4095 242 - 4095 4095 387 - 4095 4095 543 - 4095 4095 704 - 4095 4095 858 - 4095 4095 1006 - 4095 4095 1152 - 4095 4095 1303 - 4095 4095 1469 - 4095 4095 1656 - 4095 4095 1865 - 4095 4095 2102 - 4095 4095 2375 - 4095 4095 2677 - 4095 4095 2991 - 4095 4095 3295 - 4095 4095 3588 - 4095 4095 3852 - 4095 4095 4057 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 0 - 4095 4095 36 - 4095 4095 119 - 4095 4095 242 - 4095 4095 387 - 4095 4095 543 - 4095 4095 704 - 4095 4095 858 - 4095 4095 1006 - 4095 4095 1152 - 4095 4095 1303 - 4095 4095 1469 - 4095 4095 1656 - 4095 4095 1865 - 4095 4095 2102 - 4095 4095 2375 - 4095 4095 2677 - 4095 4095 2991 - 4095 4095 3295 - 4095 4095 3588 - 4095 4095 3852 - 4095 4095 4057 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 0 - 4095 4095 36 - 4095 4095 119 - 4095 4095 242 - 4095 4095 387 - 4095 4095 543 - 4095 4095 704 - 4095 4095 858 - 4095 4095 1006 - 4095 4095 1152 - 4095 4095 1303 - 4095 4095 1469 - 4095 4095 1656 - 4095 4095 1865 - 4095 4095 2102 - 4095 4095 2375 - 4095 4095 2677 - 4095 4095 2991 - 4095 4095 3295 - 4095 4095 3588 - 4095 4095 3852 - 4095 4095 4057 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 0 - 4095 4095 36 - 4095 4095 119 - 4095 4095 242 - 4095 4095 387 - 4095 4095 543 - 4095 4095 704 - 4095 4095 858 - 4095 4095 1006 - 4095 4095 1152 - 4095 4095 1303 - 4095 4095 1469 - 4095 4095 1656 - 4095 4095 1865 - 4095 4095 2102 - 4095 4095 2375 - 4095 4095 2677 - 4095 4095 2991 - 4095 4095 3295 - 4095 4095 3588 - 4095 4095 3852 - 4095 4095 4057 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 0 - 4095 4095 36 - 4095 4095 119 - 4095 4095 242 - 4095 4095 387 - 4095 4095 543 - 4095 4095 704 - 4095 4095 858 - 4095 4095 1006 - 4095 4095 1152 - 4095 4095 1303 - 4095 4095 1469 - 4095 4095 1656 - 4095 4095 1865 - 4095 4095 2102 - 4095 4095 2375 - 4095 4095 2677 - 4095 4095 2991 - 4095 4095 3295 - 4095 4095 3588 - 4095 4095 3852 - 4095 4095 4057 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 0 - 4095 4095 36 - 4095 4095 119 - 4095 4095 242 - 4095 4095 387 - 4095 4095 543 - 4095 4095 704 - 4095 4095 858 - 4095 4095 1006 - 4095 4095 1152 - 4095 4095 1303 - 4095 4095 1469 - 4095 4095 1656 - 4095 4095 1865 - 4095 4095 2102 - 4095 4095 2375 - 4095 4095 2677 - 4095 4095 2991 - 4095 4095 3295 - 4095 4095 3588 - 4095 4095 3852 - 4095 4095 4057 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 0 - 4095 4095 36 - 4095 4095 119 - 4095 4095 242 - 4095 4095 387 - 4095 4095 543 - 4095 4095 704 - 4095 4095 858 - 4095 4095 1006 - 4095 4095 1152 - 4095 4095 1303 - 4095 4095 1469 - 4095 4095 1656 - 4095 4095 1865 - 4095 4095 2102 - 4095 4095 2375 - 4095 4095 2677 - 4095 4095 2991 - 4095 4095 3295 - 4095 4095 3588 - 4095 4095 3852 - 4095 4095 4057 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 0 - 4095 4095 36 - 4095 4095 119 - 4095 4095 242 - 4095 4095 387 - 4095 4095 543 - 4095 4095 704 - 4095 4095 858 - 4095 4095 1006 - 4095 4095 1152 - 4095 4095 1303 - 4095 4095 1469 - 4095 4095 1656 - 4095 4095 1865 - 4095 4095 2102 - 4095 4095 2375 - 4095 4095 2677 - 4095 4095 2991 - 4095 4095 3295 - 4095 4095 3588 - 4095 4095 3852 - 4095 4095 4057 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 0 0 - 4095 0 36 - 4095 0 119 - 4095 0 242 - 4095 0 387 - 4095 0 543 - 4095 0 704 - 4095 0 858 - 4095 0 1006 - 4095 0 1152 - 4095 0 1303 - 4095 0 1469 - 4095 0 1656 - 4095 0 1865 - 4095 0 2102 - 4095 0 2375 - 4095 0 2677 - 4095 0 2991 - 4095 0 3295 - 4095 0 3588 - 4095 0 3852 - 4095 0 4057 - 4095 0 4095 - 4095 0 4095 - 4095 0 4095 - 4095 0 4095 - 4095 0 4095 - 4095 0 4095 - 4095 0 4095 - 4095 0 4095 - 4095 0 4095 - 4095 0 4095 - 4095 0 4095 - 4095 36 0 - 4095 36 36 - 4095 36 119 - 4095 36 242 - 4095 36 387 - 4095 36 543 - 4095 36 704 - 4095 36 858 - 4095 36 1006 - 4095 36 1152 - 4095 36 1303 - 4095 36 1469 - 4095 36 1656 - 4095 36 1865 - 4095 36 2102 - 4095 36 2375 - 4095 36 2677 - 4095 36 2991 - 4095 36 3295 - 4095 36 3588 - 4095 36 3852 - 4095 36 4057 - 4095 36 4095 - 4095 36 4095 - 4095 36 4095 - 4095 36 4095 - 4095 36 4095 - 4095 36 4095 - 4095 36 4095 - 4095 36 4095 - 4095 36 4095 - 4095 36 4095 - 4095 36 4095 - 4095 119 0 - 4095 119 36 - 4095 119 119 - 4095 119 242 - 4095 119 387 - 4095 119 543 - 4095 119 704 - 4095 119 858 - 4095 119 1006 - 4095 119 1152 - 4095 119 1303 - 4095 119 1469 - 4095 119 1656 - 4095 119 1865 - 4095 119 2102 - 4095 119 2375 - 4095 119 2677 - 4095 119 2991 - 4095 119 3295 - 4095 119 3588 - 4095 119 3852 - 4095 119 4057 - 4095 119 4095 - 4095 119 4095 - 4095 119 4095 - 4095 119 4095 - 4095 119 4095 - 4095 119 4095 - 4095 119 4095 - 4095 119 4095 - 4095 119 4095 - 4095 119 4095 - 4095 119 4095 - 4095 242 0 - 4095 242 36 - 4095 242 119 - 4095 242 242 - 4095 242 387 - 4095 242 543 - 4095 242 704 - 4095 242 858 - 4095 242 1006 - 4095 242 1152 - 4095 242 1303 - 4095 242 1469 - 4095 242 1656 - 4095 242 1865 - 4095 242 2102 - 4095 242 2375 - 4095 242 2677 - 4095 242 2991 - 4095 242 3295 - 4095 242 3588 - 4095 242 3852 - 4095 242 4057 - 4095 242 4095 - 4095 242 4095 - 4095 242 4095 - 4095 242 4095 - 4095 242 4095 - 4095 242 4095 - 4095 242 4095 - 4095 242 4095 - 4095 242 4095 - 4095 242 4095 - 4095 242 4095 - 4095 387 0 - 4095 387 36 - 4095 387 119 - 4095 387 242 - 4095 387 387 - 4095 387 543 - 4095 387 704 - 4095 387 858 - 4095 387 1006 - 4095 387 1152 - 4095 387 1303 - 4095 387 1469 - 4095 387 1656 - 4095 387 1865 - 4095 387 2102 - 4095 387 2375 - 4095 387 2677 - 4095 387 2991 - 4095 387 3295 - 4095 387 3588 - 4095 387 3852 - 4095 387 4057 - 4095 387 4095 - 4095 387 4095 - 4095 387 4095 - 4095 387 4095 - 4095 387 4095 - 4095 387 4095 - 4095 387 4095 - 4095 387 4095 - 4095 387 4095 - 4095 387 4095 - 4095 387 4095 - 4095 543 0 - 4095 543 36 - 4095 543 119 - 4095 543 242 - 4095 543 387 - 4095 543 543 - 4095 543 704 - 4095 543 858 - 4095 543 1006 - 4095 543 1152 - 4095 543 1303 - 4095 543 1469 - 4095 543 1656 - 4095 543 1865 - 4095 543 2102 - 4095 543 2375 - 4095 543 2677 - 4095 543 2991 - 4095 543 3295 - 4095 543 3588 - 4095 543 3852 - 4095 543 4057 - 4095 543 4095 - 4095 543 4095 - 4095 543 4095 - 4095 543 4095 - 4095 543 4095 - 4095 543 4095 - 4095 543 4095 - 4095 543 4095 - 4095 543 4095 - 4095 543 4095 - 4095 543 4095 - 4095 704 0 - 4095 704 36 - 4095 704 119 - 4095 704 242 - 4095 704 387 - 4095 704 543 - 4095 704 704 - 4095 704 858 - 4095 704 1006 - 4095 704 1152 - 4095 704 1303 - 4095 704 1469 - 4095 704 1656 - 4095 704 1865 - 4095 704 2102 - 4095 704 2375 - 4095 704 2677 - 4095 704 2991 - 4095 704 3295 - 4095 704 3588 - 4095 704 3852 - 4095 704 4057 - 4095 704 4095 - 4095 704 4095 - 4095 704 4095 - 4095 704 4095 - 4095 704 4095 - 4095 704 4095 - 4095 704 4095 - 4095 704 4095 - 4095 704 4095 - 4095 704 4095 - 4095 704 4095 - 4095 858 0 - 4095 858 36 - 4095 858 119 - 4095 858 242 - 4095 858 387 - 4095 858 543 - 4095 858 704 - 4095 858 858 - 4095 858 1006 - 4095 858 1152 - 4095 858 1303 - 4095 858 1469 - 4095 858 1656 - 4095 858 1865 - 4095 858 2102 - 4095 858 2375 - 4095 858 2677 - 4095 858 2991 - 4095 858 3295 - 4095 858 3588 - 4095 858 3852 - 4095 858 4057 - 4095 858 4095 - 4095 858 4095 - 4095 858 4095 - 4095 858 4095 - 4095 858 4095 - 4095 858 4095 - 4095 858 4095 - 4095 858 4095 - 4095 858 4095 - 4095 858 4095 - 4095 858 4095 - 4095 1006 0 - 4095 1006 36 - 4095 1006 119 - 4095 1006 242 - 4095 1006 387 - 4095 1006 543 - 4095 1006 704 - 4095 1006 858 - 4095 1006 1006 - 4095 1006 1152 - 4095 1006 1303 - 4095 1006 1469 - 4095 1006 1656 - 4095 1006 1865 - 4095 1006 2102 - 4095 1006 2375 - 4095 1006 2677 - 4095 1006 2991 - 4095 1006 3295 - 4095 1006 3588 - 4095 1006 3852 - 4095 1006 4057 - 4095 1006 4095 - 4095 1006 4095 - 4095 1006 4095 - 4095 1006 4095 - 4095 1006 4095 - 4095 1006 4095 - 4095 1006 4095 - 4095 1006 4095 - 4095 1006 4095 - 4095 1006 4095 - 4095 1006 4095 - 4095 1152 0 - 4095 1152 36 - 4095 1152 119 - 4095 1152 242 - 4095 1152 387 - 4095 1152 543 - 4095 1152 704 - 4095 1152 858 - 4095 1152 1006 - 4095 1152 1152 - 4095 1152 1303 - 4095 1152 1469 - 4095 1152 1656 - 4095 1152 1865 - 4095 1152 2102 - 4095 1152 2375 - 4095 1152 2677 - 4095 1152 2991 - 4095 1152 3295 - 4095 1152 3588 - 4095 1152 3852 - 4095 1152 4057 - 4095 1152 4095 - 4095 1152 4095 - 4095 1152 4095 - 4095 1152 4095 - 4095 1152 4095 - 4095 1152 4095 - 4095 1152 4095 - 4095 1152 4095 - 4095 1152 4095 - 4095 1152 4095 - 4095 1152 4095 - 4095 1303 0 - 4095 1303 36 - 4095 1303 119 - 4095 1303 242 - 4095 1303 387 - 4095 1303 543 - 4095 1303 704 - 4095 1303 858 - 4095 1303 1006 - 4095 1303 1152 - 4095 1303 1303 - 4095 1303 1469 - 4095 1303 1656 - 4095 1303 1865 - 4095 1303 2102 - 4095 1303 2375 - 4095 1303 2677 - 4095 1303 2991 - 4095 1303 3295 - 4095 1303 3588 - 4095 1303 3852 - 4095 1303 4057 - 4095 1303 4095 - 4095 1303 4095 - 4095 1303 4095 - 4095 1303 4095 - 4095 1303 4095 - 4095 1303 4095 - 4095 1303 4095 - 4095 1303 4095 - 4095 1303 4095 - 4095 1303 4095 - 4095 1303 4095 - 4095 1469 0 - 4095 1469 36 - 4095 1469 119 - 4095 1469 242 - 4095 1469 387 - 4095 1469 543 - 4095 1469 704 - 4095 1469 858 - 4095 1469 1006 - 4095 1469 1152 - 4095 1469 1303 - 4095 1469 1469 - 4095 1469 1656 - 4095 1469 1865 - 4095 1469 2102 - 4095 1469 2375 - 4095 1469 2677 - 4095 1469 2991 - 4095 1469 3295 - 4095 1469 3588 - 4095 1469 3852 - 4095 1469 4057 - 4095 1469 4095 - 4095 1469 4095 - 4095 1469 4095 - 4095 1469 4095 - 4095 1469 4095 - 4095 1469 4095 - 4095 1469 4095 - 4095 1469 4095 - 4095 1469 4095 - 4095 1469 4095 - 4095 1469 4095 - 4095 1656 0 - 4095 1656 36 - 4095 1656 119 - 4095 1656 242 - 4095 1656 387 - 4095 1656 543 - 4095 1656 704 - 4095 1656 858 - 4095 1656 1006 - 4095 1656 1152 - 4095 1656 1303 - 4095 1656 1469 - 4095 1656 1656 - 4095 1656 1865 - 4095 1656 2102 - 4095 1656 2375 - 4095 1656 2677 - 4095 1656 2991 - 4095 1656 3295 - 4095 1656 3588 - 4095 1656 3852 - 4095 1656 4057 - 4095 1656 4095 - 4095 1656 4095 - 4095 1656 4095 - 4095 1656 4095 - 4095 1656 4095 - 4095 1656 4095 - 4095 1656 4095 - 4095 1656 4095 - 4095 1656 4095 - 4095 1656 4095 - 4095 1656 4095 - 4095 1865 0 - 4095 1865 36 - 4095 1865 119 - 4095 1865 242 - 4095 1865 387 - 4095 1865 543 - 4095 1865 704 - 4095 1865 858 - 4095 1865 1006 - 4095 1865 1152 - 4095 1865 1303 - 4095 1865 1469 - 4095 1865 1656 - 4095 1865 1865 - 4095 1865 2102 - 4095 1865 2375 - 4095 1865 2677 - 4095 1865 2991 - 4095 1865 3295 - 4095 1865 3588 - 4095 1865 3852 - 4095 1865 4057 - 4095 1865 4095 - 4095 1865 4095 - 4095 1865 4095 - 4095 1865 4095 - 4095 1865 4095 - 4095 1865 4095 - 4095 1865 4095 - 4095 1865 4095 - 4095 1865 4095 - 4095 1865 4095 - 4095 1865 4095 - 4095 2102 0 - 4095 2102 36 - 4095 2102 119 - 4095 2102 242 - 4095 2102 387 - 4095 2102 543 - 4095 2102 704 - 4095 2102 858 - 4095 2102 1006 - 4095 2102 1152 - 4095 2102 1303 - 4095 2102 1469 - 4095 2102 1656 - 4095 2102 1865 - 4095 2102 2102 - 4095 2102 2375 - 4095 2102 2677 - 4095 2102 2991 - 4095 2102 3295 - 4095 2102 3588 - 4095 2102 3852 - 4095 2102 4057 - 4095 2102 4095 - 4095 2102 4095 - 4095 2102 4095 - 4095 2102 4095 - 4095 2102 4095 - 4095 2102 4095 - 4095 2102 4095 - 4095 2102 4095 - 4095 2102 4095 - 4095 2102 4095 - 4095 2102 4095 - 4095 2375 0 - 4095 2375 36 - 4095 2375 119 - 4095 2375 242 - 4095 2375 387 - 4095 2375 543 - 4095 2375 704 - 4095 2375 858 - 4095 2375 1006 - 4095 2375 1152 - 4095 2375 1303 - 4095 2375 1469 - 4095 2375 1656 - 4095 2375 1865 - 4095 2375 2102 - 4095 2375 2375 - 4095 2375 2677 - 4095 2375 2991 - 4095 2375 3295 - 4095 2375 3588 - 4095 2375 3852 - 4095 2375 4057 - 4095 2375 4095 - 4095 2375 4095 - 4095 2375 4095 - 4095 2375 4095 - 4095 2375 4095 - 4095 2375 4095 - 4095 2375 4095 - 4095 2375 4095 - 4095 2375 4095 - 4095 2375 4095 - 4095 2375 4095 - 4095 2677 0 - 4095 2677 36 - 4095 2677 119 - 4095 2677 242 - 4095 2677 387 - 4095 2677 543 - 4095 2677 704 - 4095 2677 858 - 4095 2677 1006 - 4095 2677 1152 - 4095 2677 1303 - 4095 2677 1469 - 4095 2677 1656 - 4095 2677 1865 - 4095 2677 2102 - 4095 2677 2375 - 4095 2677 2677 - 4095 2677 2991 - 4095 2677 3295 - 4095 2677 3588 - 4095 2677 3852 - 4095 2677 4057 - 4095 2677 4095 - 4095 2677 4095 - 4095 2677 4095 - 4095 2677 4095 - 4095 2677 4095 - 4095 2677 4095 - 4095 2677 4095 - 4095 2677 4095 - 4095 2677 4095 - 4095 2677 4095 - 4095 2677 4095 - 4095 2991 0 - 4095 2991 36 - 4095 2991 119 - 4095 2991 242 - 4095 2991 387 - 4095 2991 543 - 4095 2991 704 - 4095 2991 858 - 4095 2991 1006 - 4095 2991 1152 - 4095 2991 1303 - 4095 2991 1469 - 4095 2991 1656 - 4095 2991 1865 - 4095 2991 2102 - 4095 2991 2375 - 4095 2991 2677 - 4095 2991 2991 - 4095 2991 3295 - 4095 2991 3588 - 4095 2991 3852 - 4095 2991 4057 - 4095 2991 4095 - 4095 2991 4095 - 4095 2991 4095 - 4095 2991 4095 - 4095 2991 4095 - 4095 2991 4095 - 4095 2991 4095 - 4095 2991 4095 - 4095 2991 4095 - 4095 2991 4095 - 4095 2991 4095 - 4095 3295 0 - 4095 3295 36 - 4095 3295 119 - 4095 3295 242 - 4095 3295 387 - 4095 3295 543 - 4095 3295 704 - 4095 3295 858 - 4095 3295 1006 - 4095 3295 1152 - 4095 3295 1303 - 4095 3295 1469 - 4095 3295 1656 - 4095 3295 1865 - 4095 3295 2102 - 4095 3295 2375 - 4095 3295 2677 - 4095 3295 2991 - 4095 3295 3295 - 4095 3295 3588 - 4095 3295 3852 - 4095 3295 4057 - 4095 3295 4095 - 4095 3295 4095 - 4095 3295 4095 - 4095 3295 4095 - 4095 3295 4095 - 4095 3295 4095 - 4095 3295 4095 - 4095 3295 4095 - 4095 3295 4095 - 4095 3295 4095 - 4095 3295 4095 - 4095 3588 0 - 4095 3588 36 - 4095 3588 119 - 4095 3588 242 - 4095 3588 387 - 4095 3588 543 - 4095 3588 704 - 4095 3588 858 - 4095 3588 1006 - 4095 3588 1152 - 4095 3588 1303 - 4095 3588 1469 - 4095 3588 1656 - 4095 3588 1865 - 4095 3588 2102 - 4095 3588 2375 - 4095 3588 2677 - 4095 3588 2991 - 4095 3588 3295 - 4095 3588 3588 - 4095 3588 3852 - 4095 3588 4057 - 4095 3588 4095 - 4095 3588 4095 - 4095 3588 4095 - 4095 3588 4095 - 4095 3588 4095 - 4095 3588 4095 - 4095 3588 4095 - 4095 3588 4095 - 4095 3588 4095 - 4095 3588 4095 - 4095 3588 4095 - 4095 3852 0 - 4095 3852 36 - 4095 3852 119 - 4095 3852 242 - 4095 3852 387 - 4095 3852 543 - 4095 3852 704 - 4095 3852 858 - 4095 3852 1006 - 4095 3852 1152 - 4095 3852 1303 - 4095 3852 1469 - 4095 3852 1656 - 4095 3852 1865 - 4095 3852 2102 - 4095 3852 2375 - 4095 3852 2677 - 4095 3852 2991 - 4095 3852 3295 - 4095 3852 3588 - 4095 3852 3852 - 4095 3852 4057 - 4095 3852 4095 - 4095 3852 4095 - 4095 3852 4095 - 4095 3852 4095 - 4095 3852 4095 - 4095 3852 4095 - 4095 3852 4095 - 4095 3852 4095 - 4095 3852 4095 - 4095 3852 4095 - 4095 3852 4095 - 4095 4057 0 - 4095 4057 36 - 4095 4057 119 - 4095 4057 242 - 4095 4057 387 - 4095 4057 543 - 4095 4057 704 - 4095 4057 858 - 4095 4057 1006 - 4095 4057 1152 - 4095 4057 1303 - 4095 4057 1469 - 4095 4057 1656 - 4095 4057 1865 - 4095 4057 2102 - 4095 4057 2375 - 4095 4057 2677 - 4095 4057 2991 - 4095 4057 3295 - 4095 4057 3588 - 4095 4057 3852 - 4095 4057 4057 - 4095 4057 4095 - 4095 4057 4095 - 4095 4057 4095 - 4095 4057 4095 - 4095 4057 4095 - 4095 4057 4095 - 4095 4057 4095 - 4095 4057 4095 - 4095 4057 4095 - 4095 4057 4095 - 4095 4057 4095 - 4095 4095 0 - 4095 4095 36 - 4095 4095 119 - 4095 4095 242 - 4095 4095 387 - 4095 4095 543 - 4095 4095 704 - 4095 4095 858 - 4095 4095 1006 - 4095 4095 1152 - 4095 4095 1303 - 4095 4095 1469 - 4095 4095 1656 - 4095 4095 1865 - 4095 4095 2102 - 4095 4095 2375 - 4095 4095 2677 - 4095 4095 2991 - 4095 4095 3295 - 4095 4095 3588 - 4095 4095 3852 - 4095 4095 4057 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 0 - 4095 4095 36 - 4095 4095 119 - 4095 4095 242 - 4095 4095 387 - 4095 4095 543 - 4095 4095 704 - 4095 4095 858 - 4095 4095 1006 - 4095 4095 1152 - 4095 4095 1303 - 4095 4095 1469 - 4095 4095 1656 - 4095 4095 1865 - 4095 4095 2102 - 4095 4095 2375 - 4095 4095 2677 - 4095 4095 2991 - 4095 4095 3295 - 4095 4095 3588 - 4095 4095 3852 - 4095 4095 4057 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 0 - 4095 4095 36 - 4095 4095 119 - 4095 4095 242 - 4095 4095 387 - 4095 4095 543 - 4095 4095 704 - 4095 4095 858 - 4095 4095 1006 - 4095 4095 1152 - 4095 4095 1303 - 4095 4095 1469 - 4095 4095 1656 - 4095 4095 1865 - 4095 4095 2102 - 4095 4095 2375 - 4095 4095 2677 - 4095 4095 2991 - 4095 4095 3295 - 4095 4095 3588 - 4095 4095 3852 - 4095 4095 4057 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 0 - 4095 4095 36 - 4095 4095 119 - 4095 4095 242 - 4095 4095 387 - 4095 4095 543 - 4095 4095 704 - 4095 4095 858 - 4095 4095 1006 - 4095 4095 1152 - 4095 4095 1303 - 4095 4095 1469 - 4095 4095 1656 - 4095 4095 1865 - 4095 4095 2102 - 4095 4095 2375 - 4095 4095 2677 - 4095 4095 2991 - 4095 4095 3295 - 4095 4095 3588 - 4095 4095 3852 - 4095 4095 4057 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 0 - 4095 4095 36 - 4095 4095 119 - 4095 4095 242 - 4095 4095 387 - 4095 4095 543 - 4095 4095 704 - 4095 4095 858 - 4095 4095 1006 - 4095 4095 1152 - 4095 4095 1303 - 4095 4095 1469 - 4095 4095 1656 - 4095 4095 1865 - 4095 4095 2102 - 4095 4095 2375 - 4095 4095 2677 - 4095 4095 2991 - 4095 4095 3295 - 4095 4095 3588 - 4095 4095 3852 - 4095 4095 4057 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 0 - 4095 4095 36 - 4095 4095 119 - 4095 4095 242 - 4095 4095 387 - 4095 4095 543 - 4095 4095 704 - 4095 4095 858 - 4095 4095 1006 - 4095 4095 1152 - 4095 4095 1303 - 4095 4095 1469 - 4095 4095 1656 - 4095 4095 1865 - 4095 4095 2102 - 4095 4095 2375 - 4095 4095 2677 - 4095 4095 2991 - 4095 4095 3295 - 4095 4095 3588 - 4095 4095 3852 - 4095 4095 4057 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 0 - 4095 4095 36 - 4095 4095 119 - 4095 4095 242 - 4095 4095 387 - 4095 4095 543 - 4095 4095 704 - 4095 4095 858 - 4095 4095 1006 - 4095 4095 1152 - 4095 4095 1303 - 4095 4095 1469 - 4095 4095 1656 - 4095 4095 1865 - 4095 4095 2102 - 4095 4095 2375 - 4095 4095 2677 - 4095 4095 2991 - 4095 4095 3295 - 4095 4095 3588 - 4095 4095 3852 - 4095 4095 4057 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 0 - 4095 4095 36 - 4095 4095 119 - 4095 4095 242 - 4095 4095 387 - 4095 4095 543 - 4095 4095 704 - 4095 4095 858 - 4095 4095 1006 - 4095 4095 1152 - 4095 4095 1303 - 4095 4095 1469 - 4095 4095 1656 - 4095 4095 1865 - 4095 4095 2102 - 4095 4095 2375 - 4095 4095 2677 - 4095 4095 2991 - 4095 4095 3295 - 4095 4095 3588 - 4095 4095 3852 - 4095 4095 4057 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 0 - 4095 4095 36 - 4095 4095 119 - 4095 4095 242 - 4095 4095 387 - 4095 4095 543 - 4095 4095 704 - 4095 4095 858 - 4095 4095 1006 - 4095 4095 1152 - 4095 4095 1303 - 4095 4095 1469 - 4095 4095 1656 - 4095 4095 1865 - 4095 4095 2102 - 4095 4095 2375 - 4095 4095 2677 - 4095 4095 2991 - 4095 4095 3295 - 4095 4095 3588 - 4095 4095 3852 - 4095 4095 4057 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 0 - 4095 4095 36 - 4095 4095 119 - 4095 4095 242 - 4095 4095 387 - 4095 4095 543 - 4095 4095 704 - 4095 4095 858 - 4095 4095 1006 - 4095 4095 1152 - 4095 4095 1303 - 4095 4095 1469 - 4095 4095 1656 - 4095 4095 1865 - 4095 4095 2102 - 4095 4095 2375 - 4095 4095 2677 - 4095 4095 2991 - 4095 4095 3295 - 4095 4095 3588 - 4095 4095 3852 - 4095 4095 4057 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 0 - 4095 4095 36 - 4095 4095 119 - 4095 4095 242 - 4095 4095 387 - 4095 4095 543 - 4095 4095 704 - 4095 4095 858 - 4095 4095 1006 - 4095 4095 1152 - 4095 4095 1303 - 4095 4095 1469 - 4095 4095 1656 - 4095 4095 1865 - 4095 4095 2102 - 4095 4095 2375 - 4095 4095 2677 - 4095 4095 2991 - 4095 4095 3295 - 4095 4095 3588 - 4095 4095 3852 - 4095 4095 4057 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 0 0 - 4095 0 36 - 4095 0 119 - 4095 0 242 - 4095 0 387 - 4095 0 543 - 4095 0 704 - 4095 0 858 - 4095 0 1006 - 4095 0 1152 - 4095 0 1303 - 4095 0 1469 - 4095 0 1656 - 4095 0 1865 - 4095 0 2102 - 4095 0 2375 - 4095 0 2677 - 4095 0 2991 - 4095 0 3295 - 4095 0 3588 - 4095 0 3852 - 4095 0 4057 - 4095 0 4095 - 4095 0 4095 - 4095 0 4095 - 4095 0 4095 - 4095 0 4095 - 4095 0 4095 - 4095 0 4095 - 4095 0 4095 - 4095 0 4095 - 4095 0 4095 - 4095 0 4095 - 4095 36 0 - 4095 36 36 - 4095 36 119 - 4095 36 242 - 4095 36 387 - 4095 36 543 - 4095 36 704 - 4095 36 858 - 4095 36 1006 - 4095 36 1152 - 4095 36 1303 - 4095 36 1469 - 4095 36 1656 - 4095 36 1865 - 4095 36 2102 - 4095 36 2375 - 4095 36 2677 - 4095 36 2991 - 4095 36 3295 - 4095 36 3588 - 4095 36 3852 - 4095 36 4057 - 4095 36 4095 - 4095 36 4095 - 4095 36 4095 - 4095 36 4095 - 4095 36 4095 - 4095 36 4095 - 4095 36 4095 - 4095 36 4095 - 4095 36 4095 - 4095 36 4095 - 4095 36 4095 - 4095 119 0 - 4095 119 36 - 4095 119 119 - 4095 119 242 - 4095 119 387 - 4095 119 543 - 4095 119 704 - 4095 119 858 - 4095 119 1006 - 4095 119 1152 - 4095 119 1303 - 4095 119 1469 - 4095 119 1656 - 4095 119 1865 - 4095 119 2102 - 4095 119 2375 - 4095 119 2677 - 4095 119 2991 - 4095 119 3295 - 4095 119 3588 - 4095 119 3852 - 4095 119 4057 - 4095 119 4095 - 4095 119 4095 - 4095 119 4095 - 4095 119 4095 - 4095 119 4095 - 4095 119 4095 - 4095 119 4095 - 4095 119 4095 - 4095 119 4095 - 4095 119 4095 - 4095 119 4095 - 4095 242 0 - 4095 242 36 - 4095 242 119 - 4095 242 242 - 4095 242 387 - 4095 242 543 - 4095 242 704 - 4095 242 858 - 4095 242 1006 - 4095 242 1152 - 4095 242 1303 - 4095 242 1469 - 4095 242 1656 - 4095 242 1865 - 4095 242 2102 - 4095 242 2375 - 4095 242 2677 - 4095 242 2991 - 4095 242 3295 - 4095 242 3588 - 4095 242 3852 - 4095 242 4057 - 4095 242 4095 - 4095 242 4095 - 4095 242 4095 - 4095 242 4095 - 4095 242 4095 - 4095 242 4095 - 4095 242 4095 - 4095 242 4095 - 4095 242 4095 - 4095 242 4095 - 4095 242 4095 - 4095 387 0 - 4095 387 36 - 4095 387 119 - 4095 387 242 - 4095 387 387 - 4095 387 543 - 4095 387 704 - 4095 387 858 - 4095 387 1006 - 4095 387 1152 - 4095 387 1303 - 4095 387 1469 - 4095 387 1656 - 4095 387 1865 - 4095 387 2102 - 4095 387 2375 - 4095 387 2677 - 4095 387 2991 - 4095 387 3295 - 4095 387 3588 - 4095 387 3852 - 4095 387 4057 - 4095 387 4095 - 4095 387 4095 - 4095 387 4095 - 4095 387 4095 - 4095 387 4095 - 4095 387 4095 - 4095 387 4095 - 4095 387 4095 - 4095 387 4095 - 4095 387 4095 - 4095 387 4095 - 4095 543 0 - 4095 543 36 - 4095 543 119 - 4095 543 242 - 4095 543 387 - 4095 543 543 - 4095 543 704 - 4095 543 858 - 4095 543 1006 - 4095 543 1152 - 4095 543 1303 - 4095 543 1469 - 4095 543 1656 - 4095 543 1865 - 4095 543 2102 - 4095 543 2375 - 4095 543 2677 - 4095 543 2991 - 4095 543 3295 - 4095 543 3588 - 4095 543 3852 - 4095 543 4057 - 4095 543 4095 - 4095 543 4095 - 4095 543 4095 - 4095 543 4095 - 4095 543 4095 - 4095 543 4095 - 4095 543 4095 - 4095 543 4095 - 4095 543 4095 - 4095 543 4095 - 4095 543 4095 - 4095 704 0 - 4095 704 36 - 4095 704 119 - 4095 704 242 - 4095 704 387 - 4095 704 543 - 4095 704 704 - 4095 704 858 - 4095 704 1006 - 4095 704 1152 - 4095 704 1303 - 4095 704 1469 - 4095 704 1656 - 4095 704 1865 - 4095 704 2102 - 4095 704 2375 - 4095 704 2677 - 4095 704 2991 - 4095 704 3295 - 4095 704 3588 - 4095 704 3852 - 4095 704 4057 - 4095 704 4095 - 4095 704 4095 - 4095 704 4095 - 4095 704 4095 - 4095 704 4095 - 4095 704 4095 - 4095 704 4095 - 4095 704 4095 - 4095 704 4095 - 4095 704 4095 - 4095 704 4095 - 4095 858 0 - 4095 858 36 - 4095 858 119 - 4095 858 242 - 4095 858 387 - 4095 858 543 - 4095 858 704 - 4095 858 858 - 4095 858 1006 - 4095 858 1152 - 4095 858 1303 - 4095 858 1469 - 4095 858 1656 - 4095 858 1865 - 4095 858 2102 - 4095 858 2375 - 4095 858 2677 - 4095 858 2991 - 4095 858 3295 - 4095 858 3588 - 4095 858 3852 - 4095 858 4057 - 4095 858 4095 - 4095 858 4095 - 4095 858 4095 - 4095 858 4095 - 4095 858 4095 - 4095 858 4095 - 4095 858 4095 - 4095 858 4095 - 4095 858 4095 - 4095 858 4095 - 4095 858 4095 - 4095 1006 0 - 4095 1006 36 - 4095 1006 119 - 4095 1006 242 - 4095 1006 387 - 4095 1006 543 - 4095 1006 704 - 4095 1006 858 - 4095 1006 1006 - 4095 1006 1152 - 4095 1006 1303 - 4095 1006 1469 - 4095 1006 1656 - 4095 1006 1865 - 4095 1006 2102 - 4095 1006 2375 - 4095 1006 2677 - 4095 1006 2991 - 4095 1006 3295 - 4095 1006 3588 - 4095 1006 3852 - 4095 1006 4057 - 4095 1006 4095 - 4095 1006 4095 - 4095 1006 4095 - 4095 1006 4095 - 4095 1006 4095 - 4095 1006 4095 - 4095 1006 4095 - 4095 1006 4095 - 4095 1006 4095 - 4095 1006 4095 - 4095 1006 4095 - 4095 1152 0 - 4095 1152 36 - 4095 1152 119 - 4095 1152 242 - 4095 1152 387 - 4095 1152 543 - 4095 1152 704 - 4095 1152 858 - 4095 1152 1006 - 4095 1152 1152 - 4095 1152 1303 - 4095 1152 1469 - 4095 1152 1656 - 4095 1152 1865 - 4095 1152 2102 - 4095 1152 2375 - 4095 1152 2677 - 4095 1152 2991 - 4095 1152 3295 - 4095 1152 3588 - 4095 1152 3852 - 4095 1152 4057 - 4095 1152 4095 - 4095 1152 4095 - 4095 1152 4095 - 4095 1152 4095 - 4095 1152 4095 - 4095 1152 4095 - 4095 1152 4095 - 4095 1152 4095 - 4095 1152 4095 - 4095 1152 4095 - 4095 1152 4095 - 4095 1303 0 - 4095 1303 36 - 4095 1303 119 - 4095 1303 242 - 4095 1303 387 - 4095 1303 543 - 4095 1303 704 - 4095 1303 858 - 4095 1303 1006 - 4095 1303 1152 - 4095 1303 1303 - 4095 1303 1469 - 4095 1303 1656 - 4095 1303 1865 - 4095 1303 2102 - 4095 1303 2375 - 4095 1303 2677 - 4095 1303 2991 - 4095 1303 3295 - 4095 1303 3588 - 4095 1303 3852 - 4095 1303 4057 - 4095 1303 4095 - 4095 1303 4095 - 4095 1303 4095 - 4095 1303 4095 - 4095 1303 4095 - 4095 1303 4095 - 4095 1303 4095 - 4095 1303 4095 - 4095 1303 4095 - 4095 1303 4095 - 4095 1303 4095 - 4095 1469 0 - 4095 1469 36 - 4095 1469 119 - 4095 1469 242 - 4095 1469 387 - 4095 1469 543 - 4095 1469 704 - 4095 1469 858 - 4095 1469 1006 - 4095 1469 1152 - 4095 1469 1303 - 4095 1469 1469 - 4095 1469 1656 - 4095 1469 1865 - 4095 1469 2102 - 4095 1469 2375 - 4095 1469 2677 - 4095 1469 2991 - 4095 1469 3295 - 4095 1469 3588 - 4095 1469 3852 - 4095 1469 4057 - 4095 1469 4095 - 4095 1469 4095 - 4095 1469 4095 - 4095 1469 4095 - 4095 1469 4095 - 4095 1469 4095 - 4095 1469 4095 - 4095 1469 4095 - 4095 1469 4095 - 4095 1469 4095 - 4095 1469 4095 - 4095 1656 0 - 4095 1656 36 - 4095 1656 119 - 4095 1656 242 - 4095 1656 387 - 4095 1656 543 - 4095 1656 704 - 4095 1656 858 - 4095 1656 1006 - 4095 1656 1152 - 4095 1656 1303 - 4095 1656 1469 - 4095 1656 1656 - 4095 1656 1865 - 4095 1656 2102 - 4095 1656 2375 - 4095 1656 2677 - 4095 1656 2991 - 4095 1656 3295 - 4095 1656 3588 - 4095 1656 3852 - 4095 1656 4057 - 4095 1656 4095 - 4095 1656 4095 - 4095 1656 4095 - 4095 1656 4095 - 4095 1656 4095 - 4095 1656 4095 - 4095 1656 4095 - 4095 1656 4095 - 4095 1656 4095 - 4095 1656 4095 - 4095 1656 4095 - 4095 1865 0 - 4095 1865 36 - 4095 1865 119 - 4095 1865 242 - 4095 1865 387 - 4095 1865 543 - 4095 1865 704 - 4095 1865 858 - 4095 1865 1006 - 4095 1865 1152 - 4095 1865 1303 - 4095 1865 1469 - 4095 1865 1656 - 4095 1865 1865 - 4095 1865 2102 - 4095 1865 2375 - 4095 1865 2677 - 4095 1865 2991 - 4095 1865 3295 - 4095 1865 3588 - 4095 1865 3852 - 4095 1865 4057 - 4095 1865 4095 - 4095 1865 4095 - 4095 1865 4095 - 4095 1865 4095 - 4095 1865 4095 - 4095 1865 4095 - 4095 1865 4095 - 4095 1865 4095 - 4095 1865 4095 - 4095 1865 4095 - 4095 1865 4095 - 4095 2102 0 - 4095 2102 36 - 4095 2102 119 - 4095 2102 242 - 4095 2102 387 - 4095 2102 543 - 4095 2102 704 - 4095 2102 858 - 4095 2102 1006 - 4095 2102 1152 - 4095 2102 1303 - 4095 2102 1469 - 4095 2102 1656 - 4095 2102 1865 - 4095 2102 2102 - 4095 2102 2375 - 4095 2102 2677 - 4095 2102 2991 - 4095 2102 3295 - 4095 2102 3588 - 4095 2102 3852 - 4095 2102 4057 - 4095 2102 4095 - 4095 2102 4095 - 4095 2102 4095 - 4095 2102 4095 - 4095 2102 4095 - 4095 2102 4095 - 4095 2102 4095 - 4095 2102 4095 - 4095 2102 4095 - 4095 2102 4095 - 4095 2102 4095 - 4095 2375 0 - 4095 2375 36 - 4095 2375 119 - 4095 2375 242 - 4095 2375 387 - 4095 2375 543 - 4095 2375 704 - 4095 2375 858 - 4095 2375 1006 - 4095 2375 1152 - 4095 2375 1303 - 4095 2375 1469 - 4095 2375 1656 - 4095 2375 1865 - 4095 2375 2102 - 4095 2375 2375 - 4095 2375 2677 - 4095 2375 2991 - 4095 2375 3295 - 4095 2375 3588 - 4095 2375 3852 - 4095 2375 4057 - 4095 2375 4095 - 4095 2375 4095 - 4095 2375 4095 - 4095 2375 4095 - 4095 2375 4095 - 4095 2375 4095 - 4095 2375 4095 - 4095 2375 4095 - 4095 2375 4095 - 4095 2375 4095 - 4095 2375 4095 - 4095 2677 0 - 4095 2677 36 - 4095 2677 119 - 4095 2677 242 - 4095 2677 387 - 4095 2677 543 - 4095 2677 704 - 4095 2677 858 - 4095 2677 1006 - 4095 2677 1152 - 4095 2677 1303 - 4095 2677 1469 - 4095 2677 1656 - 4095 2677 1865 - 4095 2677 2102 - 4095 2677 2375 - 4095 2677 2677 - 4095 2677 2991 - 4095 2677 3295 - 4095 2677 3588 - 4095 2677 3852 - 4095 2677 4057 - 4095 2677 4095 - 4095 2677 4095 - 4095 2677 4095 - 4095 2677 4095 - 4095 2677 4095 - 4095 2677 4095 - 4095 2677 4095 - 4095 2677 4095 - 4095 2677 4095 - 4095 2677 4095 - 4095 2677 4095 - 4095 2991 0 - 4095 2991 36 - 4095 2991 119 - 4095 2991 242 - 4095 2991 387 - 4095 2991 543 - 4095 2991 704 - 4095 2991 858 - 4095 2991 1006 - 4095 2991 1152 - 4095 2991 1303 - 4095 2991 1469 - 4095 2991 1656 - 4095 2991 1865 - 4095 2991 2102 - 4095 2991 2375 - 4095 2991 2677 - 4095 2991 2991 - 4095 2991 3295 - 4095 2991 3588 - 4095 2991 3852 - 4095 2991 4057 - 4095 2991 4095 - 4095 2991 4095 - 4095 2991 4095 - 4095 2991 4095 - 4095 2991 4095 - 4095 2991 4095 - 4095 2991 4095 - 4095 2991 4095 - 4095 2991 4095 - 4095 2991 4095 - 4095 2991 4095 - 4095 3295 0 - 4095 3295 36 - 4095 3295 119 - 4095 3295 242 - 4095 3295 387 - 4095 3295 543 - 4095 3295 704 - 4095 3295 858 - 4095 3295 1006 - 4095 3295 1152 - 4095 3295 1303 - 4095 3295 1469 - 4095 3295 1656 - 4095 3295 1865 - 4095 3295 2102 - 4095 3295 2375 - 4095 3295 2677 - 4095 3295 2991 - 4095 3295 3295 - 4095 3295 3588 - 4095 3295 3852 - 4095 3295 4057 - 4095 3295 4095 - 4095 3295 4095 - 4095 3295 4095 - 4095 3295 4095 - 4095 3295 4095 - 4095 3295 4095 - 4095 3295 4095 - 4095 3295 4095 - 4095 3295 4095 - 4095 3295 4095 - 4095 3295 4095 - 4095 3588 0 - 4095 3588 36 - 4095 3588 119 - 4095 3588 242 - 4095 3588 387 - 4095 3588 543 - 4095 3588 704 - 4095 3588 858 - 4095 3588 1006 - 4095 3588 1152 - 4095 3588 1303 - 4095 3588 1469 - 4095 3588 1656 - 4095 3588 1865 - 4095 3588 2102 - 4095 3588 2375 - 4095 3588 2677 - 4095 3588 2991 - 4095 3588 3295 - 4095 3588 3588 - 4095 3588 3852 - 4095 3588 4057 - 4095 3588 4095 - 4095 3588 4095 - 4095 3588 4095 - 4095 3588 4095 - 4095 3588 4095 - 4095 3588 4095 - 4095 3588 4095 - 4095 3588 4095 - 4095 3588 4095 - 4095 3588 4095 - 4095 3588 4095 - 4095 3852 0 - 4095 3852 36 - 4095 3852 119 - 4095 3852 242 - 4095 3852 387 - 4095 3852 543 - 4095 3852 704 - 4095 3852 858 - 4095 3852 1006 - 4095 3852 1152 - 4095 3852 1303 - 4095 3852 1469 - 4095 3852 1656 - 4095 3852 1865 - 4095 3852 2102 - 4095 3852 2375 - 4095 3852 2677 - 4095 3852 2991 - 4095 3852 3295 - 4095 3852 3588 - 4095 3852 3852 - 4095 3852 4057 - 4095 3852 4095 - 4095 3852 4095 - 4095 3852 4095 - 4095 3852 4095 - 4095 3852 4095 - 4095 3852 4095 - 4095 3852 4095 - 4095 3852 4095 - 4095 3852 4095 - 4095 3852 4095 - 4095 3852 4095 - 4095 4057 0 - 4095 4057 36 - 4095 4057 119 - 4095 4057 242 - 4095 4057 387 - 4095 4057 543 - 4095 4057 704 - 4095 4057 858 - 4095 4057 1006 - 4095 4057 1152 - 4095 4057 1303 - 4095 4057 1469 - 4095 4057 1656 - 4095 4057 1865 - 4095 4057 2102 - 4095 4057 2375 - 4095 4057 2677 - 4095 4057 2991 - 4095 4057 3295 - 4095 4057 3588 - 4095 4057 3852 - 4095 4057 4057 - 4095 4057 4095 - 4095 4057 4095 - 4095 4057 4095 - 4095 4057 4095 - 4095 4057 4095 - 4095 4057 4095 - 4095 4057 4095 - 4095 4057 4095 - 4095 4057 4095 - 4095 4057 4095 - 4095 4057 4095 - 4095 4095 0 - 4095 4095 36 - 4095 4095 119 - 4095 4095 242 - 4095 4095 387 - 4095 4095 543 - 4095 4095 704 - 4095 4095 858 - 4095 4095 1006 - 4095 4095 1152 - 4095 4095 1303 - 4095 4095 1469 - 4095 4095 1656 - 4095 4095 1865 - 4095 4095 2102 - 4095 4095 2375 - 4095 4095 2677 - 4095 4095 2991 - 4095 4095 3295 - 4095 4095 3588 - 4095 4095 3852 - 4095 4095 4057 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 0 - 4095 4095 36 - 4095 4095 119 - 4095 4095 242 - 4095 4095 387 - 4095 4095 543 - 4095 4095 704 - 4095 4095 858 - 4095 4095 1006 - 4095 4095 1152 - 4095 4095 1303 - 4095 4095 1469 - 4095 4095 1656 - 4095 4095 1865 - 4095 4095 2102 - 4095 4095 2375 - 4095 4095 2677 - 4095 4095 2991 - 4095 4095 3295 - 4095 4095 3588 - 4095 4095 3852 - 4095 4095 4057 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 0 - 4095 4095 36 - 4095 4095 119 - 4095 4095 242 - 4095 4095 387 - 4095 4095 543 - 4095 4095 704 - 4095 4095 858 - 4095 4095 1006 - 4095 4095 1152 - 4095 4095 1303 - 4095 4095 1469 - 4095 4095 1656 - 4095 4095 1865 - 4095 4095 2102 - 4095 4095 2375 - 4095 4095 2677 - 4095 4095 2991 - 4095 4095 3295 - 4095 4095 3588 - 4095 4095 3852 - 4095 4095 4057 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 0 - 4095 4095 36 - 4095 4095 119 - 4095 4095 242 - 4095 4095 387 - 4095 4095 543 - 4095 4095 704 - 4095 4095 858 - 4095 4095 1006 - 4095 4095 1152 - 4095 4095 1303 - 4095 4095 1469 - 4095 4095 1656 - 4095 4095 1865 - 4095 4095 2102 - 4095 4095 2375 - 4095 4095 2677 - 4095 4095 2991 - 4095 4095 3295 - 4095 4095 3588 - 4095 4095 3852 - 4095 4095 4057 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 0 - 4095 4095 36 - 4095 4095 119 - 4095 4095 242 - 4095 4095 387 - 4095 4095 543 - 4095 4095 704 - 4095 4095 858 - 4095 4095 1006 - 4095 4095 1152 - 4095 4095 1303 - 4095 4095 1469 - 4095 4095 1656 - 4095 4095 1865 - 4095 4095 2102 - 4095 4095 2375 - 4095 4095 2677 - 4095 4095 2991 - 4095 4095 3295 - 4095 4095 3588 - 4095 4095 3852 - 4095 4095 4057 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 0 - 4095 4095 36 - 4095 4095 119 - 4095 4095 242 - 4095 4095 387 - 4095 4095 543 - 4095 4095 704 - 4095 4095 858 - 4095 4095 1006 - 4095 4095 1152 - 4095 4095 1303 - 4095 4095 1469 - 4095 4095 1656 - 4095 4095 1865 - 4095 4095 2102 - 4095 4095 2375 - 4095 4095 2677 - 4095 4095 2991 - 4095 4095 3295 - 4095 4095 3588 - 4095 4095 3852 - 4095 4095 4057 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 0 - 4095 4095 36 - 4095 4095 119 - 4095 4095 242 - 4095 4095 387 - 4095 4095 543 - 4095 4095 704 - 4095 4095 858 - 4095 4095 1006 - 4095 4095 1152 - 4095 4095 1303 - 4095 4095 1469 - 4095 4095 1656 - 4095 4095 1865 - 4095 4095 2102 - 4095 4095 2375 - 4095 4095 2677 - 4095 4095 2991 - 4095 4095 3295 - 4095 4095 3588 - 4095 4095 3852 - 4095 4095 4057 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 0 - 4095 4095 36 - 4095 4095 119 - 4095 4095 242 - 4095 4095 387 - 4095 4095 543 - 4095 4095 704 - 4095 4095 858 - 4095 4095 1006 - 4095 4095 1152 - 4095 4095 1303 - 4095 4095 1469 - 4095 4095 1656 - 4095 4095 1865 - 4095 4095 2102 - 4095 4095 2375 - 4095 4095 2677 - 4095 4095 2991 - 4095 4095 3295 - 4095 4095 3588 - 4095 4095 3852 - 4095 4095 4057 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 0 - 4095 4095 36 - 4095 4095 119 - 4095 4095 242 - 4095 4095 387 - 4095 4095 543 - 4095 4095 704 - 4095 4095 858 - 4095 4095 1006 - 4095 4095 1152 - 4095 4095 1303 - 4095 4095 1469 - 4095 4095 1656 - 4095 4095 1865 - 4095 4095 2102 - 4095 4095 2375 - 4095 4095 2677 - 4095 4095 2991 - 4095 4095 3295 - 4095 4095 3588 - 4095 4095 3852 - 4095 4095 4057 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 0 - 4095 4095 36 - 4095 4095 119 - 4095 4095 242 - 4095 4095 387 - 4095 4095 543 - 4095 4095 704 - 4095 4095 858 - 4095 4095 1006 - 4095 4095 1152 - 4095 4095 1303 - 4095 4095 1469 - 4095 4095 1656 - 4095 4095 1865 - 4095 4095 2102 - 4095 4095 2375 - 4095 4095 2677 - 4095 4095 2991 - 4095 4095 3295 - 4095 4095 3588 - 4095 4095 3852 - 4095 4095 4057 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 0 - 4095 4095 36 - 4095 4095 119 - 4095 4095 242 - 4095 4095 387 - 4095 4095 543 - 4095 4095 704 - 4095 4095 858 - 4095 4095 1006 - 4095 4095 1152 - 4095 4095 1303 - 4095 4095 1469 - 4095 4095 1656 - 4095 4095 1865 - 4095 4095 2102 - 4095 4095 2375 - 4095 4095 2677 - 4095 4095 2991 - 4095 4095 3295 - 4095 4095 3588 - 4095 4095 3852 - 4095 4095 4057 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 0 0 - 4095 0 36 - 4095 0 119 - 4095 0 242 - 4095 0 387 - 4095 0 543 - 4095 0 704 - 4095 0 858 - 4095 0 1006 - 4095 0 1152 - 4095 0 1303 - 4095 0 1469 - 4095 0 1656 - 4095 0 1865 - 4095 0 2102 - 4095 0 2375 - 4095 0 2677 - 4095 0 2991 - 4095 0 3295 - 4095 0 3588 - 4095 0 3852 - 4095 0 4057 - 4095 0 4095 - 4095 0 4095 - 4095 0 4095 - 4095 0 4095 - 4095 0 4095 - 4095 0 4095 - 4095 0 4095 - 4095 0 4095 - 4095 0 4095 - 4095 0 4095 - 4095 0 4095 - 4095 36 0 - 4095 36 36 - 4095 36 119 - 4095 36 242 - 4095 36 387 - 4095 36 543 - 4095 36 704 - 4095 36 858 - 4095 36 1006 - 4095 36 1152 - 4095 36 1303 - 4095 36 1469 - 4095 36 1656 - 4095 36 1865 - 4095 36 2102 - 4095 36 2375 - 4095 36 2677 - 4095 36 2991 - 4095 36 3295 - 4095 36 3588 - 4095 36 3852 - 4095 36 4057 - 4095 36 4095 - 4095 36 4095 - 4095 36 4095 - 4095 36 4095 - 4095 36 4095 - 4095 36 4095 - 4095 36 4095 - 4095 36 4095 - 4095 36 4095 - 4095 36 4095 - 4095 36 4095 - 4095 119 0 - 4095 119 36 - 4095 119 119 - 4095 119 242 - 4095 119 387 - 4095 119 543 - 4095 119 704 - 4095 119 858 - 4095 119 1006 - 4095 119 1152 - 4095 119 1303 - 4095 119 1469 - 4095 119 1656 - 4095 119 1865 - 4095 119 2102 - 4095 119 2375 - 4095 119 2677 - 4095 119 2991 - 4095 119 3295 - 4095 119 3588 - 4095 119 3852 - 4095 119 4057 - 4095 119 4095 - 4095 119 4095 - 4095 119 4095 - 4095 119 4095 - 4095 119 4095 - 4095 119 4095 - 4095 119 4095 - 4095 119 4095 - 4095 119 4095 - 4095 119 4095 - 4095 119 4095 - 4095 242 0 - 4095 242 36 - 4095 242 119 - 4095 242 242 - 4095 242 387 - 4095 242 543 - 4095 242 704 - 4095 242 858 - 4095 242 1006 - 4095 242 1152 - 4095 242 1303 - 4095 242 1469 - 4095 242 1656 - 4095 242 1865 - 4095 242 2102 - 4095 242 2375 - 4095 242 2677 - 4095 242 2991 - 4095 242 3295 - 4095 242 3588 - 4095 242 3852 - 4095 242 4057 - 4095 242 4095 - 4095 242 4095 - 4095 242 4095 - 4095 242 4095 - 4095 242 4095 - 4095 242 4095 - 4095 242 4095 - 4095 242 4095 - 4095 242 4095 - 4095 242 4095 - 4095 242 4095 - 4095 387 0 - 4095 387 36 - 4095 387 119 - 4095 387 242 - 4095 387 387 - 4095 387 543 - 4095 387 704 - 4095 387 858 - 4095 387 1006 - 4095 387 1152 - 4095 387 1303 - 4095 387 1469 - 4095 387 1656 - 4095 387 1865 - 4095 387 2102 - 4095 387 2375 - 4095 387 2677 - 4095 387 2991 - 4095 387 3295 - 4095 387 3588 - 4095 387 3852 - 4095 387 4057 - 4095 387 4095 - 4095 387 4095 - 4095 387 4095 - 4095 387 4095 - 4095 387 4095 - 4095 387 4095 - 4095 387 4095 - 4095 387 4095 - 4095 387 4095 - 4095 387 4095 - 4095 387 4095 - 4095 543 0 - 4095 543 36 - 4095 543 119 - 4095 543 242 - 4095 543 387 - 4095 543 543 - 4095 543 704 - 4095 543 858 - 4095 543 1006 - 4095 543 1152 - 4095 543 1303 - 4095 543 1469 - 4095 543 1656 - 4095 543 1865 - 4095 543 2102 - 4095 543 2375 - 4095 543 2677 - 4095 543 2991 - 4095 543 3295 - 4095 543 3588 - 4095 543 3852 - 4095 543 4057 - 4095 543 4095 - 4095 543 4095 - 4095 543 4095 - 4095 543 4095 - 4095 543 4095 - 4095 543 4095 - 4095 543 4095 - 4095 543 4095 - 4095 543 4095 - 4095 543 4095 - 4095 543 4095 - 4095 704 0 - 4095 704 36 - 4095 704 119 - 4095 704 242 - 4095 704 387 - 4095 704 543 - 4095 704 704 - 4095 704 858 - 4095 704 1006 - 4095 704 1152 - 4095 704 1303 - 4095 704 1469 - 4095 704 1656 - 4095 704 1865 - 4095 704 2102 - 4095 704 2375 - 4095 704 2677 - 4095 704 2991 - 4095 704 3295 - 4095 704 3588 - 4095 704 3852 - 4095 704 4057 - 4095 704 4095 - 4095 704 4095 - 4095 704 4095 - 4095 704 4095 - 4095 704 4095 - 4095 704 4095 - 4095 704 4095 - 4095 704 4095 - 4095 704 4095 - 4095 704 4095 - 4095 704 4095 - 4095 858 0 - 4095 858 36 - 4095 858 119 - 4095 858 242 - 4095 858 387 - 4095 858 543 - 4095 858 704 - 4095 858 858 - 4095 858 1006 - 4095 858 1152 - 4095 858 1303 - 4095 858 1469 - 4095 858 1656 - 4095 858 1865 - 4095 858 2102 - 4095 858 2375 - 4095 858 2677 - 4095 858 2991 - 4095 858 3295 - 4095 858 3588 - 4095 858 3852 - 4095 858 4057 - 4095 858 4095 - 4095 858 4095 - 4095 858 4095 - 4095 858 4095 - 4095 858 4095 - 4095 858 4095 - 4095 858 4095 - 4095 858 4095 - 4095 858 4095 - 4095 858 4095 - 4095 858 4095 - 4095 1006 0 - 4095 1006 36 - 4095 1006 119 - 4095 1006 242 - 4095 1006 387 - 4095 1006 543 - 4095 1006 704 - 4095 1006 858 - 4095 1006 1006 - 4095 1006 1152 - 4095 1006 1303 - 4095 1006 1469 - 4095 1006 1656 - 4095 1006 1865 - 4095 1006 2102 - 4095 1006 2375 - 4095 1006 2677 - 4095 1006 2991 - 4095 1006 3295 - 4095 1006 3588 - 4095 1006 3852 - 4095 1006 4057 - 4095 1006 4095 - 4095 1006 4095 - 4095 1006 4095 - 4095 1006 4095 - 4095 1006 4095 - 4095 1006 4095 - 4095 1006 4095 - 4095 1006 4095 - 4095 1006 4095 - 4095 1006 4095 - 4095 1006 4095 - 4095 1152 0 - 4095 1152 36 - 4095 1152 119 - 4095 1152 242 - 4095 1152 387 - 4095 1152 543 - 4095 1152 704 - 4095 1152 858 - 4095 1152 1006 - 4095 1152 1152 - 4095 1152 1303 - 4095 1152 1469 - 4095 1152 1656 - 4095 1152 1865 - 4095 1152 2102 - 4095 1152 2375 - 4095 1152 2677 - 4095 1152 2991 - 4095 1152 3295 - 4095 1152 3588 - 4095 1152 3852 - 4095 1152 4057 - 4095 1152 4095 - 4095 1152 4095 - 4095 1152 4095 - 4095 1152 4095 - 4095 1152 4095 - 4095 1152 4095 - 4095 1152 4095 - 4095 1152 4095 - 4095 1152 4095 - 4095 1152 4095 - 4095 1152 4095 - 4095 1303 0 - 4095 1303 36 - 4095 1303 119 - 4095 1303 242 - 4095 1303 387 - 4095 1303 543 - 4095 1303 704 - 4095 1303 858 - 4095 1303 1006 - 4095 1303 1152 - 4095 1303 1303 - 4095 1303 1469 - 4095 1303 1656 - 4095 1303 1865 - 4095 1303 2102 - 4095 1303 2375 - 4095 1303 2677 - 4095 1303 2991 - 4095 1303 3295 - 4095 1303 3588 - 4095 1303 3852 - 4095 1303 4057 - 4095 1303 4095 - 4095 1303 4095 - 4095 1303 4095 - 4095 1303 4095 - 4095 1303 4095 - 4095 1303 4095 - 4095 1303 4095 - 4095 1303 4095 - 4095 1303 4095 - 4095 1303 4095 - 4095 1303 4095 - 4095 1469 0 - 4095 1469 36 - 4095 1469 119 - 4095 1469 242 - 4095 1469 387 - 4095 1469 543 - 4095 1469 704 - 4095 1469 858 - 4095 1469 1006 - 4095 1469 1152 - 4095 1469 1303 - 4095 1469 1469 - 4095 1469 1656 - 4095 1469 1865 - 4095 1469 2102 - 4095 1469 2375 - 4095 1469 2677 - 4095 1469 2991 - 4095 1469 3295 - 4095 1469 3588 - 4095 1469 3852 - 4095 1469 4057 - 4095 1469 4095 - 4095 1469 4095 - 4095 1469 4095 - 4095 1469 4095 - 4095 1469 4095 - 4095 1469 4095 - 4095 1469 4095 - 4095 1469 4095 - 4095 1469 4095 - 4095 1469 4095 - 4095 1469 4095 - 4095 1656 0 - 4095 1656 36 - 4095 1656 119 - 4095 1656 242 - 4095 1656 387 - 4095 1656 543 - 4095 1656 704 - 4095 1656 858 - 4095 1656 1006 - 4095 1656 1152 - 4095 1656 1303 - 4095 1656 1469 - 4095 1656 1656 - 4095 1656 1865 - 4095 1656 2102 - 4095 1656 2375 - 4095 1656 2677 - 4095 1656 2991 - 4095 1656 3295 - 4095 1656 3588 - 4095 1656 3852 - 4095 1656 4057 - 4095 1656 4095 - 4095 1656 4095 - 4095 1656 4095 - 4095 1656 4095 - 4095 1656 4095 - 4095 1656 4095 - 4095 1656 4095 - 4095 1656 4095 - 4095 1656 4095 - 4095 1656 4095 - 4095 1656 4095 - 4095 1865 0 - 4095 1865 36 - 4095 1865 119 - 4095 1865 242 - 4095 1865 387 - 4095 1865 543 - 4095 1865 704 - 4095 1865 858 - 4095 1865 1006 - 4095 1865 1152 - 4095 1865 1303 - 4095 1865 1469 - 4095 1865 1656 - 4095 1865 1865 - 4095 1865 2102 - 4095 1865 2375 - 4095 1865 2677 - 4095 1865 2991 - 4095 1865 3295 - 4095 1865 3588 - 4095 1865 3852 - 4095 1865 4057 - 4095 1865 4095 - 4095 1865 4095 - 4095 1865 4095 - 4095 1865 4095 - 4095 1865 4095 - 4095 1865 4095 - 4095 1865 4095 - 4095 1865 4095 - 4095 1865 4095 - 4095 1865 4095 - 4095 1865 4095 - 4095 2102 0 - 4095 2102 36 - 4095 2102 119 - 4095 2102 242 - 4095 2102 387 - 4095 2102 543 - 4095 2102 704 - 4095 2102 858 - 4095 2102 1006 - 4095 2102 1152 - 4095 2102 1303 - 4095 2102 1469 - 4095 2102 1656 - 4095 2102 1865 - 4095 2102 2102 - 4095 2102 2375 - 4095 2102 2677 - 4095 2102 2991 - 4095 2102 3295 - 4095 2102 3588 - 4095 2102 3852 - 4095 2102 4057 - 4095 2102 4095 - 4095 2102 4095 - 4095 2102 4095 - 4095 2102 4095 - 4095 2102 4095 - 4095 2102 4095 - 4095 2102 4095 - 4095 2102 4095 - 4095 2102 4095 - 4095 2102 4095 - 4095 2102 4095 - 4095 2375 0 - 4095 2375 36 - 4095 2375 119 - 4095 2375 242 - 4095 2375 387 - 4095 2375 543 - 4095 2375 704 - 4095 2375 858 - 4095 2375 1006 - 4095 2375 1152 - 4095 2375 1303 - 4095 2375 1469 - 4095 2375 1656 - 4095 2375 1865 - 4095 2375 2102 - 4095 2375 2375 - 4095 2375 2677 - 4095 2375 2991 - 4095 2375 3295 - 4095 2375 3588 - 4095 2375 3852 - 4095 2375 4057 - 4095 2375 4095 - 4095 2375 4095 - 4095 2375 4095 - 4095 2375 4095 - 4095 2375 4095 - 4095 2375 4095 - 4095 2375 4095 - 4095 2375 4095 - 4095 2375 4095 - 4095 2375 4095 - 4095 2375 4095 - 4095 2677 0 - 4095 2677 36 - 4095 2677 119 - 4095 2677 242 - 4095 2677 387 - 4095 2677 543 - 4095 2677 704 - 4095 2677 858 - 4095 2677 1006 - 4095 2677 1152 - 4095 2677 1303 - 4095 2677 1469 - 4095 2677 1656 - 4095 2677 1865 - 4095 2677 2102 - 4095 2677 2375 - 4095 2677 2677 - 4095 2677 2991 - 4095 2677 3295 - 4095 2677 3588 - 4095 2677 3852 - 4095 2677 4057 - 4095 2677 4095 - 4095 2677 4095 - 4095 2677 4095 - 4095 2677 4095 - 4095 2677 4095 - 4095 2677 4095 - 4095 2677 4095 - 4095 2677 4095 - 4095 2677 4095 - 4095 2677 4095 - 4095 2677 4095 - 4095 2991 0 - 4095 2991 36 - 4095 2991 119 - 4095 2991 242 - 4095 2991 387 - 4095 2991 543 - 4095 2991 704 - 4095 2991 858 - 4095 2991 1006 - 4095 2991 1152 - 4095 2991 1303 - 4095 2991 1469 - 4095 2991 1656 - 4095 2991 1865 - 4095 2991 2102 - 4095 2991 2375 - 4095 2991 2677 - 4095 2991 2991 - 4095 2991 3295 - 4095 2991 3588 - 4095 2991 3852 - 4095 2991 4057 - 4095 2991 4095 - 4095 2991 4095 - 4095 2991 4095 - 4095 2991 4095 - 4095 2991 4095 - 4095 2991 4095 - 4095 2991 4095 - 4095 2991 4095 - 4095 2991 4095 - 4095 2991 4095 - 4095 2991 4095 - 4095 3295 0 - 4095 3295 36 - 4095 3295 119 - 4095 3295 242 - 4095 3295 387 - 4095 3295 543 - 4095 3295 704 - 4095 3295 858 - 4095 3295 1006 - 4095 3295 1152 - 4095 3295 1303 - 4095 3295 1469 - 4095 3295 1656 - 4095 3295 1865 - 4095 3295 2102 - 4095 3295 2375 - 4095 3295 2677 - 4095 3295 2991 - 4095 3295 3295 - 4095 3295 3588 - 4095 3295 3852 - 4095 3295 4057 - 4095 3295 4095 - 4095 3295 4095 - 4095 3295 4095 - 4095 3295 4095 - 4095 3295 4095 - 4095 3295 4095 - 4095 3295 4095 - 4095 3295 4095 - 4095 3295 4095 - 4095 3295 4095 - 4095 3295 4095 - 4095 3588 0 - 4095 3588 36 - 4095 3588 119 - 4095 3588 242 - 4095 3588 387 - 4095 3588 543 - 4095 3588 704 - 4095 3588 858 - 4095 3588 1006 - 4095 3588 1152 - 4095 3588 1303 - 4095 3588 1469 - 4095 3588 1656 - 4095 3588 1865 - 4095 3588 2102 - 4095 3588 2375 - 4095 3588 2677 - 4095 3588 2991 - 4095 3588 3295 - 4095 3588 3588 - 4095 3588 3852 - 4095 3588 4057 - 4095 3588 4095 - 4095 3588 4095 - 4095 3588 4095 - 4095 3588 4095 - 4095 3588 4095 - 4095 3588 4095 - 4095 3588 4095 - 4095 3588 4095 - 4095 3588 4095 - 4095 3588 4095 - 4095 3588 4095 - 4095 3852 0 - 4095 3852 36 - 4095 3852 119 - 4095 3852 242 - 4095 3852 387 - 4095 3852 543 - 4095 3852 704 - 4095 3852 858 - 4095 3852 1006 - 4095 3852 1152 - 4095 3852 1303 - 4095 3852 1469 - 4095 3852 1656 - 4095 3852 1865 - 4095 3852 2102 - 4095 3852 2375 - 4095 3852 2677 - 4095 3852 2991 - 4095 3852 3295 - 4095 3852 3588 - 4095 3852 3852 - 4095 3852 4057 - 4095 3852 4095 - 4095 3852 4095 - 4095 3852 4095 - 4095 3852 4095 - 4095 3852 4095 - 4095 3852 4095 - 4095 3852 4095 - 4095 3852 4095 - 4095 3852 4095 - 4095 3852 4095 - 4095 3852 4095 - 4095 4057 0 - 4095 4057 36 - 4095 4057 119 - 4095 4057 242 - 4095 4057 387 - 4095 4057 543 - 4095 4057 704 - 4095 4057 858 - 4095 4057 1006 - 4095 4057 1152 - 4095 4057 1303 - 4095 4057 1469 - 4095 4057 1656 - 4095 4057 1865 - 4095 4057 2102 - 4095 4057 2375 - 4095 4057 2677 - 4095 4057 2991 - 4095 4057 3295 - 4095 4057 3588 - 4095 4057 3852 - 4095 4057 4057 - 4095 4057 4095 - 4095 4057 4095 - 4095 4057 4095 - 4095 4057 4095 - 4095 4057 4095 - 4095 4057 4095 - 4095 4057 4095 - 4095 4057 4095 - 4095 4057 4095 - 4095 4057 4095 - 4095 4057 4095 - 4095 4095 0 - 4095 4095 36 - 4095 4095 119 - 4095 4095 242 - 4095 4095 387 - 4095 4095 543 - 4095 4095 704 - 4095 4095 858 - 4095 4095 1006 - 4095 4095 1152 - 4095 4095 1303 - 4095 4095 1469 - 4095 4095 1656 - 4095 4095 1865 - 4095 4095 2102 - 4095 4095 2375 - 4095 4095 2677 - 4095 4095 2991 - 4095 4095 3295 - 4095 4095 3588 - 4095 4095 3852 - 4095 4095 4057 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 0 - 4095 4095 36 - 4095 4095 119 - 4095 4095 242 - 4095 4095 387 - 4095 4095 543 - 4095 4095 704 - 4095 4095 858 - 4095 4095 1006 - 4095 4095 1152 - 4095 4095 1303 - 4095 4095 1469 - 4095 4095 1656 - 4095 4095 1865 - 4095 4095 2102 - 4095 4095 2375 - 4095 4095 2677 - 4095 4095 2991 - 4095 4095 3295 - 4095 4095 3588 - 4095 4095 3852 - 4095 4095 4057 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 0 - 4095 4095 36 - 4095 4095 119 - 4095 4095 242 - 4095 4095 387 - 4095 4095 543 - 4095 4095 704 - 4095 4095 858 - 4095 4095 1006 - 4095 4095 1152 - 4095 4095 1303 - 4095 4095 1469 - 4095 4095 1656 - 4095 4095 1865 - 4095 4095 2102 - 4095 4095 2375 - 4095 4095 2677 - 4095 4095 2991 - 4095 4095 3295 - 4095 4095 3588 - 4095 4095 3852 - 4095 4095 4057 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 0 - 4095 4095 36 - 4095 4095 119 - 4095 4095 242 - 4095 4095 387 - 4095 4095 543 - 4095 4095 704 - 4095 4095 858 - 4095 4095 1006 - 4095 4095 1152 - 4095 4095 1303 - 4095 4095 1469 - 4095 4095 1656 - 4095 4095 1865 - 4095 4095 2102 - 4095 4095 2375 - 4095 4095 2677 - 4095 4095 2991 - 4095 4095 3295 - 4095 4095 3588 - 4095 4095 3852 - 4095 4095 4057 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 0 - 4095 4095 36 - 4095 4095 119 - 4095 4095 242 - 4095 4095 387 - 4095 4095 543 - 4095 4095 704 - 4095 4095 858 - 4095 4095 1006 - 4095 4095 1152 - 4095 4095 1303 - 4095 4095 1469 - 4095 4095 1656 - 4095 4095 1865 - 4095 4095 2102 - 4095 4095 2375 - 4095 4095 2677 - 4095 4095 2991 - 4095 4095 3295 - 4095 4095 3588 - 4095 4095 3852 - 4095 4095 4057 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 0 - 4095 4095 36 - 4095 4095 119 - 4095 4095 242 - 4095 4095 387 - 4095 4095 543 - 4095 4095 704 - 4095 4095 858 - 4095 4095 1006 - 4095 4095 1152 - 4095 4095 1303 - 4095 4095 1469 - 4095 4095 1656 - 4095 4095 1865 - 4095 4095 2102 - 4095 4095 2375 - 4095 4095 2677 - 4095 4095 2991 - 4095 4095 3295 - 4095 4095 3588 - 4095 4095 3852 - 4095 4095 4057 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 0 - 4095 4095 36 - 4095 4095 119 - 4095 4095 242 - 4095 4095 387 - 4095 4095 543 - 4095 4095 704 - 4095 4095 858 - 4095 4095 1006 - 4095 4095 1152 - 4095 4095 1303 - 4095 4095 1469 - 4095 4095 1656 - 4095 4095 1865 - 4095 4095 2102 - 4095 4095 2375 - 4095 4095 2677 - 4095 4095 2991 - 4095 4095 3295 - 4095 4095 3588 - 4095 4095 3852 - 4095 4095 4057 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 0 - 4095 4095 36 - 4095 4095 119 - 4095 4095 242 - 4095 4095 387 - 4095 4095 543 - 4095 4095 704 - 4095 4095 858 - 4095 4095 1006 - 4095 4095 1152 - 4095 4095 1303 - 4095 4095 1469 - 4095 4095 1656 - 4095 4095 1865 - 4095 4095 2102 - 4095 4095 2375 - 4095 4095 2677 - 4095 4095 2991 - 4095 4095 3295 - 4095 4095 3588 - 4095 4095 3852 - 4095 4095 4057 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 0 - 4095 4095 36 - 4095 4095 119 - 4095 4095 242 - 4095 4095 387 - 4095 4095 543 - 4095 4095 704 - 4095 4095 858 - 4095 4095 1006 - 4095 4095 1152 - 4095 4095 1303 - 4095 4095 1469 - 4095 4095 1656 - 4095 4095 1865 - 4095 4095 2102 - 4095 4095 2375 - 4095 4095 2677 - 4095 4095 2991 - 4095 4095 3295 - 4095 4095 3588 - 4095 4095 3852 - 4095 4095 4057 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 0 - 4095 4095 36 - 4095 4095 119 - 4095 4095 242 - 4095 4095 387 - 4095 4095 543 - 4095 4095 704 - 4095 4095 858 - 4095 4095 1006 - 4095 4095 1152 - 4095 4095 1303 - 4095 4095 1469 - 4095 4095 1656 - 4095 4095 1865 - 4095 4095 2102 - 4095 4095 2375 - 4095 4095 2677 - 4095 4095 2991 - 4095 4095 3295 - 4095 4095 3588 - 4095 4095 3852 - 4095 4095 4057 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 0 - 4095 4095 36 - 4095 4095 119 - 4095 4095 242 - 4095 4095 387 - 4095 4095 543 - 4095 4095 704 - 4095 4095 858 - 4095 4095 1006 - 4095 4095 1152 - 4095 4095 1303 - 4095 4095 1469 - 4095 4095 1656 - 4095 4095 1865 - 4095 4095 2102 - 4095 4095 2375 - 4095 4095 2677 - 4095 4095 2991 - 4095 4095 3295 - 4095 4095 3588 - 4095 4095 3852 - 4095 4095 4057 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 0 0 - 4095 0 36 - 4095 0 119 - 4095 0 242 - 4095 0 387 - 4095 0 543 - 4095 0 704 - 4095 0 858 - 4095 0 1006 - 4095 0 1152 - 4095 0 1303 - 4095 0 1469 - 4095 0 1656 - 4095 0 1865 - 4095 0 2102 - 4095 0 2375 - 4095 0 2677 - 4095 0 2991 - 4095 0 3295 - 4095 0 3588 - 4095 0 3852 - 4095 0 4057 - 4095 0 4095 - 4095 0 4095 - 4095 0 4095 - 4095 0 4095 - 4095 0 4095 - 4095 0 4095 - 4095 0 4095 - 4095 0 4095 - 4095 0 4095 - 4095 0 4095 - 4095 0 4095 - 4095 36 0 - 4095 36 36 - 4095 36 119 - 4095 36 242 - 4095 36 387 - 4095 36 543 - 4095 36 704 - 4095 36 858 - 4095 36 1006 - 4095 36 1152 - 4095 36 1303 - 4095 36 1469 - 4095 36 1656 - 4095 36 1865 - 4095 36 2102 - 4095 36 2375 - 4095 36 2677 - 4095 36 2991 - 4095 36 3295 - 4095 36 3588 - 4095 36 3852 - 4095 36 4057 - 4095 36 4095 - 4095 36 4095 - 4095 36 4095 - 4095 36 4095 - 4095 36 4095 - 4095 36 4095 - 4095 36 4095 - 4095 36 4095 - 4095 36 4095 - 4095 36 4095 - 4095 36 4095 - 4095 119 0 - 4095 119 36 - 4095 119 119 - 4095 119 242 - 4095 119 387 - 4095 119 543 - 4095 119 704 - 4095 119 858 - 4095 119 1006 - 4095 119 1152 - 4095 119 1303 - 4095 119 1469 - 4095 119 1656 - 4095 119 1865 - 4095 119 2102 - 4095 119 2375 - 4095 119 2677 - 4095 119 2991 - 4095 119 3295 - 4095 119 3588 - 4095 119 3852 - 4095 119 4057 - 4095 119 4095 - 4095 119 4095 - 4095 119 4095 - 4095 119 4095 - 4095 119 4095 - 4095 119 4095 - 4095 119 4095 - 4095 119 4095 - 4095 119 4095 - 4095 119 4095 - 4095 119 4095 - 4095 242 0 - 4095 242 36 - 4095 242 119 - 4095 242 242 - 4095 242 387 - 4095 242 543 - 4095 242 704 - 4095 242 858 - 4095 242 1006 - 4095 242 1152 - 4095 242 1303 - 4095 242 1469 - 4095 242 1656 - 4095 242 1865 - 4095 242 2102 - 4095 242 2375 - 4095 242 2677 - 4095 242 2991 - 4095 242 3295 - 4095 242 3588 - 4095 242 3852 - 4095 242 4057 - 4095 242 4095 - 4095 242 4095 - 4095 242 4095 - 4095 242 4095 - 4095 242 4095 - 4095 242 4095 - 4095 242 4095 - 4095 242 4095 - 4095 242 4095 - 4095 242 4095 - 4095 242 4095 - 4095 387 0 - 4095 387 36 - 4095 387 119 - 4095 387 242 - 4095 387 387 - 4095 387 543 - 4095 387 704 - 4095 387 858 - 4095 387 1006 - 4095 387 1152 - 4095 387 1303 - 4095 387 1469 - 4095 387 1656 - 4095 387 1865 - 4095 387 2102 - 4095 387 2375 - 4095 387 2677 - 4095 387 2991 - 4095 387 3295 - 4095 387 3588 - 4095 387 3852 - 4095 387 4057 - 4095 387 4095 - 4095 387 4095 - 4095 387 4095 - 4095 387 4095 - 4095 387 4095 - 4095 387 4095 - 4095 387 4095 - 4095 387 4095 - 4095 387 4095 - 4095 387 4095 - 4095 387 4095 - 4095 543 0 - 4095 543 36 - 4095 543 119 - 4095 543 242 - 4095 543 387 - 4095 543 543 - 4095 543 704 - 4095 543 858 - 4095 543 1006 - 4095 543 1152 - 4095 543 1303 - 4095 543 1469 - 4095 543 1656 - 4095 543 1865 - 4095 543 2102 - 4095 543 2375 - 4095 543 2677 - 4095 543 2991 - 4095 543 3295 - 4095 543 3588 - 4095 543 3852 - 4095 543 4057 - 4095 543 4095 - 4095 543 4095 - 4095 543 4095 - 4095 543 4095 - 4095 543 4095 - 4095 543 4095 - 4095 543 4095 - 4095 543 4095 - 4095 543 4095 - 4095 543 4095 - 4095 543 4095 - 4095 704 0 - 4095 704 36 - 4095 704 119 - 4095 704 242 - 4095 704 387 - 4095 704 543 - 4095 704 704 - 4095 704 858 - 4095 704 1006 - 4095 704 1152 - 4095 704 1303 - 4095 704 1469 - 4095 704 1656 - 4095 704 1865 - 4095 704 2102 - 4095 704 2375 - 4095 704 2677 - 4095 704 2991 - 4095 704 3295 - 4095 704 3588 - 4095 704 3852 - 4095 704 4057 - 4095 704 4095 - 4095 704 4095 - 4095 704 4095 - 4095 704 4095 - 4095 704 4095 - 4095 704 4095 - 4095 704 4095 - 4095 704 4095 - 4095 704 4095 - 4095 704 4095 - 4095 704 4095 - 4095 858 0 - 4095 858 36 - 4095 858 119 - 4095 858 242 - 4095 858 387 - 4095 858 543 - 4095 858 704 - 4095 858 858 - 4095 858 1006 - 4095 858 1152 - 4095 858 1303 - 4095 858 1469 - 4095 858 1656 - 4095 858 1865 - 4095 858 2102 - 4095 858 2375 - 4095 858 2677 - 4095 858 2991 - 4095 858 3295 - 4095 858 3588 - 4095 858 3852 - 4095 858 4057 - 4095 858 4095 - 4095 858 4095 - 4095 858 4095 - 4095 858 4095 - 4095 858 4095 - 4095 858 4095 - 4095 858 4095 - 4095 858 4095 - 4095 858 4095 - 4095 858 4095 - 4095 858 4095 - 4095 1006 0 - 4095 1006 36 - 4095 1006 119 - 4095 1006 242 - 4095 1006 387 - 4095 1006 543 - 4095 1006 704 - 4095 1006 858 - 4095 1006 1006 - 4095 1006 1152 - 4095 1006 1303 - 4095 1006 1469 - 4095 1006 1656 - 4095 1006 1865 - 4095 1006 2102 - 4095 1006 2375 - 4095 1006 2677 - 4095 1006 2991 - 4095 1006 3295 - 4095 1006 3588 - 4095 1006 3852 - 4095 1006 4057 - 4095 1006 4095 - 4095 1006 4095 - 4095 1006 4095 - 4095 1006 4095 - 4095 1006 4095 - 4095 1006 4095 - 4095 1006 4095 - 4095 1006 4095 - 4095 1006 4095 - 4095 1006 4095 - 4095 1006 4095 - 4095 1152 0 - 4095 1152 36 - 4095 1152 119 - 4095 1152 242 - 4095 1152 387 - 4095 1152 543 - 4095 1152 704 - 4095 1152 858 - 4095 1152 1006 - 4095 1152 1152 - 4095 1152 1303 - 4095 1152 1469 - 4095 1152 1656 - 4095 1152 1865 - 4095 1152 2102 - 4095 1152 2375 - 4095 1152 2677 - 4095 1152 2991 - 4095 1152 3295 - 4095 1152 3588 - 4095 1152 3852 - 4095 1152 4057 - 4095 1152 4095 - 4095 1152 4095 - 4095 1152 4095 - 4095 1152 4095 - 4095 1152 4095 - 4095 1152 4095 - 4095 1152 4095 - 4095 1152 4095 - 4095 1152 4095 - 4095 1152 4095 - 4095 1152 4095 - 4095 1303 0 - 4095 1303 36 - 4095 1303 119 - 4095 1303 242 - 4095 1303 387 - 4095 1303 543 - 4095 1303 704 - 4095 1303 858 - 4095 1303 1006 - 4095 1303 1152 - 4095 1303 1303 - 4095 1303 1469 - 4095 1303 1656 - 4095 1303 1865 - 4095 1303 2102 - 4095 1303 2375 - 4095 1303 2677 - 4095 1303 2991 - 4095 1303 3295 - 4095 1303 3588 - 4095 1303 3852 - 4095 1303 4057 - 4095 1303 4095 - 4095 1303 4095 - 4095 1303 4095 - 4095 1303 4095 - 4095 1303 4095 - 4095 1303 4095 - 4095 1303 4095 - 4095 1303 4095 - 4095 1303 4095 - 4095 1303 4095 - 4095 1303 4095 - 4095 1469 0 - 4095 1469 36 - 4095 1469 119 - 4095 1469 242 - 4095 1469 387 - 4095 1469 543 - 4095 1469 704 - 4095 1469 858 - 4095 1469 1006 - 4095 1469 1152 - 4095 1469 1303 - 4095 1469 1469 - 4095 1469 1656 - 4095 1469 1865 - 4095 1469 2102 - 4095 1469 2375 - 4095 1469 2677 - 4095 1469 2991 - 4095 1469 3295 - 4095 1469 3588 - 4095 1469 3852 - 4095 1469 4057 - 4095 1469 4095 - 4095 1469 4095 - 4095 1469 4095 - 4095 1469 4095 - 4095 1469 4095 - 4095 1469 4095 - 4095 1469 4095 - 4095 1469 4095 - 4095 1469 4095 - 4095 1469 4095 - 4095 1469 4095 - 4095 1656 0 - 4095 1656 36 - 4095 1656 119 - 4095 1656 242 - 4095 1656 387 - 4095 1656 543 - 4095 1656 704 - 4095 1656 858 - 4095 1656 1006 - 4095 1656 1152 - 4095 1656 1303 - 4095 1656 1469 - 4095 1656 1656 - 4095 1656 1865 - 4095 1656 2102 - 4095 1656 2375 - 4095 1656 2677 - 4095 1656 2991 - 4095 1656 3295 - 4095 1656 3588 - 4095 1656 3852 - 4095 1656 4057 - 4095 1656 4095 - 4095 1656 4095 - 4095 1656 4095 - 4095 1656 4095 - 4095 1656 4095 - 4095 1656 4095 - 4095 1656 4095 - 4095 1656 4095 - 4095 1656 4095 - 4095 1656 4095 - 4095 1656 4095 - 4095 1865 0 - 4095 1865 36 - 4095 1865 119 - 4095 1865 242 - 4095 1865 387 - 4095 1865 543 - 4095 1865 704 - 4095 1865 858 - 4095 1865 1006 - 4095 1865 1152 - 4095 1865 1303 - 4095 1865 1469 - 4095 1865 1656 - 4095 1865 1865 - 4095 1865 2102 - 4095 1865 2375 - 4095 1865 2677 - 4095 1865 2991 - 4095 1865 3295 - 4095 1865 3588 - 4095 1865 3852 - 4095 1865 4057 - 4095 1865 4095 - 4095 1865 4095 - 4095 1865 4095 - 4095 1865 4095 - 4095 1865 4095 - 4095 1865 4095 - 4095 1865 4095 - 4095 1865 4095 - 4095 1865 4095 - 4095 1865 4095 - 4095 1865 4095 - 4095 2102 0 - 4095 2102 36 - 4095 2102 119 - 4095 2102 242 - 4095 2102 387 - 4095 2102 543 - 4095 2102 704 - 4095 2102 858 - 4095 2102 1006 - 4095 2102 1152 - 4095 2102 1303 - 4095 2102 1469 - 4095 2102 1656 - 4095 2102 1865 - 4095 2102 2102 - 4095 2102 2375 - 4095 2102 2677 - 4095 2102 2991 - 4095 2102 3295 - 4095 2102 3588 - 4095 2102 3852 - 4095 2102 4057 - 4095 2102 4095 - 4095 2102 4095 - 4095 2102 4095 - 4095 2102 4095 - 4095 2102 4095 - 4095 2102 4095 - 4095 2102 4095 - 4095 2102 4095 - 4095 2102 4095 - 4095 2102 4095 - 4095 2102 4095 - 4095 2375 0 - 4095 2375 36 - 4095 2375 119 - 4095 2375 242 - 4095 2375 387 - 4095 2375 543 - 4095 2375 704 - 4095 2375 858 - 4095 2375 1006 - 4095 2375 1152 - 4095 2375 1303 - 4095 2375 1469 - 4095 2375 1656 - 4095 2375 1865 - 4095 2375 2102 - 4095 2375 2375 - 4095 2375 2677 - 4095 2375 2991 - 4095 2375 3295 - 4095 2375 3588 - 4095 2375 3852 - 4095 2375 4057 - 4095 2375 4095 - 4095 2375 4095 - 4095 2375 4095 - 4095 2375 4095 - 4095 2375 4095 - 4095 2375 4095 - 4095 2375 4095 - 4095 2375 4095 - 4095 2375 4095 - 4095 2375 4095 - 4095 2375 4095 - 4095 2677 0 - 4095 2677 36 - 4095 2677 119 - 4095 2677 242 - 4095 2677 387 - 4095 2677 543 - 4095 2677 704 - 4095 2677 858 - 4095 2677 1006 - 4095 2677 1152 - 4095 2677 1303 - 4095 2677 1469 - 4095 2677 1656 - 4095 2677 1865 - 4095 2677 2102 - 4095 2677 2375 - 4095 2677 2677 - 4095 2677 2991 - 4095 2677 3295 - 4095 2677 3588 - 4095 2677 3852 - 4095 2677 4057 - 4095 2677 4095 - 4095 2677 4095 - 4095 2677 4095 - 4095 2677 4095 - 4095 2677 4095 - 4095 2677 4095 - 4095 2677 4095 - 4095 2677 4095 - 4095 2677 4095 - 4095 2677 4095 - 4095 2677 4095 - 4095 2991 0 - 4095 2991 36 - 4095 2991 119 - 4095 2991 242 - 4095 2991 387 - 4095 2991 543 - 4095 2991 704 - 4095 2991 858 - 4095 2991 1006 - 4095 2991 1152 - 4095 2991 1303 - 4095 2991 1469 - 4095 2991 1656 - 4095 2991 1865 - 4095 2991 2102 - 4095 2991 2375 - 4095 2991 2677 - 4095 2991 2991 - 4095 2991 3295 - 4095 2991 3588 - 4095 2991 3852 - 4095 2991 4057 - 4095 2991 4095 - 4095 2991 4095 - 4095 2991 4095 - 4095 2991 4095 - 4095 2991 4095 - 4095 2991 4095 - 4095 2991 4095 - 4095 2991 4095 - 4095 2991 4095 - 4095 2991 4095 - 4095 2991 4095 - 4095 3295 0 - 4095 3295 36 - 4095 3295 119 - 4095 3295 242 - 4095 3295 387 - 4095 3295 543 - 4095 3295 704 - 4095 3295 858 - 4095 3295 1006 - 4095 3295 1152 - 4095 3295 1303 - 4095 3295 1469 - 4095 3295 1656 - 4095 3295 1865 - 4095 3295 2102 - 4095 3295 2375 - 4095 3295 2677 - 4095 3295 2991 - 4095 3295 3295 - 4095 3295 3588 - 4095 3295 3852 - 4095 3295 4057 - 4095 3295 4095 - 4095 3295 4095 - 4095 3295 4095 - 4095 3295 4095 - 4095 3295 4095 - 4095 3295 4095 - 4095 3295 4095 - 4095 3295 4095 - 4095 3295 4095 - 4095 3295 4095 - 4095 3295 4095 - 4095 3588 0 - 4095 3588 36 - 4095 3588 119 - 4095 3588 242 - 4095 3588 387 - 4095 3588 543 - 4095 3588 704 - 4095 3588 858 - 4095 3588 1006 - 4095 3588 1152 - 4095 3588 1303 - 4095 3588 1469 - 4095 3588 1656 - 4095 3588 1865 - 4095 3588 2102 - 4095 3588 2375 - 4095 3588 2677 - 4095 3588 2991 - 4095 3588 3295 - 4095 3588 3588 - 4095 3588 3852 - 4095 3588 4057 - 4095 3588 4095 - 4095 3588 4095 - 4095 3588 4095 - 4095 3588 4095 - 4095 3588 4095 - 4095 3588 4095 - 4095 3588 4095 - 4095 3588 4095 - 4095 3588 4095 - 4095 3588 4095 - 4095 3588 4095 - 4095 3852 0 - 4095 3852 36 - 4095 3852 119 - 4095 3852 242 - 4095 3852 387 - 4095 3852 543 - 4095 3852 704 - 4095 3852 858 - 4095 3852 1006 - 4095 3852 1152 - 4095 3852 1303 - 4095 3852 1469 - 4095 3852 1656 - 4095 3852 1865 - 4095 3852 2102 - 4095 3852 2375 - 4095 3852 2677 - 4095 3852 2991 - 4095 3852 3295 - 4095 3852 3588 - 4095 3852 3852 - 4095 3852 4057 - 4095 3852 4095 - 4095 3852 4095 - 4095 3852 4095 - 4095 3852 4095 - 4095 3852 4095 - 4095 3852 4095 - 4095 3852 4095 - 4095 3852 4095 - 4095 3852 4095 - 4095 3852 4095 - 4095 3852 4095 - 4095 4057 0 - 4095 4057 36 - 4095 4057 119 - 4095 4057 242 - 4095 4057 387 - 4095 4057 543 - 4095 4057 704 - 4095 4057 858 - 4095 4057 1006 - 4095 4057 1152 - 4095 4057 1303 - 4095 4057 1469 - 4095 4057 1656 - 4095 4057 1865 - 4095 4057 2102 - 4095 4057 2375 - 4095 4057 2677 - 4095 4057 2991 - 4095 4057 3295 - 4095 4057 3588 - 4095 4057 3852 - 4095 4057 4057 - 4095 4057 4095 - 4095 4057 4095 - 4095 4057 4095 - 4095 4057 4095 - 4095 4057 4095 - 4095 4057 4095 - 4095 4057 4095 - 4095 4057 4095 - 4095 4057 4095 - 4095 4057 4095 - 4095 4057 4095 - 4095 4095 0 - 4095 4095 36 - 4095 4095 119 - 4095 4095 242 - 4095 4095 387 - 4095 4095 543 - 4095 4095 704 - 4095 4095 858 - 4095 4095 1006 - 4095 4095 1152 - 4095 4095 1303 - 4095 4095 1469 - 4095 4095 1656 - 4095 4095 1865 - 4095 4095 2102 - 4095 4095 2375 - 4095 4095 2677 - 4095 4095 2991 - 4095 4095 3295 - 4095 4095 3588 - 4095 4095 3852 - 4095 4095 4057 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 0 - 4095 4095 36 - 4095 4095 119 - 4095 4095 242 - 4095 4095 387 - 4095 4095 543 - 4095 4095 704 - 4095 4095 858 - 4095 4095 1006 - 4095 4095 1152 - 4095 4095 1303 - 4095 4095 1469 - 4095 4095 1656 - 4095 4095 1865 - 4095 4095 2102 - 4095 4095 2375 - 4095 4095 2677 - 4095 4095 2991 - 4095 4095 3295 - 4095 4095 3588 - 4095 4095 3852 - 4095 4095 4057 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 0 - 4095 4095 36 - 4095 4095 119 - 4095 4095 242 - 4095 4095 387 - 4095 4095 543 - 4095 4095 704 - 4095 4095 858 - 4095 4095 1006 - 4095 4095 1152 - 4095 4095 1303 - 4095 4095 1469 - 4095 4095 1656 - 4095 4095 1865 - 4095 4095 2102 - 4095 4095 2375 - 4095 4095 2677 - 4095 4095 2991 - 4095 4095 3295 - 4095 4095 3588 - 4095 4095 3852 - 4095 4095 4057 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 0 - 4095 4095 36 - 4095 4095 119 - 4095 4095 242 - 4095 4095 387 - 4095 4095 543 - 4095 4095 704 - 4095 4095 858 - 4095 4095 1006 - 4095 4095 1152 - 4095 4095 1303 - 4095 4095 1469 - 4095 4095 1656 - 4095 4095 1865 - 4095 4095 2102 - 4095 4095 2375 - 4095 4095 2677 - 4095 4095 2991 - 4095 4095 3295 - 4095 4095 3588 - 4095 4095 3852 - 4095 4095 4057 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 0 - 4095 4095 36 - 4095 4095 119 - 4095 4095 242 - 4095 4095 387 - 4095 4095 543 - 4095 4095 704 - 4095 4095 858 - 4095 4095 1006 - 4095 4095 1152 - 4095 4095 1303 - 4095 4095 1469 - 4095 4095 1656 - 4095 4095 1865 - 4095 4095 2102 - 4095 4095 2375 - 4095 4095 2677 - 4095 4095 2991 - 4095 4095 3295 - 4095 4095 3588 - 4095 4095 3852 - 4095 4095 4057 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 0 - 4095 4095 36 - 4095 4095 119 - 4095 4095 242 - 4095 4095 387 - 4095 4095 543 - 4095 4095 704 - 4095 4095 858 - 4095 4095 1006 - 4095 4095 1152 - 4095 4095 1303 - 4095 4095 1469 - 4095 4095 1656 - 4095 4095 1865 - 4095 4095 2102 - 4095 4095 2375 - 4095 4095 2677 - 4095 4095 2991 - 4095 4095 3295 - 4095 4095 3588 - 4095 4095 3852 - 4095 4095 4057 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 0 - 4095 4095 36 - 4095 4095 119 - 4095 4095 242 - 4095 4095 387 - 4095 4095 543 - 4095 4095 704 - 4095 4095 858 - 4095 4095 1006 - 4095 4095 1152 - 4095 4095 1303 - 4095 4095 1469 - 4095 4095 1656 - 4095 4095 1865 - 4095 4095 2102 - 4095 4095 2375 - 4095 4095 2677 - 4095 4095 2991 - 4095 4095 3295 - 4095 4095 3588 - 4095 4095 3852 - 4095 4095 4057 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 0 - 4095 4095 36 - 4095 4095 119 - 4095 4095 242 - 4095 4095 387 - 4095 4095 543 - 4095 4095 704 - 4095 4095 858 - 4095 4095 1006 - 4095 4095 1152 - 4095 4095 1303 - 4095 4095 1469 - 4095 4095 1656 - 4095 4095 1865 - 4095 4095 2102 - 4095 4095 2375 - 4095 4095 2677 - 4095 4095 2991 - 4095 4095 3295 - 4095 4095 3588 - 4095 4095 3852 - 4095 4095 4057 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 0 - 4095 4095 36 - 4095 4095 119 - 4095 4095 242 - 4095 4095 387 - 4095 4095 543 - 4095 4095 704 - 4095 4095 858 - 4095 4095 1006 - 4095 4095 1152 - 4095 4095 1303 - 4095 4095 1469 - 4095 4095 1656 - 4095 4095 1865 - 4095 4095 2102 - 4095 4095 2375 - 4095 4095 2677 - 4095 4095 2991 - 4095 4095 3295 - 4095 4095 3588 - 4095 4095 3852 - 4095 4095 4057 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 0 - 4095 4095 36 - 4095 4095 119 - 4095 4095 242 - 4095 4095 387 - 4095 4095 543 - 4095 4095 704 - 4095 4095 858 - 4095 4095 1006 - 4095 4095 1152 - 4095 4095 1303 - 4095 4095 1469 - 4095 4095 1656 - 4095 4095 1865 - 4095 4095 2102 - 4095 4095 2375 - 4095 4095 2677 - 4095 4095 2991 - 4095 4095 3295 - 4095 4095 3588 - 4095 4095 3852 - 4095 4095 4057 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 0 - 4095 4095 36 - 4095 4095 119 - 4095 4095 242 - 4095 4095 387 - 4095 4095 543 - 4095 4095 704 - 4095 4095 858 - 4095 4095 1006 - 4095 4095 1152 - 4095 4095 1303 - 4095 4095 1469 - 4095 4095 1656 - 4095 4095 1865 - 4095 4095 2102 - 4095 4095 2375 - 4095 4095 2677 - 4095 4095 2991 - 4095 4095 3295 - 4095 4095 3588 - 4095 4095 3852 - 4095 4095 4057 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - 4095 4095 4095 - - - diff --git a/tests/data/files/transform_corrupted_tag.clf b/tests/data/files/transform_corrupted_tag.clf deleted file mode 100644 index 291c7deb28..0000000000 --- a/tests/data/files/transform_corrupted_tag.clf +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/tests/data/files/transform_element_end_missing.clf b/tests/data/files/transform_element_end_missing.clf deleted file mode 100644 index 40ae7bf594..0000000000 --- a/tests/data/files/transform_element_end_missing.clf +++ /dev/null @@ -1,2 +0,0 @@ - - diff --git a/tests/data/files/transform_id_empty.clf b/tests/data/files/transform_id_empty.clf deleted file mode 100644 index 4c5825b206..0000000000 --- a/tests/data/files/transform_id_empty.clf +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/tests/data/files/transform_missing_id.clf b/tests/data/files/transform_missing_id.clf deleted file mode 100644 index 41e7e12127..0000000000 --- a/tests/data/files/transform_missing_id.clf +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/tests/data/files/transform_missing_inbitdepth.clf b/tests/data/files/transform_missing_inbitdepth.clf deleted file mode 100644 index 97d820b0c3..0000000000 --- a/tests/data/files/transform_missing_inbitdepth.clf +++ /dev/null @@ -1,5 +0,0 @@ - - - - - diff --git a/tests/data/files/transform_missing_outbitdepth.clf b/tests/data/files/transform_missing_outbitdepth.clf deleted file mode 100644 index 0a24b35c14..0000000000 --- a/tests/data/files/transform_missing_outbitdepth.clf +++ /dev/null @@ -1,5 +0,0 @@ - - - - - From 5966a6a7ec181318ecfe4fde3fbc714ee6b53927 Mon Sep 17 00:00:00 2001 From: Patrick Hodoul Date: Tue, 19 May 2020 09:17:10 -0400 Subject: [PATCH 06/33] TSC meeting notes 2020-04-27 (#1012) * TSC meeting notes 2020-04-27 Signed-off-by: Patrick Hodoul * Add space to unlock the CI builds Signed-off-by: Patrick Hodoul Co-authored-by: doug-walker <43830961+doug-walker@users.noreply.github.com> --- docs/tsc/meetings/2020-04-27.md | 36 +++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) create mode 100644 docs/tsc/meetings/2020-04-27.md diff --git a/docs/tsc/meetings/2020-04-27.md b/docs/tsc/meetings/2020-04-27.md new file mode 100644 index 0000000000..49a174be38 --- /dev/null +++ b/docs/tsc/meetings/2020-04-27.md @@ -0,0 +1,36 @@ + + + +April 27, 2020 + +Host: Michael Dolan + +Rotating Secretary: Patrick Hodoul + +Attendees: + * [X] Mark Boorer (_TSC_) - Industrial Light & Magic + * [X] Sean Cooper (_TSC_) - DNEG + * [X] Michael Dolan (_TSC Chair_) - Epic Games + * [X] Larry Gritz - Sony Pictures Imageworks + * [X] Patrick Hodoul (_TSC_) - Autodesk + * [ ] John Mertic - Academy Software Foundation / Linux Foundation + * [ ] Carl Rand (_TSC_) - Weta Digital + * [X] Doug Walker (_TSC Chief Architect_) - Autodesk + * [X] Kevin Wheatley (_TSC_) - Framestore + * [X] Bernard Lefebvre - Autodesk + * [X] Carol Payne - Netflix + * [X] Mei Chu (_TSC_) - Sony Pictures Imageworks + +# **OCIO TSC Meeting Notes** + +* Build System: + - Michael: Works on the CI build using GitHub Actions. + Will submit a PR with the AWSF 2020 docker. + Rework the worflow to have one build for the library and one for the static anlysis, + latest builds, etc. + +* Various topics: + - Carol: Waiting feedback on the Wide Gamut proposal from the community including OCIO. + - Doug: PR is coming to organize all the CLF test files from OCIO to share with others. + - Doug: ACES webinar this week explaining the new realese of ACES 1.2. + From 96da57868c6e118e3fd9838e7d33cba91cfe7884 Mon Sep 17 00:00:00 2001 From: Patrick Hodoul Date: Tue, 19 May 2020 10:04:01 -0400 Subject: [PATCH 07/33] Adsk Contrib - Optimize the GPU texture size for 1D LUTs (#1013) Signed-off-by: Patrick Hodoul Co-authored-by: doug-walker <43830961+doug-walker@users.noreply.github.com> --- src/OpenColorIO/ops/lut1d/Lut1DOpGPU.cpp | 141 ++++++++++++++++++----- src/libutils/oglapphelpers/glsl.cpp | 27 +++-- tests/cpu/ops/lut1d/Lut1DOpGPU_tests.cpp | 96 +++++++++------ 3 files changed, 191 insertions(+), 73 deletions(-) diff --git a/src/OpenColorIO/ops/lut1d/Lut1DOpGPU.cpp b/src/OpenColorIO/ops/lut1d/Lut1DOpGPU.cpp index b940e2383b..849e2ba023 100644 --- a/src/OpenColorIO/ops/lut1d/Lut1DOpGPU.cpp +++ b/src/OpenColorIO/ops/lut1d/Lut1DOpGPU.cpp @@ -16,14 +16,15 @@ namespace OCIO_NAMESPACE namespace { -void PadLutChannels(unsigned long width, - unsigned long height, - const std::vector & channel, - std::vector & chn) +void CreatePaddedLutChannels(unsigned long width, + unsigned long height, + const std::vector & channel, + std::vector & paddedChannel) { + // The 1D LUT always contains 3 channels. const unsigned long currWidth = (unsigned long)(channel.size() / 3); - if (height>1) + if (height > 1) { // Fill the texture values. // @@ -38,12 +39,12 @@ void PadLutChannels(unsigned long width, { std::transform(&channel[3 * i], &channel[3 * (i + step)], - std::back_inserter(chn), + std::back_inserter(paddedChannel), [](float val) {return SanitizeFloat(val); }); - chn.push_back(SanitizeFloat(channel[3 * (i + step) + 0])); - chn.push_back(SanitizeFloat(channel[3 * (i + step) + 1])); - chn.push_back(SanitizeFloat(channel[3 * (i + step) + 2])); + paddedChannel.push_back(SanitizeFloat(channel[3 * (i + step) + 0])); + paddedChannel.push_back(SanitizeFloat(channel[3 * (i + step) + 1])); + paddedChannel.push_back(SanitizeFloat(channel[3 * (i + step) + 2])); leftover -= step; } @@ -52,50 +53,124 @@ void PadLutChannels(unsigned long width, { std::transform(&channel[3 * (currWidth - leftover)], &channel[3 * (currWidth - 1)], - std::back_inserter(chn), + std::back_inserter(paddedChannel), [](float val) {return SanitizeFloat(val); }); - chn.push_back(SanitizeFloat(channel[3 * (currWidth - 1) + 0])); - chn.push_back(SanitizeFloat(channel[3 * (currWidth - 1) + 1])); - chn.push_back(SanitizeFloat(channel[3 * (currWidth - 1) + 2])); + paddedChannel.push_back(SanitizeFloat(channel[3 * (currWidth - 1) + 0])); + paddedChannel.push_back(SanitizeFloat(channel[3 * (currWidth - 1) + 1])); + paddedChannel.push_back(SanitizeFloat(channel[3 * (currWidth - 1) + 2])); } } else { for (auto & val : channel) { - chn.push_back(SanitizeFloat(val)); + paddedChannel.push_back(SanitizeFloat(val)); } } // Pad the remaining of the texture with the last LUT entry. // Note: GPU Textures are expected a size of width*height. - unsigned long missingEntries = width*height - ((unsigned long)chn.size() / 3); + unsigned long missingEntries = width * height - ((unsigned long)paddedChannel.size() / 3); for (unsigned long idx = 0; idx < missingEntries; ++idx) { - chn.push_back(SanitizeFloat(channel[3 * (currWidth - 1) + 0])); - chn.push_back(SanitizeFloat(channel[3 * (currWidth - 1) + 1])); - chn.push_back(SanitizeFloat(channel[3 * (currWidth - 1) + 2])); + paddedChannel.push_back(SanitizeFloat(channel[3 * (currWidth - 1) + 0])); + paddedChannel.push_back(SanitizeFloat(channel[3 * (currWidth - 1) + 1])); + paddedChannel.push_back(SanitizeFloat(channel[3 * (currWidth - 1) + 2])); } } + +void CreatePaddedRedChannel(unsigned long width, + unsigned long height, + const std::vector & channel, // Contains RGB. + std::vector & paddedChannel) // Expects Red only. +{ + // The 1D LUT always contains 3 channels. + const unsigned long currWidth = (unsigned long)(channel.size() / 3); + + if (height > 1) + { + // Fill the texture values. + // + // Make the last texel of a given row the same as the first texel + // of its next row. This will preserve the continuity along row breaks + // as long as the lookup position used by the sampler is based on (width-1) + // to account for the 1 texel padding at the end of each row. + unsigned long leftover = currWidth; + + const unsigned long step = width - 1; + for (unsigned long i = 0; i < (currWidth - step); i += step) + { + for (unsigned long idx = i; idx < (i + step); ++idx) + { + paddedChannel.push_back(SanitizeFloat(channel[3 * idx])); + } + + paddedChannel.push_back(SanitizeFloat(channel[3 * (i + step)])); + leftover -= step; + } + + // If there are still texels to fill, add them to the texture data. + if (leftover > 0) + { + for (unsigned long idx = (currWidth - leftover); idx < (currWidth - 1); ++idx) + { + paddedChannel.push_back(SanitizeFloat(channel[3 * idx])); + } + + paddedChannel.push_back(SanitizeFloat(channel[3 * (currWidth - 1)])); + } + } + else + { + for (unsigned long idx = 0; idx < currWidth; ++idx) + { + paddedChannel.push_back(SanitizeFloat(channel[3 * idx])); + } + } + + // Pad the remaining of the texture with the last LUT entry. + // Note: GPU Textures are expected a size of width * height. + + unsigned long missingEntries = width * height - (unsigned long)paddedChannel.size(); + for (unsigned long idx = 0; idx < missingEntries; ++idx) + { + paddedChannel.push_back(SanitizeFloat(channel[3 * (currWidth - 1)])); + } } +} // anon. + void GetLut1DGPUShaderProgram(GpuShaderCreatorRcPtr & shaderCreator, ConstLut1DOpDataRcPtr & lutData) { const unsigned long defaultMaxWidth = shaderCreator->getTextureMaxWidth(); - const unsigned long length = lutData->getArray().getLength(); - const unsigned long width = std::min(length, defaultMaxWidth); - const unsigned long height = (length / defaultMaxWidth) + 1; + const unsigned long length = lutData->getArray().getLength(); + const unsigned long width = std::min(length, defaultMaxWidth); + const unsigned long height = (length / defaultMaxWidth) + 1; + const unsigned long numChannels = lutData->getArray().getNumColorComponents(); + + // Note: The 1D LUT needs a GPU texture for the Look-up table implementation. + // However, the texture type & content may vary based on the number of channels + // i.e. when all channels are identical a F32 Red GPU texture is enough. + + const bool singleChannel = (numChannels == 1); // Adjust LUT texture to allow for correct 2d linear interpolation, if needed. std::vector values; - values.reserve(width*height*3); + values.reserve(width * height * numChannels); - PadLutChannels(width, height, lutData->getArray().getValues(), values); + if (singleChannel) // i.e. numChannels == 1. + { + CreatePaddedRedChannel(width, height, lutData->getArray().getValues(), values); + } + else + { + CreatePaddedLutChannels(width, height, lutData->getArray().getValues(), values); + } // Register the RGB LUT. @@ -114,7 +189,8 @@ void GetLut1DGPUShaderProgram(GpuShaderCreatorRcPtr & shaderCreator, GpuShaderText::getSamplerName(name).c_str(), lutData->getCacheID().c_str(), width, height, - GpuShaderCreator::TEXTURE_RGB_CHANNEL, + singleChannel ? GpuShaderCreator::TEXTURE_RED_CHANNEL + : GpuShaderCreator::TEXTURE_RGB_CHANNEL, lutData->getConcreteInterpolation(), &values[0]); @@ -244,9 +320,14 @@ void GetLut1DGPUShaderProgram(GpuShaderCreatorRcPtr & shaderCreator, { const std::string str = name + "_computePos(" + shaderCreator->getPixelName(); - ss.newLine() << shaderCreator->getPixelName() << ".r = " << ss.sampleTex2D(name, str + ".r)") << ".r;"; - ss.newLine() << shaderCreator->getPixelName() << ".g = " << ss.sampleTex2D(name, str + ".g)") << ".g;"; - ss.newLine() << shaderCreator->getPixelName() << ".b = " << ss.sampleTex2D(name, str + ".b)") << ".b;"; + ss.newLine() << shaderCreator->getPixelName() << ".r = " + << ss.sampleTex2D(name, str + ".r)") << ".r;"; + + ss.newLine() << shaderCreator->getPixelName() << ".g = " + << ss.sampleTex2D(name, str + ".g)") << (singleChannel ? ".r;" : ".g;"); + + ss.newLine() << shaderCreator->getPixelName() << ".b = " + << ss.sampleTex2D(name, str + ".b)") << (singleChannel ? ".r;" : ".b;"); } else { @@ -260,10 +341,12 @@ void GetLut1DGPUShaderProgram(GpuShaderCreatorRcPtr & shaderCreator, ss.newLine() << shaderCreator->getPixelName() << ".r = " << ss.sampleTex1D(name, name + "_coords.r") << ".r;"; + ss.newLine() << shaderCreator->getPixelName() << ".g = " - << ss.sampleTex1D(name, name + "_coords.g") << ".g;"; + << ss.sampleTex1D(name, name + "_coords.g") << (singleChannel ? ".r;" : ".g;"); + ss.newLine() << shaderCreator->getPixelName() << ".b = " - << ss.sampleTex1D(name, name + "_coords.b") << ".b;"; + << ss.sampleTex1D(name, name + "_coords.b") << (singleChannel ? ".r;" : ".b;"); } if (lutData->getHueAdjust() == HUE_DW3) diff --git a/src/libutils/oglapphelpers/glsl.cpp b/src/libutils/oglapphelpers/glsl.cpp index bad3df722f..b10d4f2ceb 100644 --- a/src/libutils/oglapphelpers/glsl.cpp +++ b/src/libutils/oglapphelpers/glsl.cpp @@ -96,25 +96,36 @@ void AllocateTexture3D(unsigned index, unsigned & texId, edgelen, edgelen, edgelen, 0, GL_RGB, GL_FLOAT, values); } -void AllocateTexture2D(unsigned index, unsigned & texId, unsigned width, unsigned height, - Interpolation interpolation, const float * values) +void AllocateTexture2D(unsigned index, unsigned & texId, + unsigned width, unsigned height, + GpuShaderDesc::TextureType channel, + Interpolation interpolation, const float * values) { - if(values==0x0) + if (values == nullptr) { - throw Exception("Missing texture data"); + throw Exception("Missing texture data."); + } + + GLint internalformat = GL_RGB32F_ARB; + GLenum format = GL_RGB; + + if (channel == GpuShaderCreator::TEXTURE_RED_CHANNEL) + { + internalformat = GL_R32F; + format = GL_RED; } glGenTextures(1, &texId); glActiveTexture(GL_TEXTURE0 + index); - if(height>1) + if (height > 1) { glBindTexture(GL_TEXTURE_2D, texId); SetTextureParameters(GL_TEXTURE_2D, interpolation); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB32F_ARB, width, height, 0, GL_RGB, GL_FLOAT, values); + glTexImage2D(GL_TEXTURE_2D, 0, internalformat, width, height, 0, format, GL_FLOAT, values); } else { @@ -122,7 +133,7 @@ void AllocateTexture2D(unsigned index, unsigned & texId, unsigned width, unsigne SetTextureParameters(GL_TEXTURE_1D, interpolation); - glTexImage1D(GL_TEXTURE_1D, 0, GL_RGB32F_ARB, width, 0, GL_RGB, GL_FLOAT, values); + glTexImage1D(GL_TEXTURE_1D, 0, internalformat, width, 0, format, GL_FLOAT, values); } } @@ -337,7 +348,7 @@ void OpenGLBuilder::allocateAllTextures(unsigned startIndex) // 2. Allocate the 1D LUT (a 2D texture is needed to hold large LUTs). unsigned texId = 0; - AllocateTexture2D(currIndex, texId, width, height, interpolation, values); + AllocateTexture2D(currIndex, texId, width, height, channel, interpolation, values); // 3. Keep the texture id & name for the later enabling. diff --git a/tests/cpu/ops/lut1d/Lut1DOpGPU_tests.cpp b/tests/cpu/ops/lut1d/Lut1DOpGPU_tests.cpp index 52c8982838..ee96af40bc 100644 --- a/tests/cpu/ops/lut1d/Lut1DOpGPU_tests.cpp +++ b/tests/cpu/ops/lut1d/Lut1DOpGPU_tests.cpp @@ -14,7 +14,7 @@ namespace OCIO = OCIO_NAMESPACE; OCIO_ADD_TEST(Lut1DOp, pad_lut_one_dimension) { - const unsigned width = 6; + static constexpr unsigned width = 6; // Create a channel multi row and smaller than the expected texture size. @@ -25,23 +25,25 @@ OCIO_ADD_TEST(Lut1DOp, pad_lut_one_dimension) for (unsigned idx = 0; idx chn; - OCIO_CHECK_NO_THROW(OCIO::PadLutChannels(width, 1, channel, chn)); + OCIO_CHECK_NO_THROW(OCIO::CreatePaddedLutChannels(width, 1, channel, chn)); // Check the values. - const float res[18] = { 0.0f, 0.1f, 0.2f, 1.0f, 1.1f, 1.2f, - 2.0f, 2.1f, 2.2f, 3.0f, 3.1f, 3.2f, - 3.0f, 3.1f, 3.2f, 3.0f, 3.1f, 3.2f }; + static constexpr float res[18] = { + 0.0f, 0.1f, 0.2f, 1.0f, 1.1f, 1.2f, + 2.0f, 2.1f, 2.2f, 3.0f, 3.1f, 3.2f, + 3.0f, 3.1f, 3.2f, 3.0f, 3.1f, 3.2f }; + OCIO_CHECK_EQUAL(chn.size(), 18); - for (unsigned idx = 0; idx channel; channel.resize((height * width - 4) * 3); - for (unsigned idx = 0; idx chn; - OCIO_CHECK_NO_THROW(OCIO::PadLutChannels(width, height, channel, chn)); + OCIO_CHECK_NO_THROW(OCIO::CreatePaddedLutChannels(width, height, channel, chn)); - const float res[] = { + static constexpr float res[] = { 0.0f, 0.1f, 0.2f, 1.0f, 1.1f, 1.2f, 2.0f, 2.1f, 2.2f, 3.0f, 3.1f, 3.2f, 3.0f, 3.1f, 3.2f, 4.0f, 4.1f, 4.2f, 5.0f, 5.1f, 5.2f, 6.0f, 6.1f, 6.2f, 6.0f, 6.1f, 6.2f, 7.0f, 7.1f, 7.2f, 7.0f, 7.1f, 7.2f, 7.0f, 7.1f, 7.2f }; + OCIO_CHECK_EQUAL(chn.size(), 36); - for (unsigned idx = 0; idx channel; - channel.resize((height * width - 3) * 3); + // Internally, all LUTs have three channels (R, G & B). + static const std::vector lutValues { + 0.0f, 0.1f, 0.2f, 1.0f, 1.1f, 1.2f, 2.0f, 2.1f, 2.2f, + 3.0f, 3.1f, 3.2f, 4.0f, 4.1f, 4.2f, 5.0f, 5.1f, 5.2f, + 6.0f, 6.1f, 6.2f, 7.0f, 7.1f, 7.2f, 8.0f, 8.1f, 8.2f }; - for (unsigned idx = 0; idx chn; + OCIO_CHECK_NO_THROW(OCIO::CreatePaddedLutChannels(width, height, lutValues, chn)); + + // Here is the expected buffer for the 2D Texture padded to width & height for + // the three channels (R, G, B). + static constexpr float res[width * height * 3] = { + 0.0f, 0.1f, 0.2f, 1.0f, 1.1f, 1.2f, 2.0f, 2.1f, 2.2f, 3.0f, 3.1f, 3.2f, + 3.0f, 3.1f, 3.2f, 4.0f, 4.1f, 4.2f, 5.0f, 5.1f, 5.2f, 6.0f, 6.1f, 6.2f, + 6.0f, 6.1f, 6.2f, 7.0f, 7.1f, 7.2f, 8.0f, 8.1f, 8.2f, 8.0f, 8.1f, 8.2f }; + + OCIO_CHECK_EQUAL(chn.size(), (width * height * 3)); + + for (unsigned idx = 0; idx < chn.size(); ++idx) + { + OCIO_CHECK_EQUAL(chn[idx], res[idx]); + } } - // Special case where size%(width-1) = 0 - std::vector chn; - OCIO_CHECK_NO_THROW(OCIO::PadLutChannels(width, height, channel, chn)); + { + // Test as all channels were identical i.e. only the RED one is used & padded. - // Check the values + std::vector paddedChannel; + OCIO_CHECK_NO_THROW(OCIO::CreatePaddedRedChannel(width, height, lutValues, paddedChannel)); - const float res[] = { - 0.0f, 0.1f, 0.2f, 1.0f, 1.1f, 1.2f, 2.0f, 2.1f, 2.2f, 3.0f, 3.1f, 3.2f, - 3.0f, 3.1f, 3.2f, 4.0f, 4.1f, 4.2f, 5.0f, 5.1f, 5.2f, 6.0f, 6.1f, 6.2f, - 6.0f, 6.1f, 6.2f, 7.0f, 7.1f, 7.2f, 8.0f, 8.1f, 8.2f, 8.0f, 8.1f, 8.2f }; + // Here is the expected buffer for the 2D Texture padded to width & height for + // the Red channel only i.e. no G & B channels. + static constexpr float res[width * height * 1] = { + 0.0f, 1.0f, 2.0f, 3.0f, + 3.0f, 4.0f, 5.0f, 6.0f, + 6.0f, 7.0f, 8.0f, 8.0f }; - OCIO_CHECK_EQUAL(chn.size(), 36); + OCIO_REQUIRE_EQUAL(paddedChannel.size(), (width * height * 1)); - for (unsigned idx = 0; idx Date: Tue, 19 May 2020 10:38:01 -0400 Subject: [PATCH 08/33] 2020-05-11 tsc mtg notes (#1014) * 2020-05-11 tsc mtg notes Signed-off-by: Doug Walker * Adjust wording Signed-off-by: Doug Walker Co-authored-by: Michael Dolan Co-authored-by: Patrick Hodoul --- docs/tsc/meetings/2020-05-11.md | 70 +++++++++++++++++++++++++++++++++ 1 file changed, 70 insertions(+) create mode 100644 docs/tsc/meetings/2020-05-11.md diff --git a/docs/tsc/meetings/2020-05-11.md b/docs/tsc/meetings/2020-05-11.md new file mode 100644 index 0000000000..8529986884 --- /dev/null +++ b/docs/tsc/meetings/2020-05-11.md @@ -0,0 +1,70 @@ + + + +May 11, 2020 + +Host: Michael Dolan + +Rotating Secretary: Doug Walker + +Attendees: + * [x] Mark Boorer (_TSC_) - Industrial Light & Magic + * [x] Mei Chu (_TSC_) - Sony Pictures Imageworks + * [ ] Sean Cooper (_TSC ACES TAC Rep_) - DNEG + * [x] Michael Dolan (_TSC Chair_) - Epic Games + * [x] Patrick Hodoul (_TSC_) - Autodesk + * [ ] John Mertic - Academy Software Foundation / Linux Foundation + * [x] Carol Payne (_TSC_) - Netflix + * [ ] Carl Rand (_TSC_) - Weta Digital + * [x] Doug Walker (_TSC Chief Architect_) - Autodesk + * [x] Kevin Wheatley (_TSC_) - Framestore + * Joseph Goldstone - ARRI + * Bernard Lefebvre - Autodesk + +Apologies: + Sean Cooper + +# **OCIO TSC Meeting Notes** + +* Videos for OCIO + - Michael: Emily Olin (ASWF PR director) is hoping to help us develop some videos explaining + and demonstrating OCIO, and is looking for studios who can contribute recent images, videos, + breakdowns etc. that could be used within that. If any of you have some content you could + clear, let me know and I can put Emily in contact with you. + - Michael: I was able to get a few things cleared when I was at Sony, but it would be great to + get some new content in addition to that. + - Mark: I think anything from our YouTube videos should be available. + - Carol: We have been working with some international studios and may be able to get something. + - Michael: It's a nice opportunity for a studio to show public support for OCIO. + - Doug: We're thinking of maybe having two videos: one is an overview introducing what OCIO is, + and a second that is specifically about the new features in OCIO v2. + - Michael/Doug: It would be nice to have some images from a recognizable movie that are in + different color spaces to help with the explanations. + +* OCIO Configs Repo + - Michael: If anyone has any objections to me getting the ball rolling with getting an + OpenColorIO-Config-ACES repo set up under ASWF GH org, please let me know. We can rename it + later, but I would like to start some momentum on that effort. We can hold off on any other + config repos for now, but the ACES one seems pertinent to get going. + - Michael: We would like to have a v2 example config in place by SIGGRAPH and need to start now + to avoid a last minute rush. + - The TSC expressed support for that plan. + - There was some discussion about whether this would be useful for OCIO unit tests since the + existing tests build "toy configs" on the fly rather than real configs. However the group + felt it would be difficult to leverage this for several reasons including the fact that it + is in a separate repo and also changes to it might break tests. Also, we are trying to + minimize the number of external files the unit tests require. + - Micheal: On the topic of unit tests, it might be cool to use Github Actions CI to do some + testing where images are processed and compared to reference images. + +* Documentation + - Doug: We are just over two months from feature complete, we need to start updating the + documentation as soon as possible. It sounds like we have a lot of agreement about wanting + to refresh the landing page, restructure the documentation, etc. but if we don't get that + in place soon we may be stuck having to just update what is already there. + - Carol: Sean has been working on a solution for the docstrings and we have had some + discussion on other aspects. I will try to block out some time to work on a list of items + that will need to be addressed. + - Carol: There are a number of tasks involved in making the refreshed landing page: a nice + design, making it mobile friendly, doing the SEO work, etc. Could the Linux Foundation help? + - Michael: Yes, we should reach out to Emily about that. From 32914193f9970f63ccfba7efb3a60848e5df4e04 Mon Sep 17 00:00:00 2001 From: Patrick Hodoul Date: Mon, 25 May 2020 22:48:46 -0400 Subject: [PATCH 09/33] Adsk Contrib - Fix a CDL file load bug for ColorDecisionList case (#1022) Signed-off-by: Patrick Hodoul --- src/OpenColorIO/transforms/CDLTransform.cpp | 14 +++++++------- tests/cpu/transforms/CDLTransform_tests.cpp | 19 +++++++++++++++++++ 2 files changed, 26 insertions(+), 7 deletions(-) diff --git a/src/OpenColorIO/transforms/CDLTransform.cpp b/src/OpenColorIO/transforms/CDLTransform.cpp index 94e1cce167..d5c1e37fe6 100755 --- a/src/OpenColorIO/transforms/CDLTransform.cpp +++ b/src/OpenColorIO/transforms/CDLTransform.cpp @@ -202,7 +202,7 @@ void ClearCDLTransformFileCache() CDLTransformRcPtr CDLTransform::CreateFromFile(const char * src, const char * cccid_) { - if (!src || (strlen(src) == 0)) + if (!src || !*src) { std::ostringstream os; os << "Error loading CDL xml. "; @@ -217,7 +217,7 @@ CDLTransformRcPtr CDLTransform::CreateFromFile(const char * src, const char * cc AutoMutex lock(g_cacheMutex); // Use g_cacheSrcIsCC as a proxy for if we have loaded this source - // file already (in which case it must be in cache, or an error) + // file already (in which case it must be in cache, or an error). StringBoolMap::iterator srcIsCCiter = g_cacheSrcIsCC.find(src); if (srcIsCCiter != g_cacheSrcIsCC.end()) @@ -252,7 +252,7 @@ CDLTransformRcPtr CDLTransform::CreateFromFile(const char * src, const char * cc throw Exception (os.str().c_str()); } - // Try to read all ccs from the file, into cache + // Try to read all ccs from the file, into cache. std::ifstream istream(src); if (istream.fail()) { @@ -268,7 +268,7 @@ CDLTransformRcPtr CDLTransform::CreateFromFile(const char * src, const char * cc if (parser.isCC()) { - // Load a single ColorCorrection into the cache + // Load a single ColorCorrection into the cache. CDLTransformRcPtr cdl = CDLTransform::Create(); parser.getCDLTransform(cdl); @@ -276,10 +276,10 @@ CDLTransformRcPtr CDLTransform::CreateFromFile(const char * src, const char * cc g_cacheSrcIsCC[src] = true; g_cache[GetCDLLocalCacheKey(src, cccid)] = cdl; } - else if (parser.isCCC()) + else { - // Load all CCs from the ColorCorrectionCollection - // into the cache + // Load all CCs from the ColorCorrectionCollection or from the ColorDecisionList + // into the cache. CDLTransformMap transformMap; CDLTransformVec transformVec; FormatMetadataImpl metadata; diff --git a/tests/cpu/transforms/CDLTransform_tests.cpp b/tests/cpu/transforms/CDLTransform_tests.cpp index f75b3968e1..17305c699a 100644 --- a/tests/cpu/transforms/CDLTransform_tests.cpp +++ b/tests/cpu/transforms/CDLTransform_tests.cpp @@ -9,6 +9,7 @@ #include "transforms/CDLTransform.cpp" #include "testutils/UnitTest.h" +#include "UnitTestLogUtils.h" #include "UnitTestUtils.h" #include "Platform.h" @@ -165,6 +166,24 @@ OCIO_ADD_TEST(CDLTransform, create_from_ccc_file) } } +OCIO_ADD_TEST(CDLTransform, create_from_cdl_file) +{ + // As warning messages are expected, please mute them. + OCIO::MuteLogging mute; + + // Note: Detailed test is already done, this unit test only validates that + // this CDL file (i.e. containing a ColorDecisionList) correctly loads + // using a CDLTransform. + + const std::string filePath(std::string(OCIO::getTestFilesDir()) + "/cdl_test1.cdl"); + + OCIO::CDLTransformRcPtr transform; + + OCIO_CHECK_NO_THROW(transform = OCIO::CDLTransform::CreateFromFile(filePath.c_str(), "cc0003")); + OCIO_CHECK_EQUAL(std::string("cc0003"), std::string(transform->getID())); + OCIO_CHECK_EQUAL(transform->getStyle(), OCIO::CDL_NO_CLAMP); +} + OCIO_ADD_TEST(CDLTransform, create_from_ccc_file_failure) { const std::string filePath(std::string(OCIO::getTestFilesDir()) + "/cdl_test1.ccc"); From afad84e0a8e98b245daed692455bd3f9c4e02965 Mon Sep 17 00:00:00 2001 From: Michael Dolan Date: Mon, 1 Jun 2020 09:19:40 -0400 Subject: [PATCH 10/33] Add TSC notes for 05-18-2020 (#1019) * Add TSC notes for 05-18-2020 Signed-off-by: Michael Dolan * Fix indentation issue Signed-off-by: Michael Dolan * Fix typo Signed-off-by: Michael Dolan Co-authored-by: Patrick Hodoul --- docs/tsc/meetings/2020-05-18.md | 119 ++++++++++++++++++++++++++++++++ 1 file changed, 119 insertions(+) create mode 100644 docs/tsc/meetings/2020-05-18.md diff --git a/docs/tsc/meetings/2020-05-18.md b/docs/tsc/meetings/2020-05-18.md new file mode 100644 index 0000000000..72a8f8edb0 --- /dev/null +++ b/docs/tsc/meetings/2020-05-18.md @@ -0,0 +1,119 @@ + + + +May 18, 2020 + +Host: Michael Dolan + +Rotating Secretary: Michael Dolan + +Attendees: + * [ ] Mark Boorer (_TSC_) - Industrial Light & Magic + * [ ] Mei Chu (_TSC_) - Sony Pictures Imageworks + * [X] Sean Cooper (_TSC ACES TAC Rep_) - DNEG + * [X] Michael Dolan (_TSC Chair_) - Epic Games + * [ ] Patrick Hodoul (_TSC_) - Autodesk + * [ ] John Mertic - Academy Software Foundation / Linux Foundation + * [X] Carol Payne (_TSC_) - Netflix + * [ ] Carl Rand (_TSC_) - Weta Digital + * [X] Doug Walker (_TSC Chief Architect_) - Autodesk + * [X] Kevin Wheatley (_TSC_) - Framestore + * [X] Joseph Goldstone - ARRI + * [X] Troy Sobotka + +Apologies: + * Patrick Hodoul + * Mei Chu + +# **OCIO TSC Meeting Notes** + +* Documentation + - [Public working document, by Carol and Sean](https://docs.google.com/document/d/17IQR2tRYxqGXkExOLvP9S_dMkOkOID-NIIAGXGfyxNk/edit?usp=sharing) + - Carol: Document is a first draft. Went through existing documentation + to outline what's there, and thoughts around it. The rest of the doc has + examples and info on static site generators, themes, etc. Sean added a + proposed plan of attack for getting the work started. + - Doug: Good focus for the discussion. Thanks for putting it together! + - Carol: Putting it all down is good for establishing priorities. Some + items can happen concurrently, but some first steps are needed. + - Sean: First two points to decide on are the look and a static site + generator. + - Carol: If there was a time to change things, it is now. We could go a + different direction if needed. + - Michael: Many of us have expressed an openness to Sphinx alternatives if + something else makes more sense. + - Sean: Trying to find the best solution. Three options seem to be: Write + everything by hand, use an auto-generation tool, or be stuck in some + middle ground of building your own tooling. + - Carol: Looked at [Jekyll](https://jekyllrb.com/); has best integration + with GH pages, which would make it easy to use. I've never used + [Staticman](https://staticman.net/), but that looks like a good + integration which takes a static site and can add forms, tables, etc., + which trigger auto-rebuild or generation of issues, PRs, etc., which is + nice. Might be other tools, but these looked cool, to keep functionality + on website, but with GH handled changes. + - Sean: My initial thinking is that most of the world knows Sphinx, so it + could be picked up by anyone. The more obscure you get, the harder it is + for others to pick it up. Could have one build for static site, and + another for API docs. One option is to use a + [VuePress](https://vuepress.vuejs.org/) website, and then RTD could use + the VuePress theme to house API docs. + - Carol: I'm going to try and build some stuff locally to test. + - Michael: We could reach out on Slack and in ocio mail lists for community + input. + - Carol: I can reach out. The bulk of work will be rewriting the user guide. + - Sean: I added points to end of doc around documentation and its + organization. Asked the question, "who is the end consumer?", and called + out 4 groups: artists, studio config maintainers, studio TDs + (troubleshooting OCIO integrations), and OCIO integrators. Who is the + target, and who do we focus docs on? Maybe all? + - Carol: A lot of it can hopefully be to work with DCC vendors to help them + update their docs as well, and to understand coming changes. Then we can + point our docs to theirs. + - Michael: The [Compatible Software](https://github.com/AcademySoftwareFoundation/OpenColorIO/blob/master/docs/CompatibleSoftware.rst) + page of the OCIO website was updated recently and contains many + up-to-date documentation links. + - Doug: Also may want to add OCIO developers to the list of consumers, to + orient them to the code base. + - Joseph: that would be great. Also a 6th group: people submitting + transforms to a config. Camera manufacturers, etc. What are procedures + for contribution? How to provide test cases? + - Carol: Contributors is a block in there, and different contributor types. + - Sean: We should also work on documentation for configs we provide. That + was something provided previously for the SPI configs: user case studies, + etc. Those docs should live in config repos, and the main docs could + point to the config websites. + - Carol: Ideally they use the same process as the site + - Doug: Config docs would be simpler, with no API generation. + - Michael: At the next TSC meeting we can reconvene to discuss further, with + community input received this week. + - Sean made #docs channel in Slack, and will add all TSC members as Slack + admins. + - **TODO**: Carol will get documentation conversation started by posting + document in #docs channel as ocio-dev (possibly ocio-user too). + +* [OpenColorIO-Config-ACES](https://github.com/AcademySoftwareFoundation/OpenColorIO-Config-ACES) + - Michael: This repo has been created and the committer group is being + setup, which will include current active OCIO committers, plus Thomas + Mansencal and Michael Parsons. Sean, are you ok with the multiple repo + approach? I know you've expressed other approaches too. + - Sean: Multiple repos are ok. The use case that convinced me was ability + to version up and generate artifacts independently for the configs. + - General agreement that the ACES config is the best place to start, and + other configs can be explored/discussed later. + - Michael: I added one issue to the new repo to discuss formation of a + config working group, which can determine next steps, and decide on a + chair. + - **TODO**: Michael to make initial PR with LICENSE, etc. + +* PR #1011 + - Doug: CLF-specific PR up and ready for review, with changes from the CLF + ACES working group. Would like to get it merged by tomorrow for the next + working group meeting. + - Michael: I will review today. + - No voiced objections to merging it. + +* Items for next TSC meeting agenda: + - Next week is a holiday in US and UK. Group can still meet to discuss + documentation if there is interest, otherwise we can skip and keep + the conversation going in the new #docs Slack channel. From 309b246dc3e94166aa0b9a186edc432dbee4bc3f Mon Sep 17 00:00:00 2001 From: Patrick Hodoul Date: Mon, 1 Jun 2020 14:20:51 -0400 Subject: [PATCH 11/33] Adsk Contrib - Various CLF writer improvements (#1020) Signed-off-by: Patrick Hodoul --- .../fileformats/ctf/CTFTransform.cpp | 214 +++++++++++------- .../fileformats/xmlutils/XMLWriterUtils.cpp | 10 +- src/apps/ociomakeclf/main.cpp | 25 +- src/apps/ocioperf/main.cpp | 71 +----- src/apputils/measure.h | 90 ++++++++ tests/cpu/fileformats/FileFormatCTF_tests.cpp | 12 +- 6 files changed, 257 insertions(+), 165 deletions(-) create mode 100644 src/apputils/measure.h diff --git a/src/OpenColorIO/fileformats/ctf/CTFTransform.cpp b/src/OpenColorIO/fileformats/ctf/CTFTransform.cpp index c221776aea..8b78d3e02a 100644 --- a/src/OpenColorIO/fileformats/ctf/CTFTransform.cpp +++ b/src/OpenColorIO/fileformats/ctf/CTFTransform.cpp @@ -26,6 +26,12 @@ namespace OCIO_NAMESPACE { +// Note: 17 would allow exactly restoring most doubles but anything higher than 15, +// introduces some serialization issues such as: 81.9 -> 81.90000000000001. +// This results in less pretty output and also causes problems for some unit tests. +static constexpr unsigned DOUBLE_PRECISION = 15; + + void CTFVersion::ReadVersion(const std::string & versionString, CTFVersion & versionOut) { unsigned int numDot = 0; @@ -495,7 +501,7 @@ template <> void SetOStream(double, std::ostream & xml) { xml.width(19); - xml.precision(15); + xml.precision(DOUBLE_PRECISION); } template @@ -507,73 +513,101 @@ void WriteValues(XmlFormatter & formatter, unsigned iterStep, scaleType scale) { - std::ostream& xml = formatter.getStream(); + // Method used to write an array of values of the same type. - for (Iter it(valuesBegin); it != valuesEnd; it += iterStep) + std::ostream & xml = formatter.getStream(); + std::ostringstream oss; + + // The numbers in a CLF/CTF file may always contain fractional values, regardless of the + // bit-depth attributes. E.g., even if the bit-depth is 8i, the array could contain values + // such as [-0.1, 8, 100.234, 305]. However, we do use the bit-depth to initialize the most + // likely formatting to use when printing arrays with large numbers of values such as LUTs. + // And if the array really does only have integers, it is nicer to print those without + // decimal points. + + switch (bitDepth) { - switch (bitDepth) - { - case BIT_DEPTH_UINT8: - { - xml.width(3); - xml << (*it) * scale; - break; - } - case BIT_DEPTH_UINT10: - { - xml.width(4); - xml << (*it) * scale; - break; - } + case BIT_DEPTH_UINT8: + { + oss.width(3); + break; + } + case BIT_DEPTH_UINT10: + { + oss.width(4); + break; + } - case BIT_DEPTH_UINT12: - { - xml.width(4); - xml << (*it) * scale; - break; - } + case BIT_DEPTH_UINT12: + { + oss.width(4); + break; + } - case BIT_DEPTH_UINT16: - { - xml.width(5); - xml << (*it) * scale; - break; - } + case BIT_DEPTH_UINT16: + { + oss.width(5); + break; + } - case BIT_DEPTH_F16: - { - xml.width(11); - xml.precision(5); - WriteValue((*it) * scale, xml); - break; - } + case BIT_DEPTH_F16: + { + oss.width(11); + oss.precision(5); + break; + } + + case BIT_DEPTH_F32: + { + SetOStream(*valuesBegin, oss); + break; + } + + case BIT_DEPTH_UINT14: + case BIT_DEPTH_UINT32: + { + throw Exception("Unsupported bitdepth."); + break; + } + + case BIT_DEPTH_UNKNOWN: + { + throw Exception("Unknown bitdepth."); + break; + } + } + + const bool floatValues = (bitDepth == BIT_DEPTH_F16) || (bitDepth == BIT_DEPTH_F32); + + for (Iter it(valuesBegin); it != valuesEnd; it += iterStep) + { + oss.str(""); - case BIT_DEPTH_F32: + if (floatValues) { - SetOStream(*it, xml); - WriteValue((*it) * scale, xml); - break; + WriteValue((*it) * scale, oss); } - - case BIT_DEPTH_UINT14: - case BIT_DEPTH_UINT32: + else { - throw Exception("Unsupported bitdepth."); - break; + oss << (*it) * scale; } - case BIT_DEPTH_UNKNOWN: + const std::string value = oss.str(); + if (value.length() > (size_t)oss.width()) { - throw Exception("Unknown bitdepth."); - break; + // The imposed precision requires more characters so the code + // recomputes the width to better align the values for the next lines. + oss.width(value.length()); } - } + xml << value; - if (std::distance(valuesBegin, it) % valuesPerLine - == valuesPerLine - 1) + if (std::distance(valuesBegin, it) % valuesPerLine == valuesPerLine - 1) { - xml << std::endl; + // std::endln writes a newline and flushes the output buffer where '\n' only + // writes a newline. Flushing the buffer for all floats of large LUTs + // introduces a huge performance hit so only use '\n'. + xml << "\n"; } else { @@ -775,7 +809,14 @@ void CDLWriter::getAttributes(XmlFormatter::Attributes & attributes) const void CDLWriter::writeContent() const { XmlFormatter::Attributes attributes; + auto op = getOp(); + + std::ostringstream oss; + oss.precision(DOUBLE_PRECISION); + + CDLOpData::ChannelParams params; + // SOPNode. m_formatter.writeStartTag(TAG_SOPNODE, attributes); { @@ -786,9 +827,20 @@ void CDLWriter::writeContent() const METADATA_SOP_DESCRIPTION, desc); WriteDescriptions(m_formatter, TAG_DESCRIPTION, desc); - m_formatter.writeContentTag(TAG_SLOPE, m_cdl->getSlopeString()); - m_formatter.writeContentTag(TAG_OFFSET, m_cdl->getOffsetString()); - m_formatter.writeContentTag(TAG_POWER, m_cdl->getPowerString()); + oss.str(""); + params = m_cdl->getSlopeParams(); + oss << params[0] << ", " << params[1] << ", " << params[2]; + m_formatter.writeContentTag(TAG_SLOPE, oss.str()); + + oss.str(""); + params = m_cdl->getOffsetParams(); + oss << params[0] << ", " << params[1] << ", " << params[2]; + m_formatter.writeContentTag(TAG_OFFSET, oss.str()); + + oss.str(""); + params = m_cdl->getPowerParams(); + oss << params[0] << ", " << params[1] << ", " << params[2]; + m_formatter.writeContentTag(TAG_POWER, oss.str()); } m_formatter.writeEndTag(TAG_SOPNODE); @@ -802,7 +854,9 @@ void CDLWriter::writeContent() const METADATA_SAT_DESCRIPTION, desc); WriteDescriptions(m_formatter, TAG_DESCRIPTION, desc); - m_formatter.writeContentTag(TAG_SATURATION, m_cdl->getSaturationString()); + oss.str(""); + oss << m_cdl->getSaturation(); + m_formatter.writeContentTag(TAG_SATURATION, oss.str()); } m_formatter.writeEndTag(TAG_SATNODE); } @@ -877,41 +931,41 @@ void ExposureContrastWriter::getAttributes(XmlFormatter::Attributes& attributes) void ExposureContrastWriter::writeContent() const { + std::ostringstream oss; + oss.precision(DOUBLE_PRECISION); + XmlFormatter::Attributes attributes; { - std::stringstream expAttr; - WriteValue(m_ec->getExposure(), expAttr); - attributes.push_back(XmlFormatter::Attribute(ATTR_EXPOSURE, - expAttr.str())); + oss.str(""); + WriteValue(m_ec->getExposure(), oss); + attributes.push_back(XmlFormatter::Attribute(ATTR_EXPOSURE, oss.str())); } { - std::stringstream contAttr; - WriteValue(m_ec->getContrast(), contAttr); - attributes.push_back(XmlFormatter::Attribute(ATTR_CONTRAST, - contAttr.str())); + oss.str(""); + WriteValue(m_ec->getContrast(), oss); + attributes.push_back(XmlFormatter::Attribute(ATTR_CONTRAST, oss.str())); } { - std::stringstream gammaAttr; - WriteValue(m_ec->getGamma(), gammaAttr); - attributes.push_back(XmlFormatter::Attribute(ATTR_GAMMA, - gammaAttr.str())); + oss.str(""); + WriteValue(m_ec->getGamma(), oss); + attributes.push_back(XmlFormatter::Attribute(ATTR_GAMMA, oss.str())); } { - std::ostringstream oss; + oss.str(""); WriteValue(m_ec->getPivot(), oss); attributes.push_back(XmlFormatter::Attribute(ATTR_PIVOT, oss.str())); } if (m_ec->getLogExposureStep() != ExposureContrastOpData::LOGEXPOSURESTEP_DEFAULT) { - std::ostringstream oss; + oss.str(""); WriteValue(m_ec->getLogExposureStep(), oss); attributes.push_back(XmlFormatter::Attribute(ATTR_LOGEXPOSURESTEP, oss.str())); } if (m_ec->getLogMidGray() != ExposureContrastOpData::LOGMIDGRAY_DEFAULT) { - std::ostringstream oss; + oss.str(""); WriteValue(m_ec->getLogMidGray(), oss); attributes.push_back(XmlFormatter::Attribute(ATTR_LOGMIDGRAY, oss.str())); } @@ -995,6 +1049,7 @@ void FixedFunctionWriter::getAttributes(XmlFormatter::Attributes& attributes) co { size_t i = 0; std::stringstream ffParams; + ffParams.precision(DOUBLE_PRECISION); WriteValue(params[i], ffParams); while (++i < numParams) { @@ -1074,11 +1129,12 @@ void AddGammaParams(XmlFormatter::Attributes & attributes, const GammaOpData::Style style, bool useGamma) { - std::stringstream gammaAttr; - gammaAttr << params[0]; + std::stringstream oss; + oss.precision(DOUBLE_PRECISION); + oss << params[0]; attributes.push_back(XmlFormatter::Attribute(useGamma ? ATTR_GAMMA : ATTR_EXPONENT, - gammaAttr.str())); + oss.str())); switch (style) { @@ -1087,10 +1143,9 @@ void AddGammaParams(XmlFormatter::Attributes & attributes, case GammaOpData::MONCURVE_MIRROR_FWD: case GammaOpData::MONCURVE_MIRROR_REV: { - std::stringstream offsetAttr; - offsetAttr << params[1]; - attributes.push_back(XmlFormatter::Attribute(ATTR_OFFSET, - offsetAttr.str())); + oss.str(""); + oss << params[1]; + attributes.push_back(XmlFormatter::Attribute(ATTR_OFFSET, oss.str())); break; } case GammaOpData::BASIC_FWD: @@ -1244,6 +1299,7 @@ void AddLogParam(XmlFormatter::Attributes & attributes, double attrValue) { std::stringstream stream; + stream.precision(DOUBLE_PRECISION); stream << attrValue; attributes.push_back(XmlFormatter::Attribute(attrName, stream.str())); } @@ -1743,7 +1799,7 @@ const char * RangeWriter::getTagName() const void WriteTag(XmlFormatter & fmt, const char * tag, double value) { std::ostringstream o; - o.precision(15); + o.precision(DOUBLE_PRECISION); o << value; fmt.writeContentTag(tag, ' ' + o.str() + ' '); } diff --git a/src/OpenColorIO/fileformats/xmlutils/XMLWriterUtils.cpp b/src/OpenColorIO/fileformats/xmlutils/XMLWriterUtils.cpp index 2747521d00..30fa0a8266 100644 --- a/src/OpenColorIO/fileformats/xmlutils/XMLWriterUtils.cpp +++ b/src/OpenColorIO/fileformats/xmlutils/XMLWriterUtils.cpp @@ -43,7 +43,7 @@ void XmlFormatter::writeStartTag(const std::string & tagName, m_stream << "\""; } - m_stream << ">" << std::endl; + m_stream << ">\n"; } void XmlFormatter::writeStartTag(const std::string & tagName) @@ -55,7 +55,7 @@ void XmlFormatter::writeStartTag(const std::string & tagName) void XmlFormatter::writeEndTag(const std::string & tagName) { writeIndent(); - m_stream << "" << std::endl; + m_stream << "\n"; } void XmlFormatter::writeContentTag(const std::string & tagName, @@ -79,7 +79,7 @@ void XmlFormatter::writeContentTag(const std::string & tagName, } m_stream << ">"; writeString(content); - m_stream << "" << std::endl; + m_stream << "\n"; } // Write the content using escaped characters if needed. @@ -87,7 +87,7 @@ void XmlFormatter::writeContent(const std::string & content) { writeIndent(); writeString(content); - m_stream << std::endl; + m_stream << "\n"; } void XmlFormatter::writeEmptyTag(const std::string & tagName, @@ -105,7 +105,7 @@ void XmlFormatter::writeEmptyTag(const std::string & tagName, } // Note we close the tag, no end tag is needed. - m_stream << " />" << std::endl; + m_stream << " />\n"; } std::ostream & XmlFormatter::getStream() diff --git a/src/apps/ociomakeclf/main.cpp b/src/apps/ociomakeclf/main.cpp index 080806e823..d9458cab8f 100644 --- a/src/apps/ociomakeclf/main.cpp +++ b/src/apps/ociomakeclf/main.cpp @@ -11,6 +11,7 @@ namespace OCIO = OCIO_NAMESPACE; #include "apputils/argparse.h" +#include "apputils/measure.h" #include "utils/StringUtils.h" @@ -78,7 +79,7 @@ void CreateOutputLutFile(const std::string & outLutFilepath, OCIO::ConstGroupTra int main(int argc, const char ** argv) { - bool help = false, verbose = false, listCSCColorSpaces = false; + bool help = false, verbose = false, measure = false, listCSCColorSpaces = false; std::string cscColorSpace; ArgParse ap; @@ -92,6 +93,7 @@ int main(int argc, const char ** argv) "", "Options:", "--help", &help, "Print help message", "--verbose", &verbose, "Display general information", + "--measure", &measure, "Measure (in ms) the CLF write", "--list", &listCSCColorSpaces, "List of the supported CSC color spaces", "--csc %s", &cscColorSpace, "The color space that the input LUT expects and produces", nullptr); @@ -251,13 +253,26 @@ int main(int argc, const char ** argv) grp->appendTransform(outBuiltin); } - if (verbose) + static constexpr char Msg[] = "Creating the CLF lut file"; + + if (verbose && !measure) { - std::cout << "Creating the CLF lut file." << std::endl; + std::cout << Msg << "." << std::endl; } - // Create the CLF file. - CreateOutputLutFile(outLutFilepath, grp); + if (measure) + { + Measure m(Msg); + m.resume(); + + // Create the CLF file. + CreateOutputLutFile(outLutFilepath, grp); + } + else + { + // Create the CLF file. + CreateOutputLutFile(outLutFilepath, grp); + } } catch (OCIO::Exception & exception) { diff --git a/src/apps/ocioperf/main.cpp b/src/apps/ocioperf/main.cpp index c505774b4b..29644f5906 100644 --- a/src/apps/ocioperf/main.cpp +++ b/src/apps/ocioperf/main.cpp @@ -1,7 +1,6 @@ // SPDX-License-Identifier: BSD-3-Clause // Copyright Contributors to the OpenColorIO Project. -#include #include @@ -12,6 +11,7 @@ namespace OIIO = OIIO_NAMESPACE; #endif #include "apputils/argparse.h" +#include "apputils/measure.h" #include "OpenEXR/half.h" #include "oiiohelpers.h" #include "utils/StringUtils.h" @@ -21,75 +21,6 @@ namespace OCIO = OCIO_NAMESPACE; -// Utility to measure time in ms. -class Measure -{ -public: - Measure() = delete; - Measure(const Measure &) = delete; - - explicit Measure(const char * explanation, unsigned iterations) - : m_explanations(explanation) - , m_iterations(iterations) - , m_started(false) - , m_duration(0) - { - } - - ~Measure() - { - if(m_started) - { - pause(); - } - - std::cout << std::endl; - std::cout << m_explanations << std::endl; - std::cout << " CPU processing took: " - << (m_duration.count()/float(m_iterations)) - << " ms" << std::endl; - } - - void resume() - { - if(m_started) - { - throw OCIO::Exception("Measure already started."); - } - - m_started = true; - m_start = std::chrono::high_resolution_clock::now(); - } - - void pause() - { - std::chrono::high_resolution_clock::time_point end - = std::chrono::high_resolution_clock::now(); - - if(m_started) - { - std::chrono::duration duration = end - m_start; - - m_duration += duration; - } - else - { - throw OCIO::Exception("Measure already stopped."); - } - - m_started = false; - } - -private: - const std::string m_explanations; - const unsigned m_iterations; - - bool m_started; - std::chrono::high_resolution_clock::time_point m_start; - - std::chrono::duration m_duration; -}; - // Load in memory an image from disk. void LoadImage(const std::string & filepath, bool verbose, diff --git a/src/apputils/measure.h b/src/apputils/measure.h new file mode 100644 index 0000000000..2a35b58162 --- /dev/null +++ b/src/apputils/measure.h @@ -0,0 +1,90 @@ +// SPDX-License-Identifier: BSD-3-Clause +// Copyright Contributors to the OpenColorIO Project. + +#ifndef INCLUDED_OCIO_MEASURE_H +#define INCLUDED_OCIO_MEASURE_H + + +#include +#include +#include + + +// Utility to measure time in ms. +class Measure +{ +public: + Measure() = delete; + Measure(const Measure &) = delete; + + explicit Measure(const char * explanation) + : m_explanations(explanation) + { + } + + explicit Measure(const char * explanation, unsigned iterations) + : m_explanations(explanation) + , m_iterations(iterations) + { + } + + ~Measure() + { + if(m_started) + { + pause(); + } + print(); + } + + void resume() + { + if(m_started) + { + throw std::runtime_error("Measure already started."); + } + + m_started = true; + m_start = std::chrono::high_resolution_clock::now(); + } + + void pause() + { + std::chrono::high_resolution_clock::time_point end + = std::chrono::high_resolution_clock::now(); + + if(m_started) + { + const std::chrono::duration duration = end - m_start; + + m_duration += duration; + } + else + { + throw std::runtime_error("Measure already stopped."); + } + + m_started = false; + } + + void print() const noexcept + { + std::cout << "\n" + << m_explanations << "\n" + << " Processing took: " + << (m_duration.count() / float(m_iterations)) + << " ms" << std::endl; + } + +private: + const std::string m_explanations; + const unsigned m_iterations = 1; + + bool m_started = false; + std::chrono::high_resolution_clock::time_point m_start; + + std::chrono::duration m_duration { 0 }; +}; + + +#endif // INCLUDED_OCIO_MEASURE_H diff --git a/tests/cpu/fileformats/FileFormatCTF_tests.cpp b/tests/cpu/fileformats/FileFormatCTF_tests.cpp index 2547dd5c11..f737894e06 100644 --- a/tests/cpu/fileformats/FileFormatCTF_tests.cpp +++ b/tests/cpu/fileformats/FileFormatCTF_tests.cpp @@ -5405,10 +5405,10 @@ OCIO_ADD_TEST(CTFTransform, gamma5_ctf) const std::string expected{ R"( - - - - + + + + )" }; @@ -6067,7 +6067,7 @@ OCIO_ADD_TEST(CTFTransform, lut1d_10i_ctf) 0 0 0 511 4011.12 -24.103 -1023 1023 1023 + 1023 1023 1023 @@ -6395,7 +6395,7 @@ OCIO_ADD_TEST(CTFTransform, bitdepth_ctf) 0 511.5 -1023 + 1023 From e02611355fd8b9f7d8634b41bbd39c6eca566bb1 Mon Sep 17 00:00:00 2001 From: Michael Dolan Date: Mon, 1 Jun 2020 23:27:07 -0400 Subject: [PATCH 12/33] Add Mark Titchener as Foundry TSC member (#1021) * Add Mark Titchener to GOVERNANCE.md Signed-off-by: Michael Dolan * Add Mark Titchener to TSC meeting template Signed-off-by: Michael Dolan Co-authored-by: Patrick Hodoul --- GOVERNANCE.md | 1 + docs/tsc/meetings/template.md | 1 + 2 files changed, 2 insertions(+) diff --git a/GOVERNANCE.md b/GOVERNANCE.md index 1e088c0476..54746ac4f9 100644 --- a/GOVERNANCE.md +++ b/GOVERNANCE.md @@ -120,6 +120,7 @@ project at all ASWF TAC meetings. * Patrick Hodoul - Autodesk * Carol Payne - Netflix * Carl Rand - Weta Digital +* Mark Titchener - Foundry * Doug Walker - Autodesk * Kevin Wheatley - Framestore diff --git a/docs/tsc/meetings/template.md b/docs/tsc/meetings/template.md index a072e3c8fa..45fbf0fccf 100644 --- a/docs/tsc/meetings/template.md +++ b/docs/tsc/meetings/template.md @@ -15,6 +15,7 @@ Attendees: * [ ] Patrick Hodoul (_TSC_) - Autodesk * [ ] John Mertic - Academy Software Foundation / Linux Foundation * [ ] Carol Payne (_TSC_) - Netflix + * [ ] Mark Titchener (_TSC_) - Foundry * [ ] Carl Rand (_TSC_) - Weta Digital * [ ] Doug Walker (_TSC Chief Architect_) - Autodesk * [ ] Kevin Wheatley (_TSC_) - Framestore From 7d12e39cf5fc8bd5c2d79fb89417fbd43f128cc8 Mon Sep 17 00:00:00 2001 From: Mei Chu <33743518+meimchu@users.noreply.github.com> Date: Thu, 4 Jun 2020 12:08:18 -0700 Subject: [PATCH 13/33] Updated various python unit tests. (#1025) Signed-off-by: Mei Chu --- tests/CMakeLists.txt | 2 +- tests/python/{Baker.py => BakerTest.py} | 5 +- tests/python/CDLTransformTest.py | 428 ++++++++++++++++++++---- tests/python/ColorSpaceTest.py | 321 ++++++++++++++++-- tests/python/ConfigTest.py | 43 ++- tests/python/ConstantsTest.py | 121 ++++--- tests/python/ContextTest.py | 14 +- tests/python/MainTest.py | 16 +- tests/python/OpenColorIOTestSuite.py | 87 ++--- tests/python/TransformsTest.py | 58 ++-- tests/python/UnitTestUtils.py | 79 +++++ tests/python/__init__.py | 0 12 files changed, 906 insertions(+), 268 deletions(-) rename tests/python/{Baker.py => BakerTest.py} (99%) create mode 100644 tests/python/UnitTestUtils.py create mode 100644 tests/python/__init__.py diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 9db6a57b2b..b2076b3a90 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -21,5 +21,5 @@ if(OCIO_BUILD_JAVA) endif() #if(OCIO_BUILD_PYTHON) -# add_subdirectory(python) + add_subdirectory(python) #endif() diff --git a/tests/python/Baker.py b/tests/python/BakerTest.py similarity index 99% rename from tests/python/Baker.py rename to tests/python/BakerTest.py index e6346bfb8f..bee418e5b6 100644 --- a/tests/python/Baker.py +++ b/tests/python/BakerTest.py @@ -7,7 +7,7 @@ import PyOpenColorIO as OCIO class BakerTest(unittest.TestCase): - + def __init__(self, testName, sseBuild): super(BakerTest, self).__init__(testName) self.useSSE = sseBuild @@ -30,7 +30,7 @@ def __init__(self, testName, sseBuild): isdata: false allocation: uniform to_reference: ! {value: [2.2, 2.2, 2.2, 1]}""" - + EXPECTED_LUT_NONSSE = """CSPLUTV100 3D @@ -116,4 +116,3 @@ def test_interface(self): self.assertEqual(10, bakee.getNumFormats()) self.assertEqual("cinespace", bakee.getFormatNameByIndex(4)) self.assertEqual("3dl", bakee.getFormatExtensionByIndex(1)) - diff --git a/tests/python/CDLTransformTest.py b/tests/python/CDLTransformTest.py index 23918d626e..8729038912 100644 --- a/tests/python/CDLTransformTest.py +++ b/tests/python/CDLTransformTest.py @@ -1,109 +1,393 @@ # SPDX-License-Identifier: BSD-3-Clause # Copyright Contributors to the OpenColorIO Project. -import unittest, os, sys -sys.path.append(os.path.join(sys.argv[1], "src", "pyglue")) -import PyOpenColorIO as OCIO - -class CDLTransformTest(unittest.TestCase): +import unittest +import os +import sys - def test_interface(self): +import PyOpenColorIO as OCIO +from UnitTestUtils import TEST_DATAFILES_DIR, TEST_NAMES, TEST_DESCS - cdl = OCIO.CDLTransform() - id = cdl.getID(); - self.assertEqual(id, "") - cdl.setID("abcd") - self.assertEqual(cdl.getID(), "abcd") +DEFAULT_CDL = """ + + 1 1 1 + 0 0 0 + 1 1 1 + + + 1 + +""" - description = cdl.getDescription(); - self.assertEqual(description, "") - cdl.setDescription("abcdefg") - self.assertEqual(cdl.getDescription(), "abcdefg") - slope = cdl.getSlope() +class CDLTransformTest(unittest.TestCase): + # Default CDL values on initialization. + DEFAULT_CDL_SLOPE = [1.0, 1.0, 1.0] + DEFAULT_CDL_OFFSET = [0.0, 0.0, 0.0] + DEFAULT_CDL_POWER = [1.0, 1.0, 1.0] + DEFAULT_CDL_SAT = 1.0 + + # Values to test setter and getter. + TEST_CDL_ID = 'shot 042' + TEST_CDL_DESC = 'Cool look for forest scenes.' + TEST_CDL_SLOPE = [1.5, 2, 2.5] + TEST_CDL_OFFSET = [3, 3.5, 4] + TEST_CDL_POWER = [4.5, 5, 5.5] + TEST_CDL_SAT = 6 + TEST_CDL = """ + + {1} + {2} + {3} + {4} + + + {5} + +""".format(TEST_CDL_ID, + TEST_CDL_DESC, + ' '.join(map(str, TEST_CDL_SLOPE)), + ' '.join(map(str, TEST_CDL_OFFSET)), + ' '.join(map(str, TEST_CDL_POWER)), + str(TEST_CDL_SAT)) + + def setUp(self): + self.cdl_tr = OCIO.CDLTransform() + + def tearDown(self): + self.cdl_tr = None + + def test_id(self): + """ + Test the setID() and getID() methods. + """ + + # Default initialized id value is "" + self.assertEqual(self.cdl_tr.getID(), '') + + # Test id name setter and getter. + for id_ in TEST_NAMES: + self.cdl_tr.setID(id_) + self.assertEqual(id_, self.cdl_tr.getID()) + + def test_description(self): + """ + Test the setDescription() and getDescription() methods. + """ + + # Default initialized description value is "" + self.assertEqual(self.cdl_tr.getDescription(), '') + + # Test description setter and getter. + for desc in TEST_DESCS: + self.cdl_tr.setDescription(desc) + self.assertEqual(desc, self.cdl_tr.getDescription()) + + def test_slope(self): + """ + Test the setSlope() and getSlope() methods. + """ + + # Default initialized slope values are [1.0, 1.0, 1.0] + slope = self.cdl_tr.getSlope() self.assertEqual(len(slope), 3) - self.assertEqual(slope[0], 1.0) - self.assertEqual(slope[1], 1.0) - self.assertEqual(slope[2], 1.0) - - slope[1] = 2.0 - cdl.setSlope(slope) + self.assertListEqual(self.DEFAULT_CDL_SLOPE, slope) - slope = cdl.getSlope() + # Test by setting slope values to TEST_CDL_SLOPE. + self.cdl_tr.setSlope(self.TEST_CDL_SLOPE) + slope = self.cdl_tr.getSlope() self.assertEqual(len(slope), 3) - self.assertEqual(slope[0], 1.0) - self.assertEqual(slope[1], 2.0) - self.assertEqual(slope[2], 1.0) + self.assertListEqual(self.TEST_CDL_SLOPE, slope) - offset = cdl.getOffset() - self.assertEqual(len(offset), 3) - self.assertEqual(offset[0], 0.0) - self.assertEqual(offset[1], 0.0) - self.assertEqual(offset[2], 0.0) - - offset[1] = 2.0 - cdl.setOffset(offset) + def test_offset(self): + """ + Test the setOffset() and getOffset() methods. + """ - offset = cdl.getOffset() + # Default initialized offset values are [0.0, 0.0, 0.0] + offset = self.cdl_tr.getOffset() self.assertEqual(len(offset), 3) - self.assertEqual(offset[0], 0.0) - self.assertEqual(offset[1], 2.0) - self.assertEqual(offset[2], 0.0) + self.assertListEqual(self.DEFAULT_CDL_OFFSET, offset) - power = cdl.getPower() - self.assertEqual(len(power), 3) - self.assertEqual(power[0], 1.0) - self.assertEqual(power[1], 1.0) - self.assertEqual(power[2], 1.0) + # Test by setting offset values to TEST_CDL_OFFSET. + self.cdl_tr.setOffset(self.TEST_CDL_OFFSET) + offset = self.cdl_tr.getOffset() + self.assertEqual(len(offset), 3) + self.assertListEqual(self.TEST_CDL_OFFSET, offset) - power[1] = 2.0 - cdl.setPower(power) + def test_power(self): + """ + Test the setPower() and getPower() methods. + """ - power = cdl.getPower() + # Default initialized power values are [0.0, 0.0, 0.0] + power = self.cdl_tr.getPower() self.assertEqual(len(power), 3) - self.assertEqual(power[0], 1.0) - self.assertEqual(power[1], 2.0) - self.assertEqual(power[2], 1.0) - - saturation = cdl.getSat() - self.assertEqual(saturation, 1.0) - cdl.setSat(2.0) - self.assertEqual(cdl.getSat(), 2.0) - + self.assertListEqual(self.DEFAULT_CDL_POWER, power) + # Test by setting power values to TEST_CDL_POWER. + self.cdl_tr.setPower(self.TEST_CDL_POWER) + power = self.cdl_tr.getPower() + self.assertEqual(len(power), 3) + self.assertListEqual(self.TEST_CDL_POWER, power) + + def test_saturation(self): + """ + Test the setSat() and getSat() methods. + """ + + # Default initialized saturation value is 1.0 + saturation = self.cdl_tr.getSat() + self.assertEqual(self.DEFAULT_CDL_SAT, saturation) + + # Test by setting saturation value to TEST_CDL_SAT. + self.cdl_tr.setSat(self.TEST_CDL_SAT) + self.assertEqual(self.cdl_tr.getSat(), self.TEST_CDL_SAT) + + def test_direction(self): + """ + Test the setDirection() and getDirection() methods. + """ + + # Default initialized direction is forward. + self.assertEqual(self.cdl_tr.getDirection(), OCIO.TRANSFORM_DIR_FORWARD) + + for direction in OCIO.TransformDirection.__members__.values(): + # Setting the unknown direction preserves the current direction. + if direction != OCIO.TRANSFORM_DIR_UNKNOWN: + self.cdl_tr.setDirection(direction) + self.assertEqual(self.cdl_tr.getDirection(), direction) + + def test_style(self): + """ + Test the setStyle() and getStyle() methods. + """ + + # Default initialized direction is forward. + self.assertEqual(self.cdl_tr.getStyle(), OCIO.CDL_NO_CLAMP) + + for style in OCIO.CDLStyle.__members__.values(): + self.cdl_tr.setStyle(style) + self.assertEqual(self.cdl_tr.getStyle(), style) + + def test_xml(self): + """ + Test the setXML() and getXML() methods. + """ + + self.cdl_tr.setXML(self.TEST_CDL) + self.assertEqual(self.cdl_tr.getID(), self.TEST_CDL_ID) + self.assertEqual(self.cdl_tr.getDescription(), self.TEST_CDL_DESC) + self.assertListEqual(self.cdl_tr.getSlope(), self.TEST_CDL_SLOPE) + self.assertListEqual(self.cdl_tr.getOffset(), self.TEST_CDL_OFFSET) + self.assertListEqual(self.cdl_tr.getPower(), self.TEST_CDL_POWER) + self.assertEqual(self.cdl_tr.getSat(), self.TEST_CDL_SAT) + + # Test the XML produced by this CDLTransform object. + self.assertEqual(self.cdl_tr.getXML(), self.TEST_CDL) + + def test_createfromfile_cc(self): + """ + Test CreateFromFile() method with a cc file. + """ + + # Try env var first to get test file path. + test_file = '%s/cdl_test1.cc' % TEST_DATAFILES_DIR + + # Test cc file. + cdl = OCIO.CDLTransform.CreateFromFile(test_file, 'foo') + self.assertEqual(cdl.getID(), 'foo') + self.assertEqual(cdl.getDescription(), 'this is a description') + self.assertListEqual(cdl.getSlope(), [1.1, 1.2, 1.3]) + self.assertListEqual(cdl.getOffset(), [2.1, 2.2, 2.3]) + self.assertListEqual(cdl.getPower(), [3.1, 3.2, 3.3]) + self.assertEqual(cdl.getSat(), 0.7) + + def test_createfromfile_ccc(self): + """ + Test CreateFromFile() method with a ccc file. + """ + + # Try env var first to get test file path. + test_file = '%s/cdl_test1.ccc' % TEST_DATAFILES_DIR + + # Test 4th member of the ccc file. + cdl1 = OCIO.CDLTransform.CreateFromFile(test_file, '3') + self.assertEqual(cdl1.getID(), '') + self.assertListEqual(cdl1.getSlope(), [4.0, 5.0, 6.0]) + self.assertListEqual(cdl1.getOffset(), [0.0, 0.0, 0.0]) + self.assertListEqual(cdl1.getPower(), [0.9, 1.0, 1.2]) + self.assertEqual(cdl1.getSat(), 1.0) + + # Test a specified id member of the ccc file. + cdl2 = OCIO.CDLTransform.CreateFromFile(test_file, 'cc0003') + self.assertEqual(cdl2.getID(), 'cc0003') + self.assertEqual(cdl2.getDescription(), 'golden') + self.assertListEqual(cdl2.getSlope(), [1.2, 1.1, 1.0]) + self.assertListEqual(cdl2.getOffset(), [0.0, 0.0, 0.0]) + self.assertListEqual(cdl2.getPower(), [0.9, 1.0, 1.2]) + self.assertEqual(cdl2.getSat(), 1.0) + + def test_createfromfile_cdl(self): + """ + Test CreateFromFile() method with a cdl file. + """ + + # Try env var first to get test file path. + test_file = '%s/cdl_test1.cdl' % TEST_DATAFILES_DIR + + # Test a specified id member of the cdl file. + cdl = OCIO.CDLTransform.CreateFromFile(test_file, 'cc0003') + self.assertEqual(cdl.getID(), 'cc0003') + self.assertEqual(cdl.getDescription(), 'golden') + self.assertListEqual(cdl.getSlope(), [1.2, 1.1, 1.0]) + self.assertListEqual(cdl.getOffset(), [0.0, 0.0, 0.0]) + self.assertListEqual(cdl.getPower(), [0.9, 1.0, 1.2]) + self.assertEqual(cdl.getSat(), 1.0) + + + def test_validate_slope(self): + """ + Test the validate() method for slope values. Values must be above 0. + """ + + self.cdl_tr.setSlope(self.TEST_CDL_SLOPE) + self.assertIsNone(self.cdl_tr.validate()) + + # Exception validation test. + self.cdl_tr.setSlope([-1, -2, -3]) + with self.assertRaises(OCIO.Exception): + self.cdl_tr.validate() + + def test_validate_saturation(self): + """ + Test the validate() method for saturation value. Value must be above 0. + """ + + self.cdl_tr.setSat(self.TEST_CDL_SAT) + self.assertIsNone(self.cdl_tr.validate()) + + # Exception validation test + self.cdl_tr.setSat(-0.1) + with self.assertRaises(OCIO.Exception): + self.cdl_tr.validate() + + def test_validate_power(self): + """ + Test the validate() method for power values. Values must be above 0. + """ + + self.cdl_tr.setPower(self.TEST_CDL_POWER) + self.assertIsNone(self.cdl_tr.validate()) + + # Exception validation test + self.cdl_tr.setPower([-1, -2, -3]) + with self.assertRaises(OCIO.Exception): + self.cdl_tr.validate() + + def test_validate_direction(self): + """ + Test the validate() method for direction. + Direction must be forward or inverse. + """ + + self.cdl_tr.setDirection(OCIO.TRANSFORM_DIR_FORWARD) + self.assertIsNone(self.cdl_tr.validate()) + + # As the CDL Transform does not support the unknown direction, + # it preserves the original direction. + self.cdl_tr.setDirection(OCIO.TRANSFORM_DIR_UNKNOWN) + self.assertIsNone(self.cdl_tr.validate()) def test_equality(self): + """ + Test the equals() method. + """ cdl1 = OCIO.CDLTransform() self.assertTrue(cdl1.equals(cdl1)) cdl2 = OCIO.CDLTransform() - self.assertTrue(cdl1.equals(cdl2)) self.assertTrue(cdl2.equals(cdl1)) cdl1.setSat(0.12601234) - self.assertFalse(cdl1.equals(cdl2)) self.assertFalse(cdl2.equals(cdl1)) cdl2.setSat(0.12601234) - self.assertTrue(cdl1.equals(cdl2)) self.assertTrue(cdl2.equals(cdl1)) - - def test_validation(self): - - cdl1 = OCIO.CDLTransform() - cdl1.validate() - - cdl1.setSat(1.12) - cdl1.validate() - - # Test one faulty saturation - - cdl1.setSat(-1.12) - with self.assertRaises(Exception): - cdl1.validate() + def test_constructor_with_keyword(self): + """ + Test CDLTransform constructor with keywords and validate its values. + """ + + # With keywords in their proper order. + cdl_tr = OCIO.CDLTransform(slope=self.TEST_CDL_SLOPE, + offset=self.TEST_CDL_OFFSET, + power=self.TEST_CDL_POWER, + sat=self.TEST_CDL_SAT, + id=self.TEST_CDL_ID, + desc=self.TEST_CDL_DESC) + + self.assertEqual(self.TEST_CDL_ID, cdl_tr.getID()) + self.assertEqual(self.TEST_CDL_DESC, cdl_tr.getDescription()) + self.assertEqual(self.TEST_CDL_SLOPE, cdl_tr.getSlope()) + self.assertEqual(self.TEST_CDL_OFFSET, cdl_tr.getOffset()) + self.assertEqual(self.TEST_CDL_POWER, cdl_tr.getPower()) + self.assertEqual(self.TEST_CDL_SAT, cdl_tr.getSat()) + self.assertEqual(self.TEST_CDL, cdl_tr.getXML()) + + # With keyword not in their proper order. + cdl_tr2 = OCIO.CDLTransform(id=self.TEST_CDL_ID, + desc=self.TEST_CDL_DESC, + slope=self.TEST_CDL_SLOPE, + offset=self.TEST_CDL_OFFSET, + power=self.TEST_CDL_POWER, + sat=self.TEST_CDL_SAT) + + self.assertEqual(self.TEST_CDL_ID, cdl_tr2.getID()) + self.assertEqual(self.TEST_CDL_DESC, cdl_tr2.getDescription()) + self.assertEqual(self.TEST_CDL_SLOPE, cdl_tr2.getSlope()) + self.assertEqual(self.TEST_CDL_OFFSET, cdl_tr2.getOffset()) + self.assertEqual(self.TEST_CDL_POWER, cdl_tr2.getPower()) + self.assertEqual(self.TEST_CDL_SAT, cdl_tr2.getSat()) + self.assertEqual(self.TEST_CDL, cdl_tr2.getXML()) + + def test_constructor_without_keyword(self): + """ + Test CDLTransform constructor without keywords and validate its values. + """ + + cdl_tr = OCIO.CDLTransform(self.TEST_CDL_SLOPE, + self.TEST_CDL_OFFSET, + self.TEST_CDL_POWER, + self.TEST_CDL_SAT, + self.TEST_CDL_ID, + self.TEST_CDL_DESC) + + self.assertEqual(self.TEST_CDL_ID, cdl_tr.getID()) + self.assertEqual(self.TEST_CDL_DESC, cdl_tr.getDescription()) + self.assertEqual(self.TEST_CDL_SLOPE, cdl_tr.getSlope()) + self.assertEqual(self.TEST_CDL_OFFSET, cdl_tr.getOffset()) + self.assertEqual(self.TEST_CDL_POWER, cdl_tr.getPower()) + self.assertEqual(self.TEST_CDL_SAT, cdl_tr.getSat()) + self.assertEqual(self.TEST_CDL, cdl_tr.getXML()) + + def test_constructor_without_parameter(self): + """ + Test CDLTransform default constructor and validate its values. + """ + + cdl_tr = OCIO.CDLTransform() + + self.assertEqual(cdl_tr.getID(), '') + self.assertEqual(cdl_tr.getDescription(), '') + self.assertEqual(cdl_tr.getSlope(), [1.0, 1.0, 1.0]) + self.assertEqual(cdl_tr.getOffset(), [0.0, 0.0, 0.0]) + self.assertEqual(cdl_tr.getPower(), [1.0, 1.0, 1.0]) + self.assertEqual(cdl_tr.getSat(), 1.0) + self.assertEqual(cdl_tr.getXML(), DEFAULT_CDL) diff --git a/tests/python/ColorSpaceTest.py b/tests/python/ColorSpaceTest.py index f26075f953..8cff13f0a5 100644 --- a/tests/python/ColorSpaceTest.py +++ b/tests/python/ColorSpaceTest.py @@ -1,31 +1,304 @@ # SPDX-License-Identifier: BSD-3-Clause # Copyright Contributors to the OpenColorIO Project. -import unittest, os, sys +import unittest +import os +import sys + import PyOpenColorIO as OCIO +from UnitTestUtils import SIMPLE_CONFIG, TEST_NAMES, TEST_DESCS, TEST_CATEGORIES + class ColorSpaceTest(unittest.TestCase): - - def test_interface(self): + def setUp(self): + self.colorspace = OCIO.ColorSpace() + self.log_tr = OCIO.LogTransform(10) + + def tearDown(self): + self.colorspace = None + self.log_tr = None + + def test_allocation(self): + """ + Test the setAllocation() and getAllocation() methods. + """ + + # Known constants tests + for i, allocation in enumerate(OCIO.Allocation.__members__.values()): + self.colorspace.setAllocation(allocation) + self.assertEqual(allocation, self.colorspace.getAllocation()) + + # Wrong type tests (using TransformDirection instead.) + for direction in OCIO.TransformDirection.__members__.values(): + with self.assertRaises(TypeError): + self.colorspace.setAllocation(direction) + + # Wrong type tests (set to None.) + with self.assertRaises(TypeError): + self.colorspace.setAllocation(None) + + def test_allocation_vars(self): + """ + Test the setAllocationVars() and getAllocationVars() methods. + """ + + # Array length tests + alloc_vars = [] + for i in range(1, 5): + # This will create [0.1] up to [0.1, 0.2, 0.3, 0.4] + alloc_vars.append(0.1 * i) + if i < 2 or i > 3: + with self.assertRaises(OCIO.Exception): + self.colorspace.setAllocationVars(alloc_vars) + else: + self.colorspace.setAllocationVars(alloc_vars) + self.assertEqual(len(alloc_vars), len( + self.colorspace.getAllocationVars())) + + # Wrong type tests + wrong_alloc_vars = [['test'], 'test', 0.1, 1] + for wrong_alloc_var in wrong_alloc_vars: + with self.assertRaises(TypeError): + self.colorspace.setAllocationVars(wrong_alloc_var) + + def test_bitdepth(self): + """ + Test the setBitDepth() and getBitDepth() methods. + """ + + # Known constants tests + for i, bit_depth in enumerate(OCIO.BitDepth.__members__.values()): + self.colorspace.setBitDepth(bit_depth) + self.assertEqual(bit_depth, self.colorspace.getBitDepth()) + + # Wrong type tests (using TransformDirection instead.) + for direction in OCIO.TransformDirection.__members__.values(): + with self.assertRaises(TypeError): + self.colorspace.setBitDepth(direction) + + # Wrong type tests (set to None.) + with self.assertRaises(TypeError): + self.colorspace.setBitDepth(None) + + def test_category(self): + """ + Test the hasCategory(), addCategory(), removeCategory(), + getCategories() and clearCategories() methods. + """ + + # Test empty categories + self.assertFalse(self.colorspace.hasCategory('ocio')) + self.assertEqual(len(self.colorspace.getCategories()), 0) + with self.assertRaises(IndexError): + self.colorspace.getCategories()[0] + + # Test with defined TEST_CATEGORIES. + for i, y in enumerate(TEST_CATEGORIES): + self.assertEqual(len(self.colorspace.getCategories()), i) + self.colorspace.addCategory(y) + self.assertTrue(self.colorspace.hasCategory(y)) + + # Test the output list is equal to TEST_CATEGORIES. + self.assertListEqual( + list(self.colorspace.getCategories()), TEST_CATEGORIES) + + # Test the length of list is equal to the length of TEST_CATEGORIES. + self.assertEqual(len(self.colorspace.getCategories()), + len(TEST_CATEGORIES)) + + iterator = self.colorspace.getCategories() + for a in TEST_CATEGORIES: + self.assertEqual(a, next(iterator)) + + # Test the length of categories is zero after clearCategories() + self.colorspace.clearCategories() + self.assertEqual(len(self.colorspace.getCategories()), 0) + + # Testing individually adding and removing a category. + self.colorspace.addCategory(TEST_CATEGORIES[0]) + self.assertEqual(len(self.colorspace.getCategories()), 1) + self.colorspace.removeCategory(TEST_CATEGORIES[0]) + self.assertEqual(len(self.colorspace.getCategories()), 0) + + def test_config(self): + """ + Test the ColorSpace object from an OCIO config. + """ + + # Get simple config file from Constants.py + cfg = OCIO.Config().CreateFromStream(SIMPLE_CONFIG) + + # Test ColorSpace class object getters from config + cs = cfg.getColorSpace('vd8') + self.assertEqual(cs.getName(), 'vd8') + self.assertEqual(cs.getDescription(), 'how many transforms can we use?\n') + self.assertEqual(cs.getFamily(), 'vd8') + self.assertEqual(cs.getAllocation(), OCIO.ALLOCATION_UNIFORM) + self.assertEqual(cs.getAllocationVars(), []) + self.assertEqual(cs.getEqualityGroup(), '') + self.assertEqual(cs.getBitDepth(), OCIO.BIT_DEPTH_UINT8) + self.assertFalse(cs.isData()) + + to_ref = cs.getTransform(OCIO.COLORSPACE_DIR_TO_REFERENCE) + self.assertIsInstance(to_ref, OCIO.GroupTransform) + self.assertEqual(len(to_ref), 3) + + def test_constructor_with_keyword(self): + """ + Test ColorSpace constructor with keywords and validate its values. + """ + + # With keywords in their proper order. + cs = OCIO.ColorSpace(name='test', + family='ocio family', + equalityGroup='My_Equality', + description='This is a test colourspace!', + bitDepth=OCIO.BIT_DEPTH_F32, + isData=False, + allocation=OCIO.ALLOCATION_LG2, + allocationVars=[0.0, 1.0]) + + self.assertEqual(cs.getName(), 'test') + self.assertEqual(cs.getFamily(), 'ocio family') + self.assertEqual(cs.getEqualityGroup(), 'My_Equality') + self.assertEqual(cs.getDescription(), 'This is a test colourspace!') + self.assertEqual(cs.getBitDepth(), OCIO.BIT_DEPTH_F32) + self.assertFalse(cs.isData()) + self.assertEqual(cs.getAllocation(), OCIO.ALLOCATION_LG2) + self.assertEqual(cs.getAllocationVars(), [0.0, 1.0]) + + # With keyword not in their proper order. + cs2 = OCIO.ColorSpace(family='ocio family', + name='test', + isData=False, + allocationVars=[0.0, 1.0], + allocation=OCIO.ALLOCATION_LG2, + description='This is a test colourspace!', + equalityGroup='My_Equality', + bitDepth=OCIO.BIT_DEPTH_F32, + ) + + self.assertEqual(cs2.getName(), 'test') + self.assertEqual(cs2.getFamily(), 'ocio family') + self.assertEqual(cs2.getEqualityGroup(), 'My_Equality') + self.assertEqual(cs2.getDescription(), 'This is a test colourspace!') + self.assertEqual(cs2.getBitDepth(), OCIO.BIT_DEPTH_F32) + self.assertFalse(cs2.isData()) + self.assertEqual(cs2.getAllocation(), OCIO.ALLOCATION_LG2) + self.assertEqual(cs2.getAllocationVars(), [0.0, 1.0]) + + def test_constructor_without_keyword(self): + """ + Test ColorSpace constructor without keywords and validate its values. + """ + + cs = OCIO.ColorSpace(OCIO.REFERENCE_SPACE_SCENE, + 'test', + 'ocio family', + 'My_Equality', + 'This is a test colourspace!', + OCIO.BIT_DEPTH_F32, + False, + OCIO.ALLOCATION_LG2, + [0.0, 1.0]) + + self.assertEqual(cs.getName(), 'test') + self.assertEqual(cs.getFamily(), 'ocio family') + self.assertEqual(cs.getEqualityGroup(), 'My_Equality') + self.assertEqual(cs.getDescription(), 'This is a test colourspace!') + self.assertEqual(cs.getBitDepth(), OCIO.BIT_DEPTH_F32) + self.assertFalse(cs.isData()) + self.assertEqual(cs.getAllocation(), OCIO.ALLOCATION_LG2) + self.assertEqual(cs.getAllocationVars(), [0.0, 1.0]) + + def test_constructor_without_parameter(self): + """ + Test ColorSpace default constructor and validate its values. + """ + cs = OCIO.ColorSpace() - cs.setName("mynewcolspace") - self.assertEqual("mynewcolspace", cs.getName()) - cs.setFamily("fam1") - self.assertEqual("fam1", cs.getFamily()) - cs.setEqualityGroup("match1") - self.assertEqual("match1", cs.getEqualityGroup()) - cs.setDescription("this is a test") - self.assertEqual("this is a test", cs.getDescription()) - cs.setBitDepth(OCIO.Constants.BIT_DEPTH_F16) - self.assertEqual(OCIO.Constants.BIT_DEPTH_F16, cs.getBitDepth()) - cs.setIsData(False) - self.assertEqual(False, cs.isData()) - cs.setAllocation(OCIO.Constants.ALLOCATION_LG2) - self.assertEqual(OCIO.Constants.ALLOCATION_LG2, cs.getAllocation()) - cs.setAllocationVars([0.1, 0.2, 0.3]) - self.assertEqual(3, len(cs.getAllocationVars())) - lt = OCIO.LogTransform() - lt.setBase(10.0) - cs.setTransform(lt, OCIO.Constants.COLORSPACE_DIR_TO_REFERENCE) - ott = cs.getTransform(OCIO.Constants.COLORSPACE_DIR_TO_REFERENCE) - self.assertEquals(10.0, ott.getBase()) + + self.assertEqual(cs.getName(), '') + self.assertEqual(cs.getFamily(), '') + self.assertEqual(cs.getEqualityGroup(), '') + self.assertEqual(cs.getDescription(), '') + self.assertEqual(cs.getBitDepth(), OCIO.BIT_DEPTH_UNKNOWN) + self.assertFalse(cs.isData()) + self.assertEqual(cs.getAllocation(), OCIO.ALLOCATION_UNIFORM) + self.assertEqual(cs.getAllocationVars(), []) + + def test_data(self): + """ + Test the setIsData() and getIsData() methods. + """ + + # Boolean tests + is_datas = [True, False] + for is_data in is_datas: + self.colorspace.setIsData(is_data) + self.assertEqual(is_data, self.colorspace.isData()) + + # Wrong type tests + wrong_is_datas = [['test'], 'test'] + for wrong_is_data in wrong_is_datas: + with self.assertRaises(TypeError): + self.colorspace.setIsData(wrong_is_data) + + def test_description(self): + """ + Test the setDescription() and getDescription() methods. + """ + + for desc in TEST_DESCS: + self.colorspace.setDescription(desc) + self.assertEqual(desc, self.colorspace.getDescription()) + + def test_equality(self): + """ + Test the setEqualityGroup() and getEqualityGroup() methods. + """ + + for name in TEST_NAMES: + self.colorspace.setEqualityGroup(name) + self.assertEqual(name, self.colorspace.getEqualityGroup()) + + def test_family(self): + """ + Test the setFamily() and getFamily() methods. + """ + + for name in TEST_NAMES: + self.colorspace.setFamily(name) + self.assertEqual(name, self.colorspace.getFamily()) + + def test_name(self): + """ + Test the setName() and getName() methods. + """ + + for name in TEST_NAMES: + self.colorspace.setName(name) + self.assertEqual(name, self.colorspace.getName()) + + def test_transform(self): + """ + Test the setTransform() and getTransform() methods. + """ + + # Known constants tests + for i, direction in enumerate(OCIO.ColorSpaceDirection.__members__.values()): + if direction == OCIO.COLORSPACE_DIR_UNKNOWN: + with self.assertRaises(OCIO.Exception): + self.colorspace.setTransform(self.log_tr, direction) + else: + self.colorspace.setTransform(self.log_tr, direction) + + if direction == OCIO.COLORSPACE_DIR_UNKNOWN: + with self.assertRaises(OCIO.Exception): + log_transform = self.colorspace.getTransform( + direction) + else: + log_transform = self.colorspace.getTransform(direction) + self.assertIsInstance(log_transform, OCIO.LogTransform) + self.assertEquals(self.log_tr.getBase(), + log_transform.getBase()) diff --git a/tests/python/ConfigTest.py b/tests/python/ConfigTest.py index d9d975a8f7..a2c80b22e9 100644 --- a/tests/python/ConfigTest.py +++ b/tests/python/ConfigTest.py @@ -35,7 +35,7 @@ class ConfigTest(unittest.TestCase): bitdepth: 32f description: | A raw color space. Conversions to and from this space are no-ops. - + isdata: true allocation: uniform @@ -49,7 +49,7 @@ class ConfigTest(unittest.TestCase): representation of the scene with primaries that correspond to scanned film. 0.18 in this space corresponds to a properly exposed 18% grey card. - + isdata: false allocation: lg2 @@ -60,7 +60,7 @@ class ConfigTest(unittest.TestCase): bitdepth: 8ui description: | how many transforms can we use? - + isdata: false allocation: uniform to_reference: ! @@ -69,7 +69,7 @@ class ConfigTest(unittest.TestCase): - ! {matrix: [1, 2, 3, 4, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1], offset: [1, 2, 0, 0]} - ! {slope: [0.9, 1, 1], offset: [0.1, 0.3, 0.4], power: [1.1, 1.1, 1.1], sat: 0.9} """ - + def setUp(self): osx_hack = '' @@ -81,10 +81,10 @@ def setUp(self): self.GLSLResult = """ // Generated by OpenColorIO -vec4 pytestocio(in vec4 inPixel, - const sampler3D lut3d) +vec4 pytestocio(in vec4 inPixel, + const sampler3D lut3d) { -vec4 out_pixel = inPixel; +vec4 out_pixel = inPixel; out_pixel = out_pixel * mat4(1.0874889, -0.079466686, -0.0080222245, 0., -0.023622228, 1.0316445, -0.0080222245, 0., -0.023622226, -0.079466686, 1.1030889, 0., 0., 0., 0., 1.); out_pixel = pow(max(out_pixel, vec4(0., 0., 0., 0.)), vec4(0.90909088, 0.90909088, 0.90909088, 1.)); out_pixel = out_pixel * mat4(1.1111112, -2., -3., -4., 0., 1., 0., 0., 0., 0., 1., 0., 0., 0., 0., 1.); @@ -96,9 +96,9 @@ def setUp(self): } """ - + def test_is_editable(self): - + cfg = OCIO.Config().CreateFromStream(self.SIMPLE_PROFILE) self.assertEqual(cfg.isEditable(), False) cfg = cfg.createEditableCopy() @@ -107,12 +107,11 @@ def test_is_editable(self): self.assertEqual(ctx.isEditable(), False) ctx = ctx.createEditableCopy() self.assertEqual(ctx.isEditable(), True) - ctx.setEnvironmentMode(OCIO.Constants.ENV_ENVIRONMENT_LOAD_ALL) - + ctx.setEnvironmentMode(OCIO.ENV_ENVIRONMENT_LOAD_ALL) + def test_interface(self): - - _cfg = OCIO.Config().CreateFromStream(self.SIMPLE_PROFILE) - _cfge = _cfg.createEditableCopy() + + _cfge = OCIO.Config().CreateFromStream(self.SIMPLE_PROFILE) _cfge.clearEnvironmentVars() self.assertEqual(0, _cfge.getNumEnvironmentVars()) _cfge.addEnvironmentVar("FOO", "test1") @@ -135,10 +134,8 @@ def test_interface(self): self.assertEqual(self.SIMPLE_PROFILE, _cfg.serialize()) #self.assertEqual("$07d1fb1509eeae1837825fd4242f8a69:$885ad1683add38a11f7bbe34e8bf9ac0", # _cfg.getCacheID()) - con = _cfg.getCurrentContext() + con = _cfge.getCurrentContext() self.assertNotEqual(0, con.getNumStringVars()) - #self.assertEqual("", _cfg.getCacheID(con)) - #self.assertEqual("", _cfge.getWorkingDir()) _cfge.setWorkingDir("/foobar") self.assertEqual("/foobar", _cfge.getWorkingDir()) self.assertEqual(3, _cfge.getNumColorSpaces()) @@ -156,7 +153,7 @@ def test_interface(self): _cfge.setStrictParsingEnabled(True) self.assertEqual(True, _cfge.isStrictParsingEnabled()) self.assertEqual(2, _cfge.getNumRoles()) - self.assertEqual(False, _cfg.hasRole("foo")) + self.assertEqual(False, _cfg.hasRole("foo")) _cfge.setRole("foo", "vd8") self.assertEqual(3, _cfge.getNumRoles()) self.assertEqual(True, _cfge.hasRole("foo")) @@ -197,17 +194,17 @@ def test_interface(self): self.assertEqual("somespace", glk.getProcessSpace()) _cfge.clearLooks() self.assertEqual(0, _cfge.getNumLooks()) - + #getProcessor(context, srcColorSpace, dstColorSpace) #getProcessor(context, srcName,dstName); #getProcessor(transform); #getProcessor(transform, direction); #getProcessor(context, transform, direction); - + _proc = _cfg.getProcessor("lnh", "vd8") self.assertEqual(False, _proc.isNoOp()) self.assertEqual(True, _proc.hasChannelCrosstalk()) - + #float packedpix[] = new float[]{0.48f, 0.18f, 0.9f, 1.0f, # 0.48f, 0.18f, 0.18f, 1.0f, # 0.48f, 0.18f, 0.18f, 1.0f, @@ -218,7 +215,7 @@ def test_interface(self): #_proc.apply(foo); #FloatBuffer wee = foo.getData(); #self.assertEqual(-2.4307251581696764E-35f, wee.get(2), 1e-8); - + # TODO: these should work in-place rgbfoo = _proc.applyRGB([0.48, 0.18, 0.18]) self.assertAlmostEqual(1.9351077, rgbfoo[0], delta=1e-7); @@ -226,7 +223,7 @@ def test_interface(self): rgbafoo = _proc.applyRGBA([0.48, 0.18, 0.18, 1.0]) self.assertAlmostEqual(1.0, rgbafoo[3], delta=1e-8) #self.assertEqual("$a92ef63abd9edf61ad5a7855da064648", _proc.getCpuCacheID()) - + _cfge.clearSearchPaths() self.assertEqual(0, _cfge.getNumSearchPaths()) _cfge.addSearchPath("First/ Path") diff --git a/tests/python/ConstantsTest.py b/tests/python/ConstantsTest.py index 5187287ee7..a64bc3a2dc 100644 --- a/tests/python/ConstantsTest.py +++ b/tests/python/ConstantsTest.py @@ -5,74 +5,73 @@ import PyOpenColorIO as OCIO class ConstantsTest(unittest.TestCase): - + def test_interface(self): - + # LoggingLevel - self.assertEqual(OCIO.Constants.LOGGING_LEVEL_NONE, "none") - self.assertEqual(OCIO.Constants.LOGGING_LEVEL_WARNING, "warning") - self.assertEqual(OCIO.Constants.LOGGING_LEVEL_INFO, "info") - self.assertEqual(OCIO.Constants.LOGGING_LEVEL_DEBUG, "debug") - self.assertEqual(OCIO.Constants.LOGGING_LEVEL_UNKNOWN, "unknown") - + self.assertEqual(OCIO.LOGGING_LEVEL_NONE, "none") + self.assertEqual(OCIO.LOGGING_LEVEL_WARNING, "warning") + self.assertEqual(OCIO.LOGGING_LEVEL_INFO, "info") + self.assertEqual(OCIO.LOGGING_LEVEL_DEBUG, "debug") + self.assertEqual(OCIO.LOGGING_LEVEL_UNKNOWN, "unknown") + # TransformDirection - self.assertEqual(OCIO.Constants.TRANSFORM_DIR_UNKNOWN, "unknown") - self.assertEqual(OCIO.Constants.TRANSFORM_DIR_FORWARD, "forward") - self.assertEqual(OCIO.Constants.TRANSFORM_DIR_INVERSE, "inverse") - self.assertEqual(OCIO.Constants.GetInverseTransformDirection(OCIO.Constants.TRANSFORM_DIR_UNKNOWN), - OCIO.Constants.TRANSFORM_DIR_UNKNOWN) - self.assertEqual(OCIO.Constants.GetInverseTransformDirection(OCIO.Constants.TRANSFORM_DIR_FORWARD), - OCIO.Constants.TRANSFORM_DIR_INVERSE) - self.assertEqual(OCIO.Constants.GetInverseTransformDirection(OCIO.Constants.TRANSFORM_DIR_INVERSE), - OCIO.Constants.TRANSFORM_DIR_FORWARD) - + self.assertEqual(OCIO.TRANSFORM_DIR_UNKNOWN, "unknown") + self.assertEqual(OCIO.TRANSFORM_DIR_FORWARD, "forward") + self.assertEqual(OCIO.TRANSFORM_DIR_INVERSE, "inverse") + self.assertEqual(OCIO.GetInverseTransformDirection(OCIO.TRANSFORM_DIR_UNKNOWN), + OCIO.TRANSFORM_DIR_UNKNOWN) + self.assertEqual(OCIO.GetInverseTransformDirection(OCIO.TRANSFORM_DIR_FORWARD), + OCIO.TRANSFORM_DIR_INVERSE) + self.assertEqual(OCIO.GetInverseTransformDirection(OCIO.TRANSFORM_DIR_INVERSE), + OCIO.TRANSFORM_DIR_FORWARD) + # ColorSpaceDirection - self.assertEqual(OCIO.Constants.COLORSPACE_DIR_UNKNOWN, "unknown") - self.assertEqual(OCIO.Constants.COLORSPACE_DIR_TO_REFERENCE, "to_reference") - self.assertEqual(OCIO.Constants.COLORSPACE_DIR_FROM_REFERENCE, "from_reference") - + self.assertEqual(OCIO.COLORSPACE_DIR_UNKNOWN, "unknown") + self.assertEqual(OCIO.COLORSPACE_DIR_TO_REFERENCE, "to_reference") + self.assertEqual(OCIO.COLORSPACE_DIR_FROM_REFERENCE, "from_reference") + # BitDepth - self.assertEqual(OCIO.Constants.BIT_DEPTH_UNKNOWN, "unknown") - self.assertEqual(OCIO.Constants.BIT_DEPTH_UINT8, "8ui") - self.assertEqual(OCIO.Constants.BIT_DEPTH_UINT10, "10ui") - self.assertEqual(OCIO.Constants.BIT_DEPTH_UINT12, "12ui") - self.assertEqual(OCIO.Constants.BIT_DEPTH_UINT14, "14ui") - self.assertEqual(OCIO.Constants.BIT_DEPTH_UINT16, "16ui") - self.assertEqual(OCIO.Constants.BIT_DEPTH_UINT32, "32ui") - self.assertEqual(OCIO.Constants.BIT_DEPTH_F16, "16f") - self.assertEqual(OCIO.Constants.BIT_DEPTH_F32, "32f") - + self.assertEqual(OCIO.BIT_DEPTH_UNKNOWN, "unknown") + self.assertEqual(OCIO.BIT_DEPTH_UINT8, "8ui") + self.assertEqual(OCIO.BIT_DEPTH_UINT10, "10ui") + self.assertEqual(OCIO.BIT_DEPTH_UINT12, "12ui") + self.assertEqual(OCIO.BIT_DEPTH_UINT14, "14ui") + self.assertEqual(OCIO.BIT_DEPTH_UINT16, "16ui") + self.assertEqual(OCIO.BIT_DEPTH_UINT32, "32ui") + self.assertEqual(OCIO.BIT_DEPTH_F16, "16f") + self.assertEqual(OCIO.BIT_DEPTH_F32, "32f") + # Allocation - self.assertEqual(OCIO.Constants.ALLOCATION_UNKNOWN, "unknown") - self.assertEqual(OCIO.Constants.ALLOCATION_UNIFORM, "uniform") - self.assertEqual(OCIO.Constants.ALLOCATION_LG2, "lg2") - + self.assertEqual(OCIO.ALLOCATION_UNKNOWN, "unknown") + self.assertEqual(OCIO.ALLOCATION_UNIFORM, "uniform") + self.assertEqual(OCIO.ALLOCATION_LG2, "lg2") + # Interpolation - self.assertEqual(OCIO.Constants.INTERP_UNKNOWN, "unknown") - self.assertEqual(OCIO.Constants.INTERP_NEAREST, "nearest") - self.assertEqual(OCIO.Constants.INTERP_LINEAR, "linear") - self.assertEqual(OCIO.Constants.INTERP_TETRAHEDRAL, "tetrahedral") - self.assertEqual(OCIO.Constants.INTERP_BEST, "best") - + self.assertEqual(OCIO.INTERP_UNKNOWN, "unknown") + self.assertEqual(OCIO.INTERP_NEAREST, "nearest") + self.assertEqual(OCIO.INTERP_LINEAR, "linear") + self.assertEqual(OCIO.INTERP_TETRAHEDRAL, "tetrahedral") + self.assertEqual(OCIO.INTERP_BEST, "best") + # GpuLanguage - self.assertEqual(OCIO.Constants.GPU_LANGUAGE_UNKNOWN, "unknown") - self.assertEqual(OCIO.Constants.GPU_LANGUAGE_CG, "cg") - self.assertEqual(OCIO.Constants.GPU_LANGUAGE_GLSL_1_0, "glsl_1.0") - self.assertEqual(OCIO.Constants.GPU_LANGUAGE_GLSL_1_3, "glsl_1.3") - + self.assertEqual(OCIO.GPU_LANGUAGE_UNKNOWN, "unknown") + self.assertEqual(OCIO.GPU_LANGUAGE_CG, "cg") + self.assertEqual(OCIO.GPU_LANGUAGE_GLSL_1_0, "glsl_1.0") + self.assertEqual(OCIO.GPU_LANGUAGE_GLSL_1_3, "glsl_1.3") + # EnvironmentMode - self.assertEqual(OCIO.Constants.ENV_ENVIRONMENT_UNKNOWN, "unknown") - self.assertEqual(OCIO.Constants.ENV_ENVIRONMENT_LOAD_PREDEFINED, "loadpredefined") - self.assertEqual(OCIO.Constants.ENV_ENVIRONMENT_LOAD_ALL, "loadall") - - # Roles - self.assertEqual(OCIO.Constants.ROLE_DEFAULT, "default") - self.assertEqual(OCIO.Constants.ROLE_REFERENCE, "reference") - self.assertEqual(OCIO.Constants.ROLE_DATA, "data") - self.assertEqual(OCIO.Constants.ROLE_COLOR_PICKING, "color_picking") - self.assertEqual(OCIO.Constants.ROLE_SCENE_LINEAR, "scene_linear") - self.assertEqual(OCIO.Constants.ROLE_COMPOSITING_LOG, "compositing_log") - self.assertEqual(OCIO.Constants.ROLE_COLOR_TIMING, "color_timing") - self.assertEqual(OCIO.Constants.ROLE_TEXTURE_PAINT, "texture_paint") - self.assertEqual(OCIO.Constants.ROLE_MATTE_PAINT, "matte_paint") + self.assertEqual(OCIO.ENV_ENVIRONMENT_UNKNOWN, "unknown") + self.assertEqual(OCIO.ENV_ENVIRONMENT_LOAD_PREDEFINED, "loadpredefined") + self.assertEqual(OCIO.ENV_ENVIRONMENT_LOAD_ALL, "loadall") + # Roles + self.assertEqual(OCIO.ROLE_DEFAULT, "default") + self.assertEqual(OCIO.ROLE_REFERENCE, "reference") + self.assertEqual(OCIO.ROLE_DATA, "data") + self.assertEqual(OCIO.ROLE_COLOR_PICKING, "color_picking") + self.assertEqual(OCIO.ROLE_SCENE_LINEAR, "scene_linear") + self.assertEqual(OCIO.ROLE_COMPOSITING_LOG, "compositing_log") + self.assertEqual(OCIO.ROLE_COLOR_TIMING, "color_timing") + self.assertEqual(OCIO.ROLE_TEXTURE_PAINT, "texture_paint") + self.assertEqual(OCIO.ROLE_MATTE_PAINT, "matte_paint") diff --git a/tests/python/ContextTest.py b/tests/python/ContextTest.py index 0656161dcf..6267354264 100644 --- a/tests/python/ContextTest.py +++ b/tests/python/ContextTest.py @@ -5,7 +5,7 @@ import PyOpenColorIO as OCIO class ContextTest(unittest.TestCase): - + def test_interface(self): cont = OCIO.Context() cont.setSearchPath("testing123") @@ -13,9 +13,9 @@ def test_interface(self): self.assertEqual("$4c2d66a612fc25ddd509591e1dead57b", cont.getCacheID()) self.assertEqual("testing123", cont.getSearchPath()) self.assertEqual("/dir/123", cont.getWorkingDir()) - cont.setStringVar("TeSt", "foobar") - self.assertEqual("foobar", cont.getStringVar("TeSt")) - self.assertEqual(1, cont.getNumStringVars()) + cont["TeSt"] = "foobar" + self.assertEqual("foobar", cont["TeSt"]) + self.assertEqual(1, len(cont)) self.assertEqual("TeSt", cont.getStringVarNameByIndex(0)) cont.loadEnvironment() self.assertNotEqual(0, cont.getNumStringVars()) @@ -23,9 +23,9 @@ def test_interface(self): self.assertEqual("/foo/foobar/bar", cont.resolveStringVar("/foo/${TEST1}/bar")) cont.clearStringVars() self.assertEqual(0, cont.getNumStringVars()) - self.assertEqual(OCIO.Constants.ENV_ENVIRONMENT_LOAD_PREDEFINED, cont.getEnvironmentMode()) - cont.setEnvironmentMode(OCIO.Constants.ENV_ENVIRONMENT_LOAD_ALL) - self.assertEqual(OCIO.Constants.ENV_ENVIRONMENT_LOAD_ALL, cont.getEnvironmentMode()) + self.assertEqual(OCIO.ENV_ENVIRONMENT_LOAD_PREDEFINED, cont.getEnvironmentMode()) + cont.setEnvironmentMode(OCIO.ENV_ENVIRONMENT_LOAD_ALL) + self.assertEqual(OCIO.ENV_ENVIRONMENT_LOAD_ALL, cont.getEnvironmentMode()) cont.clearSearchPaths() self.assertEqual(0, cont.getNumSearchPaths()) cont.addSearchPath("First/ Path") diff --git a/tests/python/MainTest.py b/tests/python/MainTest.py index 3643e729af..f10bada79e 100644 --- a/tests/python/MainTest.py +++ b/tests/python/MainTest.py @@ -5,7 +5,7 @@ import PyOpenColorIO as OCIO class MainTest(unittest.TestCase): - + FOO ="""ocio_profile_version: 2 search_path: \"\" @@ -37,18 +37,16 @@ class MainTest(unittest.TestCase): isdata: true allocation: uniform """ - + def test_interface(self): - + OCIO.ClearAllCaches() - #self.assertEqual("1.0.8", OCIO.version) - #self.assertEqual(16779264, OCIO.hexversion) - self.assertEqual(OCIO.Constants.LOGGING_LEVEL_INFO, OCIO.GetLoggingLevel()) - OCIO.SetLoggingLevel(OCIO.Constants.LOGGING_LEVEL_NONE) - self.assertEqual(OCIO.Constants.LOGGING_LEVEL_NONE, OCIO.GetLoggingLevel()) + self.assertEqual(OCIO.LOGGING_LEVEL_INFO, OCIO.GetLoggingLevel()) + OCIO.SetLoggingLevel(OCIO.LOGGING_LEVEL_NONE) + self.assertEqual(OCIO.LOGGING_LEVEL_NONE, OCIO.GetLoggingLevel()) foo = OCIO.GetCurrentConfig() self.assertEqual(self.FOO, foo.serialize()) - OCIO.SetLoggingLevel(OCIO.Constants.LOGGING_LEVEL_INFO) + OCIO.SetLoggingLevel(OCIO.LOGGING_LEVEL_INFO) bar = OCIO.Config().CreateFromStream(foo.serialize()) OCIO.SetCurrentConfig(bar) wee = OCIO.GetCurrentConfig() diff --git a/tests/python/OpenColorIOTestSuite.py b/tests/python/OpenColorIOTestSuite.py index 024500777d..8be9f61b28 100755 --- a/tests/python/OpenColorIOTestSuite.py +++ b/tests/python/OpenColorIOTestSuite.py @@ -1,71 +1,81 @@ # SPDX-License-Identifier: BSD-3-Clause # Copyright Contributors to the OpenColorIO Project. -import unittest, os, sys +import unittest +import os +import sys build_location = sys.argv[1] +os.environ["BUILD_LOCATION"] = build_location opencolorio_sse = sys.argv[2].lower() == 'true' -opencolorio_dir = os.path.join(build_location, "src", "OpenColorIO") -pyopencolorio_dir = os.path.join(build_location, "src", "bindings", "python") +opencolorio_dir = os.path.join(build_location, 'src', 'OpenColorIO') +pyopencolorio_dir = os.path.join(build_location, 'src', 'bindings', 'python') if os.name == 'nt': # On Windows we must append the build type to the build dirs and add the main library to PATH # Note: Only when compiling within Microsoft Visual Studio editor i.e. not on command line. - if len(sys.argv)==4: + if len(sys.argv) == 4: opencolorio_dir = os.path.join(opencolorio_dir, sys.argv[3]) pyopencolorio_dir = os.path.join(pyopencolorio_dir, sys.argv[3]) - os.environ['PATH'] = "{0};{1}".format(opencolorio_dir, os.environ.get('PATH',"")) + os.environ['PATH'] = '{0};{1}'.format( + opencolorio_dir, os.getenv('PATH', '')) elif sys.platform == 'darwin': # On OSX we must add the main library location to DYLD_LIBRARY_PATH - os.environ['DYLD_LIBRARY_PATH'] = "{0}:{1}".format(opencolorio_dir, os.environ.get('DYLD_LIBRARY_PATH', "")) + os.environ['DYLD_LIBRARY_PATH'] = '{0}:{1}'.format( + opencolorio_dir, os.getenv('DYLD_LIBRARY_PATH', '')) sys.path.insert(0, pyopencolorio_dir) import PyOpenColorIO as OCIO -from MainTest import * -from ConstantsTest import * -from ConfigTest import * -from ContextTest import * -from LookTest import * -from ColorSpaceTest import * -from GpuShaderDescTest import * -from Baker import * -from TransformsTest import * -from CDLTransformTest import * -from RangeTransformTest import * - -class FooTest(unittest.TestCase): - - def test_interface(self): - pass +import ColorSpaceTest +import CDLTransformTest +#from MainTest import * +#from ConstantsTest import * +#from ConfigTest import * +#from ContextTest import * +#from LookTest import * +#from GpuShaderDescTest import * +#from Baker import * +#from TransformsTest import * +#from RangeTransformTest import * def suite(): + """Load unittest.TestCase objects from *Test.py files within ./tests/Python + + :return: unittest test suite of TestCase objects. + :rtype: unittest.TestSuite + """ + + # top level directory cached on loader instance suite = unittest.TestSuite() - suite.addTest(MainTest("test_interface")) - suite.addTest(ConstantsTest("test_interface")) - suite.addTest(ConfigTest("test_interface")) - suite.addTest(ConfigTest("test_is_editable")) - suite.addTest(ContextTest("test_interface")) - suite.addTest(LookTest("test_interface")) - suite.addTest(ColorSpaceTest("test_interface")) - suite.addTest(CDLTransformTest("test_interface")) - suite.addTest(CDLTransformTest("test_equality")) - suite.addTest(CDLTransformTest("test_validation")) - suite.addTest(RangeTransformTest("test_interface")) - suite.addTest(RangeTransformTest("test_equality")) - suite.addTest(RangeTransformTest("test_validation")) - suite.addTest(TransformsTest("test_interface")) + loader = unittest.TestLoader() + + suite.addTest(loader.loadTestsFromModule(ColorSpaceTest)) + suite.addTest(loader.loadTestsFromModule(CDLTransformTest)) + #suite.addTest(MainTest("test_interface")) + #suite.addTest(ConstantsTest("test_interface")) + #suite.addTest(ConfigTest("test_interface")) + #suite.addTest(ConfigTest("test_is_editable")) + #suite.addTest(ContextTest("test_interface")) + #suite.addTest(LookTest("test_interface")) + #suite.addTest(RangeTransformTest("test_interface")) + #suite.addTest(RangeTransformTest("test_equality")) + #suite.addTest(RangeTransformTest("test_validation")) + #suite.addTest(TransformsTest("test_interface")) + # Processor # ProcessorMetadata - suite.addTest(GpuShaderDescTest("test_interface")) - suite.addTest(BakerTest("test_interface", opencolorio_sse)) + #suite.addTest(GpuShaderDescTest("test_interface")) + #suite.addTest(BakerTest("test_interface", opencolorio_sse)) # PackedImageDesc # PlanarImageDesc + return suite + if __name__ == '__main__': runner = unittest.TextTestRunner(verbosity=2) test_suite = suite() @@ -73,4 +83,3 @@ def suite(): if result.wasSuccessful() == False: sys.exit(1) sys.exit(0) - diff --git a/tests/python/TransformsTest.py b/tests/python/TransformsTest.py index 57c889a4e2..a1b80fb75a 100644 --- a/tests/python/TransformsTest.py +++ b/tests/python/TransformsTest.py @@ -10,39 +10,39 @@ def test_interface(self): ### AllocationTransform ### at = OCIO.AllocationTransform() - self.assertEqual(OCIO.Constants.ALLOCATION_UNIFORM, at.getAllocation()) - at.setAllocation(OCIO.Constants.ALLOCATION_LG2) - self.assertEqual(OCIO.Constants.ALLOCATION_LG2, at.getAllocation()) + self.assertEqual(OCIO.ALLOCATION_UNIFORM, at.getAllocation()) + at.setAllocation(OCIO.ALLOCATION_LG2) + self.assertEqual(OCIO.ALLOCATION_LG2, at.getAllocation()) self.assertEqual(0, at.getNumVars()) at.setVars([0.1, 0.2, 0.3]) self.assertEqual(3, at.getNumVars()) newvars = at.getVars() self.assertAlmostEqual(0.2, newvars[1], delta=1e-8) - at2 = OCIO.AllocationTransform(OCIO.Constants.ALLOCATION_LG2, + at2 = OCIO.AllocationTransform(OCIO.ALLOCATION_LG2, [0.1, 0.2, 0.3], - OCIO.Constants.TRANSFORM_DIR_INVERSE) - self.assertEqual(OCIO.Constants.ALLOCATION_LG2, at2.getAllocation()) + OCIO.TRANSFORM_DIR_INVERSE) + self.assertEqual(OCIO.ALLOCATION_LG2, at2.getAllocation()) self.assertEqual(3, at2.getNumVars()) newvars2 = at2.getVars() for i in range(0, 3): self.assertAlmostEqual(float(i+1)/10.0, newvars2[i], delta=1e-7) - self.assertEqual(OCIO.Constants.TRANSFORM_DIR_INVERSE, at2.getDirection()) + self.assertEqual(OCIO.TRANSFORM_DIR_INVERSE, at2.getDirection()) - at3 = OCIO.AllocationTransform(allocation=OCIO.Constants.ALLOCATION_LG2, + at3 = OCIO.AllocationTransform(allocation=OCIO.ALLOCATION_LG2, vars=[0.1, 0.2, 0.3], - direction=OCIO.Constants.TRANSFORM_DIR_INVERSE) - self.assertEqual(OCIO.Constants.ALLOCATION_LG2, at3.getAllocation()) + direction=OCIO.TRANSFORM_DIR_INVERSE) + self.assertEqual(OCIO.ALLOCATION_LG2, at3.getAllocation()) self.assertEqual(3, at3.getNumVars()) newvars3 = at3.getVars() for i in range(0, 3): self.assertAlmostEqual(float(i+1)/10.0, newvars3[i], delta=1e-7) - self.assertEqual(OCIO.Constants.TRANSFORM_DIR_INVERSE, at3.getDirection()) + self.assertEqual(OCIO.TRANSFORM_DIR_INVERSE, at3.getDirection()) ### Base Transform method tests ### - self.assertEqual(OCIO.Constants.TRANSFORM_DIR_FORWARD, at.getDirection()) - at.setDirection(OCIO.Constants.TRANSFORM_DIR_UNKNOWN) - self.assertEqual(OCIO.Constants.TRANSFORM_DIR_UNKNOWN, at.getDirection()) + self.assertEqual(OCIO.TRANSFORM_DIR_FORWARD, at.getDirection()) + at.setDirection(OCIO.TRANSFORM_DIR_UNKNOWN) + self.assertEqual(OCIO.TRANSFORM_DIR_UNKNOWN, at.getDirection()) ### CDLTransform ### cdl = OCIO.CDLTransform() @@ -104,7 +104,7 @@ def test_interface(self): [1.1, 1.2, 1.3], [2.1, 2.2, 2.3], 0.5, - OCIO.Constants.TRANSFORM_DIR_INVERSE, + OCIO.TRANSFORM_DIR_INVERSE, 'foobar123', 'bar') slope2 = cdl2.getSlope() offset2 = cdl2.getOffset() @@ -118,7 +118,7 @@ def test_interface(self): self.assertAlmostEqual(0.2126, luma2[0], delta=1e-8) self.assertAlmostEqual(0.7152, luma2[1], delta=1e-8) self.assertAlmostEqual(0.0722, luma2[2], delta=1e-8) - self.assertEqual(OCIO.Constants.TRANSFORM_DIR_INVERSE, cdl2.getDirection()) + self.assertEqual(OCIO.TRANSFORM_DIR_INVERSE, cdl2.getDirection()) self.assertEqual('foobar123', cdl2.getID()) self.assertEqual('bar', cdl2.getDescription()) @@ -126,7 +126,7 @@ def test_interface(self): offset=[1.1, 1.2, 1.3], power=[2.1, 2.2, 2.3], sat=0.5, - direction=OCIO.Constants.TRANSFORM_DIR_INVERSE, + direction=OCIO.TRANSFORM_DIR_INVERSE, id='foobar123', description='bar') slope3 = cdl2.getSlope() offset3 = cdl2.getOffset() @@ -140,7 +140,7 @@ def test_interface(self): self.assertAlmostEqual(0.2126, luma3[0], delta=1e-8) self.assertAlmostEqual(0.7152, luma3[1], delta=1e-8) self.assertAlmostEqual(0.0722, luma3[2], delta=1e-8) - self.assertEqual(OCIO.Constants.TRANSFORM_DIR_INVERSE, cdl3.getDirection()) + self.assertEqual(OCIO.TRANSFORM_DIR_INVERSE, cdl3.getDirection()) self.assertEqual('foobar123', cdl3.getID()) self.assertEqual('bar', cdl3.getDescription()) @@ -175,19 +175,19 @@ def test_interface(self): self.assertEqual(True, dt.getLooksOverrideEnabled()) dt2 = OCIO.DisplayTransform("lin18", "sRGB", "foobar", - OCIO.Constants.TRANSFORM_DIR_INVERSE) + OCIO.TRANSFORM_DIR_INVERSE) self.assertEqual("lin18", dt2.getInputColorSpaceName()) self.assertEqual("sRGB", dt2.getDisplay()) self.assertEqual("foobar", dt2.getView()) - self.assertEqual(OCIO.Constants.TRANSFORM_DIR_INVERSE, dt2.getDirection()) + self.assertEqual(OCIO.TRANSFORM_DIR_INVERSE, dt2.getDirection()) dt3 = OCIO.DisplayTransform(inputColorSpaceName="lin18", display="sRGB", view="foobar", - direction=OCIO.Constants.TRANSFORM_DIR_INVERSE) + direction=OCIO.TRANSFORM_DIR_INVERSE) self.assertEqual("lin18", dt3.getInputColorSpaceName()) self.assertEqual("sRGB", dt3.getDisplay()) self.assertEqual("foobar", dt3.getView()) - self.assertEqual(OCIO.Constants.TRANSFORM_DIR_INVERSE, dt3.getDirection()) + self.assertEqual(OCIO.TRANSFORM_DIR_INVERSE, dt3.getDirection()) ### ExponentTransform ### et = OCIO.ExponentTransform() @@ -201,8 +201,8 @@ def test_interface(self): self.assertEqual("foo", ft.getSrc()) ft.setCCCId("foobar") self.assertEqual("foobar", ft.getCCCId()) - ft.setInterpolation(OCIO.Constants.INTERP_NEAREST) - self.assertEqual(OCIO.Constants.INTERP_NEAREST, ft.getInterpolation()) + ft.setInterpolation(OCIO.INTERP_NEAREST) + self.assertEqual(OCIO.INTERP_NEAREST, ft.getInterpolation()) self.assertEqual(24, ft.getNumFormats()) self.assertEqual("flame", ft.getFormatNameByIndex(0)) self.assertEqual("3dl", ft.getFormatExtensionByIndex(0)) @@ -213,7 +213,7 @@ def test_interface(self): gt.appendTransform(ft) self.assertEqual(2, gt.getNumTransforms()) foo = gt.getTransform(0) - self.assertEqual(OCIO.Constants.TRANSFORM_DIR_FORWARD, foo.getDirection()) + self.assertEqual(OCIO.TRANSFORM_DIR_FORWARD, foo.getDirection()) ### LogTransform ### lt = OCIO.LogTransform() @@ -262,25 +262,25 @@ def test_interface(self): 0.9, 1.0, 1.1, 1.2, 1.3, 1.4, 1.5, 1.6], [0.1, 0.2, 0.3, 0.4], - OCIO.Constants.TRANSFORM_DIR_INVERSE) + OCIO.TRANSFORM_DIR_INVERSE) m44_4 = mt4.getMatrix() offset_4 = mt4.getOffset() for i in range(0, 16): self.assertAlmostEqual(float(i+1)/10.0, m44_4[i], delta=1e-7) for i in range(0, 4): self.assertAlmostEqual(float(i+1)/10.0, offset_4[i], delta=1e-7) - self.assertEqual(mt4.getDirection(), OCIO.Constants.TRANSFORM_DIR_INVERSE) + self.assertEqual(mt4.getDirection(), OCIO.TRANSFORM_DIR_INVERSE) mt5 = OCIO.MatrixTransform(matrix=[0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0, 1.1, 1.2, 1.3, 1.4, 1.5, 1.6], offset=[0.1, 0.2, 0.3, 0.4], - direction=OCIO.Constants.TRANSFORM_DIR_INVERSE) + direction=OCIO.TRANSFORM_DIR_INVERSE) m44_5 = mt5.getMatrix() offset_5 = mt5.getOffset() for i in range(0, 16): self.assertAlmostEqual(float(i+1)/10.0, m44_5[i], delta=1e-7) for i in range(0, 4): self.assertAlmostEqual(float(i+1)/10.0, offset_5[i], delta=1e-7) - self.assertEqual(mt5.getDirection(), OCIO.Constants.TRANSFORM_DIR_INVERSE) + self.assertEqual(mt5.getDirection(), OCIO.TRANSFORM_DIR_INVERSE) diff --git a/tests/python/UnitTestUtils.py b/tests/python/UnitTestUtils.py new file mode 100644 index 0000000000..ecb16784aa --- /dev/null +++ b/tests/python/UnitTestUtils.py @@ -0,0 +1,79 @@ +import os +from random import randint + + +TEST_DATAFILES_DIR = os.path.join(os.getenv('BUILD_LOCATION', None), 'testdata') + +TEST_NAMES = ['default_name', 'HelloWorld', + 'Simple Colourspace', 'a1b2c3d4', 'RGBA.1&2*3#'] + +TEST_DESCS = [ + 'These: < & " ' > are escape chars', 'this is a description', + 'The show reference space. This is a sensor referred linear ' + 'representation of the scene with primaries that correspond to\nscanned film. ' + '0.18 in this space corresponds to a properly\nexposed 18 % grey card.', + 'A raw color space. Conversions to and from this space are no-ops.', + 'how many transforms can we use?'] + +TEST_CATEGORIES = ['linear', 'rendering', 'log', '123', 'a1b.'] + +SIMPLE_CONFIG = """ocio_profile_version: 1 + +search_path: luts +strictparsing: false +luma: [0.2126, 0.7152, 0.0722] + +roles: + default: raw + scene_linear: lnh + +displays: + sRGB: + - ! {name: Film1D, colorspace: vd8} + - ! {name: Raw, colorspace: raw} + +active_displays: [] +active_views: [] + +colorspaces: + - ! + name: raw + family: raw + equalitygroup: "" + bitdepth: 32f + description: | + A raw color space. Conversions to and from this space are no-ops. + + isdata: true + allocation: uniform + + - ! + name: lnh + family: ln + equalitygroup: "" + bitdepth: 16f + description: | + The show reference space. This is a sensor referred linear + representation of the scene with primaries that correspond to + scanned film. 0.18 in this space corresponds to a properly + exposed 18% grey card. + + isdata: false + allocation: lg2 + + - ! + name: vd8 + family: vd8 + equalitygroup: "" + bitdepth: 8ui + description: | + how many transforms can we use? + + isdata: false + allocation: uniform + to_reference: ! + children: + - ! {value: [2.2, 2.2, 2.2, 1]} + - ! {matrix: [1, 2, 3, 4, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1], offset: [1, 2, 0, 0]} + - ! {slope: [0.9, 1, 1], offset: [0.1, 0.3, 0.4], power: [1.1, 1.1, 1.1], sat: 0.9} +""" diff --git a/tests/python/__init__.py b/tests/python/__init__.py new file mode 100644 index 0000000000..e69de29bb2 From b3398c1b47751f22733102bb7f114579e449e9c5 Mon Sep 17 00:00:00 2001 From: Michael Dolan Date: Mon, 8 Jun 2020 14:20:43 -0400 Subject: [PATCH 14/33] Add notes from 06-01-2020 TSC meeting (#1024) * Add notes from 06-01-2020 TSC meeting Signed-off-by: Michael Dolan * Fix typo Signed-off-by: Michael Dolan --- docs/tsc/meetings/2020-06-01.md | 159 ++++++++++++++++++++++++++++++++ 1 file changed, 159 insertions(+) create mode 100644 docs/tsc/meetings/2020-06-01.md diff --git a/docs/tsc/meetings/2020-06-01.md b/docs/tsc/meetings/2020-06-01.md new file mode 100644 index 0000000000..6f57861c47 --- /dev/null +++ b/docs/tsc/meetings/2020-06-01.md @@ -0,0 +1,159 @@ + + + +June 1, 2020 + +Host: Michael Dolan + +Rotating Secretary: Michael Dolan + +Attendees: + * [X] Mark Boorer (_TSC_) - Industrial Light & Magic + * [X] Mei Chu (_TSC_) - Sony Pictures Imageworks + * [X] Sean Cooper (_TSC ACES TAC Rep_) - DNEG + * [X] Michael Dolan (_TSC Chair_) - Epic Games + * [X] Patrick Hodoul (_TSC_) - Autodesk + * [X] John Mertic - Academy Software Foundation / Linux Foundation + * [X] Carol Payne (_TSC_) - Netflix + * [X] Mark Titchener (_TSC_) - Foundry + * [ ] Carl Rand (_TSC_) - Weta Digital + * [X] Doug Walker (_TSC Chief Architect_) - Autodesk + * [X] Kevin Wheatley (_TSC_) - Framestore + * [X] Bernard Lefebvre - Autodesk + * [X] Troy Sobotka + * [X] Joseph Goldstone - ARRI + +# **OCIO TSC Meeting Notes** + +* OpenColorIO-Config-ACES first steps + - Michael: Thinking of setting up a meeting to discuss a starting point. Do + we feel that a working group would be good for oversight? + - Sean: Could use oversight of technical maintenance, and of what goes into + the config; architecture vs implementation. Need to decide who owns the + decision making. OCIO or ACES? + - Michael: In previous discussion Academy preferred OCIO ownership, but + they were happy to guide. + - Sean: Need to discuss topics like: should the config have 300 color + spaces or 20? + - Doug: It's an Interesting issue. There are cameras in there that perhaps + should not be there. A group can discuss what the config should be. + General VFX config? Or implementation of ACES? + - Joseph: Should known broken transforms be weeded out or fixed? Can + someone at Canon confirm the transform is right? Could be a discussion + with ACES. + - Carol: Would be useful to have someone from ACES involved. + - Doug: From the previous conversation, we would become a product partner, + and ACES is involved through that. Partners will meet at events to + discuss how things are going. Somewhat hands off so far, and they + generally want external organizations to manage it. There's no active + certification process to test IDTs, etc. Up to product partners to own + their implementations. + - Michael: Does the ACES logo program have a validation process? + - Doug: There is a test kit, with a list of categories for levels of + certification; for grading software vs. a camera, for example. The test + kit had CTL and CLF files, etc. It may not be completed, due to ACESclip + being incomplete? + - Michael: For validation it would be great to have CI with verification of + config against ACES test images. I would be interested in contributing + this if there's need. + - Doug: There are some issues with some ACES reference images that don't + match CTL. I support the need to have a group meet and oversee these + configs. + - Carol: Perhaps we can have an ACES Central partnership; a dedicated place + to talk and participate? ACES sometimes get blamed for problems with + implementations. We need to be partners. + - Michael: They did express the desire to partner with OCIO. ACES just + wouldn't own the code. + - Sean: Should we tease apart the concept of an ACES config? It's really + more of a workhorse config for the industry currently. Studios grab it + and use it. Different configs have different needs. Just an ACES config + would be smaller and more straightforward. We should get a sampling of + users; pull them into the conversation. It's not just about ACES and + OCIO, but about helping the community with color management. + - Troy: The current config has some scripting implement already. + - **TODO**: Michael will work on getting a meeting schedule with interested + parties. + +* Keeping track of OCIO v2 TODOs + - Michael: Proposal to use GitHub Projects for _some_ task management: + - [GitHub Projects](https://github.com/AcademySoftwareFoundation/OpenColorIO/projects) + - Doug: OpenEXR has a discussion on that too, for the Imath work. People + have been supportive for using it. + - Carol: Agree this would be a good place to track and split up work. + - Doug: Documentation is the highest priority. Would like to have something + up and running at OCIO v2 launch time. That was going to be at SIGGRAPH, + but we still need to decide on a date. It could also be at DigiPro. This + is coming up quickly. I feel an urgency for getting something in place + where people can contribute to docs. + - **TODO**: Michael to explore setting up GH Projects to help keep track of + initiatives and priority. + +* Documentation status update + - Sean: Community feedback was fairly quiet. Started slack channel for + further discussion. + - Doug: Ben replied to the post with good ideas. + - Carol: Some replies from people interested in following along and others + with some ideas. Not a ton of response. I will go back and continue + research, and meet with Sean offline to establish a proposed plan for + implementation. + - Sean: Agree. My intent is to get PR in this week with a hosted GH page to + look at something and talk specifics. Can currently compile docstrings + from C++ headers and use with Python docstrings. I've been reformatting + C++ headers and making them doxygen compatible. Once the implementation is + worked out it will become a conversation about structure and what to fill + in. + - Sean: General question: Since Python and C++ docstring largely use the + same text, should we use abstract API docs? These could pull out + specifics about implementations, and can be manually written where needed. + - Michael: I have seen other API docs that will use tabs for specific + language implementation. The C++ docs also do this for different C++ + standards. + - Doug: Sean's doxyfy prototype had tabs for languages. + - Sean: It looks funny in VuePress, but could be fixed with CSS. My vision + is to have a generic description with language notes. I will try to do a + demo at the next meeting. + - Doug: We could set up different time for a focused discussion on docs if + needed too. + - Sean: Might be more people with thoughts, like Ben. + - **TODO**: Sean will get mechanical part of docs working and can arrange + additional meeting from there. + - Michael: Others can help once structure is in place. + - Sean: Doxygen generates headers with string literals. Not sure if we + should be committing auto-generating headers to the repo, or let them be + generated as part of the build process. It would need to be rebuilt + every time. + - Mark B: Better to do this in the build system. The Existing repo has the + same concepts for generated code. + - Sean: It needs to be there for python bindings to be built. + - Mark B: CMake can have target dependencies to make sure build order is + correct. + +* Foundry SDK usage in CI? + - John: We had a discussion around Foundry SDKs and CI build processes a + while back. Is this still something needed? I'm working with legal to + make an agreement with companies to allow SDK use in the build stack. + This topic was restarting to help with some needs on OTIO. + - Mark B: There was a discussion on who would maintain the OCIO Nuke + nodes, but that conversation stopped. OCIO v2 scratches a lot of their + itches, so they chose to wait and see. + - Mark T: Foundry would like to take ownership of the Nuke nodes and open + source them. + - Mark B: The nodes are already open source. New versions could be + contributed there. + - Mark T: True. We want to have more involvement with development of the + nodes. Nuke would be a requirement for the build process. Pete and I + will discuss how to proceed. + - John: The topic with legal is for terms around SDKs for open source use, + so that ASWF projects could leverage these. Both of these projects are + good example use cases to develop that. + - Michael: If nodes came back into repo, CI would be needed, so that would + be useful. + - Doug: CI currently doesn't build any plugins. Possible that core changes + could break plugins without us knowing. + - Mark T: We tried building the Nuke nodes against OCIO v2 recently and + weren't able to. + - Michael: There have been quite a few API changes. + - Mark T: We are not against contributing the nodes to the main project for + hosting. + - John: I will follow up on discussions with Foundry. We are going through + SDK terms and conditions. From 3866694a5ee027cc45dbfd69c202a21853cc24e3 Mon Sep 17 00:00:00 2001 From: Michael Dolan Date: Wed, 10 Jun 2020 08:19:11 -0400 Subject: [PATCH 15/33] Refactor PyBuiltinTransform (#1026) * Refactor PyBuiltinTransform Signed-off-by: Michael Dolan * Add unit tests, fix None style handling Signed-off-by: Michael Dolan * Fix Python 2/3 compatibility issue Signed-off-by: Michael Dolan * Fix Windows warning Signed-off-by: Michael Dolan Co-authored-by: Patrick Hodoul --- src/bindings/python/PyBuiltinTransform.cpp | 14 +- .../python/PyBuiltinTransformRegistry.cpp | 134 ++++++++++++++---- tests/python/BuiltinTransformRegistryTest.py | 109 ++++++++++++++ tests/python/BuiltinTransformTest.py | 100 +++++++++++++ tests/python/OpenColorIOTestSuite.py | 4 + tests/python/UnitTestUtils.py | 29 +++- 6 files changed, 353 insertions(+), 37 deletions(-) create mode 100644 tests/python/BuiltinTransformRegistryTest.py create mode 100644 tests/python/BuiltinTransformTest.py diff --git a/src/bindings/python/PyBuiltinTransform.cpp b/src/bindings/python/PyBuiltinTransform.cpp index be7db27c01..e69b6ac148 100644 --- a/src/bindings/python/PyBuiltinTransform.cpp +++ b/src/bindings/python/PyBuiltinTransform.cpp @@ -8,12 +8,24 @@ namespace OCIO_NAMESPACE void bindPyBuiltinTransform(py::module & m) { + BuiltinTransformRcPtr DEFAULT = BuiltinTransform::Create(); + py::class_(m, "BuiltinTransform") .def(py::init(&BuiltinTransform::Create)) + .def(py::init([](const std::string & style, TransformDirection dir) + { + BuiltinTransformRcPtr p = BuiltinTransform::Create(); + if (!style.empty()) { p->setStyle(style.c_str()); } + p->setDirection(dir); + p->validate(); + return p; + }), + "style"_a = DEFAULT->getStyle(), + "dir"_a = DEFAULT->getDirection()) - .def("setStyle", &BuiltinTransform::setStyle, "style"_a) + .def("setStyle", &BuiltinTransform::setStyle, "style"_a.none(false)) .def("getStyle", &BuiltinTransform::getStyle) .def("getDescription", &BuiltinTransform::getDescription); } diff --git a/src/bindings/python/PyBuiltinTransformRegistry.cpp b/src/bindings/python/PyBuiltinTransformRegistry.cpp index 091ad9d1e5..c76f857bab 100644 --- a/src/bindings/python/PyBuiltinTransformRegistry.cpp +++ b/src/bindings/python/PyBuiltinTransformRegistry.cpp @@ -7,39 +7,115 @@ namespace OCIO_NAMESPACE { -void bindPyBuiltinTransformRegistry(py::module & m) +namespace +{ + +// Wrapper to preserve the BuiltinTransformRegistry singleton. +class PyBuiltinTransformRegistry { - // Wrapper to preserve the BuiltinTransformRegistry singleton. - class Wrapper +public: + PyBuiltinTransformRegistry() = default; + ~PyBuiltinTransformRegistry() = default; + + size_t getNumBuiltins() const noexcept { - public: - Wrapper() = default; - Wrapper(const Wrapper &) = delete; - Wrapper & operator=(const Wrapper &) = delete; - ~Wrapper() = default; - - size_t getNumBuiltins() const noexcept - { - return BuiltinTransformRegistry::Get()->getNumBuiltins(); - } - - const char * getBuiltinStyle(size_t idx) const - { - return BuiltinTransformRegistry::Get()->getBuiltinStyle(idx); - } - - const char * getBuiltinDescription(size_t idx) const - { - return BuiltinTransformRegistry::Get()->getBuiltinDescription(idx); - } - }; - - py::class_(m, "BuiltinTransformRegistry") + return BuiltinTransformRegistry::Get()->getNumBuiltins(); + } + + const char * getBuiltinStyle(size_t idx) const + { + return BuiltinTransformRegistry::Get()->getBuiltinStyle(idx); + } + + const char * getBuiltinDescription(size_t idx) const + { + return BuiltinTransformRegistry::Get()->getBuiltinDescription(idx); + } +}; + +enum BuiltinTransformRegistryIterator +{ + IT_BUILTIN_STYLE = 0, + IT_BUILTIN +}; + +using BuiltinStyleIterator = PyIterator; +using BuiltinIterator = PyIterator; + +} // namespace + +void bindPyBuiltinTransformRegistry(py::module & m) +{ + auto cls = py::class_(m, "BuiltinTransformRegistry") .def(py::init<>()) - .def("getNumBuiltins", &Wrapper::getNumBuiltins) - .def("getBuiltinStyle", &Wrapper::getBuiltinStyle) - .def("getBuiltinDescription", &Wrapper::getBuiltinDescription); + .def("__iter__", [](PyBuiltinTransformRegistry & self) + { + return BuiltinStyleIterator(self); + }) + .def("__len__", [](PyBuiltinTransformRegistry & self) { return self.getNumBuiltins(); }) + .def("__getitem__", [](PyBuiltinTransformRegistry & self, const std::string & style) + { + for (size_t i = 0; i < self.getNumBuiltins(); i++) + { + const char * thisStyle = self.getBuiltinStyle(i); + if (StringUtils::Compare(std::string(thisStyle), style)) + { + return self.getBuiltinDescription(i); + } + } + + std::ostringstream os; + os << "'" << style << "'"; + throw py::key_error(os.str().c_str()); + }) + .def("__contains__", [](PyBuiltinTransformRegistry & self, const std::string & style) + { + for (size_t i = 0; i < self.getNumBuiltins(); i++) + { + const char * thisStyle = self.getBuiltinStyle(i); + if (StringUtils::Compare(std::string(thisStyle), style)) + { + return true; + } + } + return false; + }) + + .def("getBuiltins", [](PyBuiltinTransformRegistry & self) + { + return BuiltinIterator(self); + }); + + py::class_(cls, "BuiltinStyleIterator") + .def("__len__", [](BuiltinStyleIterator & it) { return it.m_obj.getNumBuiltins(); }) + .def("__getitem__", [](BuiltinStyleIterator & it, int i) + { + // BuiltinTransformRegistry provides index check with exception + return it.m_obj.getBuiltinStyle(i); + }) + .def("__iter__", [](BuiltinStyleIterator & it) -> BuiltinStyleIterator & { return it; }) + .def("__next__", [](BuiltinStyleIterator & it) + { + int i = it.nextIndex((int)it.m_obj.getNumBuiltins()); + return it.m_obj.getBuiltinStyle(i); + }); + + py::class_(cls, "BuiltinIterator") + .def("__len__", [](BuiltinIterator & it) { return it.m_obj.getNumBuiltins(); }) + .def("__getitem__", [](BuiltinIterator & it, int i) + { + // BuiltinTransformRegistry provides index check with exception + return py::make_tuple(it.m_obj.getBuiltinStyle(i), + it.m_obj.getBuiltinDescription(i)); + }) + .def("__iter__", [](BuiltinIterator & it) -> BuiltinIterator & { return it; }) + .def("__next__", [](BuiltinIterator & it) + { + int i = it.nextIndex((int)it.m_obj.getNumBuiltins()); + return py::make_tuple(it.m_obj.getBuiltinStyle(i), + it.m_obj.getBuiltinDescription(i)); + }); } } // namespace OCIO_NAMESPACE diff --git a/tests/python/BuiltinTransformRegistryTest.py b/tests/python/BuiltinTransformRegistryTest.py new file mode 100644 index 0000000000..07ed61a551 --- /dev/null +++ b/tests/python/BuiltinTransformRegistryTest.py @@ -0,0 +1,109 @@ +# SPDX-License-Identifier: BSD-3-Clause +# Copyright Contributors to the OpenColorIO Project. + +import collections +import unittest + +import PyOpenColorIO as OCIO +from UnitTestUtils import STRING_TYPES + + +class BuiltinTransformRegistryTest(unittest.TestCase): + # BuiltinTransformRegistry singleton + REGISTRY = None + + @classmethod + def setUpClass(cls): + cls.REGISTRY = OCIO.BuiltinTransformRegistry() + + def test_iterable(self): + # Iterate all styles, validating all are non-empty strings + all_styles = [] + for style in self.REGISTRY: + self.assertIsInstance(style, STRING_TYPES) + self.assertIsInstance(self.REGISTRY[style], STRING_TYPES) + all_styles.append(style) + + # All styles were iterated over, and __len__ and list() behave + self.assertEqual(len(all_styles), len(self.REGISTRY)) + self.assertListEqual(all_styles, list(self.REGISTRY)) + + # Test iterator instance + iterator = iter(self.REGISTRY) + self.assertIsInstance(iterator, collections.Iterable) + + # Iterator size is available + self.assertEqual(len(iterator), len(self.REGISTRY)) + + # Iterator supports range-based loop and indexing + values = list(iterator) + for i in range(len(iterator)): + # Item at index matches list result + self.assertEqual(iterator[i], values[i]) + self.assertIsInstance(iterator[i], STRING_TYPES) + + def test_get_builtins(self): + # tuple iterator (like dict.items()) + for item in self.REGISTRY.getBuiltins(): + self.assertIsInstance(item, tuple) + self.assertEqual(len(item), 2) + self.assertIsInstance(item[0], STRING_TYPES) + self.assertIsInstance(item[1], STRING_TYPES) + + # tuple unpacking support + for style, desc in self.REGISTRY.getBuiltins(): + # __getitem__ has correct result + self.assertEqual(self.REGISTRY[style], desc) + self.assertIsInstance(style, STRING_TYPES) + self.assertIsInstance(desc, STRING_TYPES) + + # Test iterator instance + iterator = self.REGISTRY.getBuiltins() + self.assertIsInstance(iterator, collections.Iterable) + + # Iterator size is available + self.assertEqual(len(iterator), len(self.REGISTRY)) + + # Iterator supports range-based loop and indexing + values = list(iterator) + for i in range(len(iterator)): + # Item at index matches list result + self.assertEqual(iterator[i], values[i]) + + self.assertIsInstance(iterator[i], tuple) + self.assertEqual(len(iterator[i]), 2) + self.assertIsInstance(iterator[i][0], STRING_TYPES) + self.assertIsInstance(iterator[i][1], STRING_TYPES) + + def test_contains(self): + # Valid __contains__ for all styles + for style in self.REGISTRY: + self.assertTrue(style in self.REGISTRY) + self.assertFalse(style not in self.REGISTRY) + + # Invalid __contains__ for non-styles + self.assertTrue("invalid" not in self.REGISTRY) + self.assertFalse("invalid" in self.REGISTRY) + + def test_multi_reference(self): + # Registry is a singleton. Make sure multiple Python + # instances can be held. + instances = [] + for i in range(10): + instances.append(OCIO.BuiltinTransformRegistry()) + + # Other instances should still function after deleting one. The + # underlying C++ object is not deleted. + instance_0 = instances.pop(0) + self.assertEqual(len(instances), 9) + del instance_0 + + # Variable is no longer defined + with self.assertRaises(NameError): + len(instance_0) + + # Test underlying C++ reference validity by accessing registry + # data for each instance. + for instance in instances: + self.assertGreaterEqual(len(instance), 1) + self.assertEqual(len(instance), len(self.REGISTRY)) diff --git a/tests/python/BuiltinTransformTest.py b/tests/python/BuiltinTransformTest.py new file mode 100644 index 0000000000..5cfa7b7c1a --- /dev/null +++ b/tests/python/BuiltinTransformTest.py @@ -0,0 +1,100 @@ +# SPDX-License-Identifier: BSD-3-Clause +# Copyright Contributors to the OpenColorIO Project. + +import unittest + +import PyOpenColorIO as OCIO + + +class BuiltinTransformTest(unittest.TestCase): + # BuiltinTransformRegistry singleton + REGISTRY = None + + # Default values + DEFAULT_STYLE = 'IDENTITY' + DEFAULT_DESC = '' + DEFAULT_STR = '' + + # One reference style + EXAMPLE_STYLE = 'ACES-AP0_to_CIE-XYZ-D65_BFD' + EXAMPLE_DESC = ( + 'Convert ACES AP0 primaries to CIE XYZ with a D65 white point with ' + 'Bradford adaptation') + + @classmethod + def setUpClass(cls): + cls.REGISTRY = OCIO.BuiltinTransformRegistry() + + def setUp(self): + self.builtin_tr = OCIO.BuiltinTransform() + + def cleanUp(self): + self.builtin_tr = None + + def test_style(self): + # Default style is identity + self.assertEqual(self.builtin_tr.getStyle(), self.DEFAULT_STYLE) + self.assertEqual(self.builtin_tr.getDescription(), self.DEFAULT_DESC) + + # Set/get all styles from registry + for style, desc in self.REGISTRY.getBuiltins(): + self.builtin_tr.setStyle(style) + self.assertEqual(self.builtin_tr.getStyle(), style) + self.assertEqual(self.builtin_tr.getDescription(), desc) + self.assertIsNone(self.builtin_tr.validate()) # Does not raise + + # Invalid style raises OCIO Exception + with self.assertRaises(OCIO.Exception): + self.builtin_tr.setStyle("invalid") + + # Safe invalid type handling + for invalid in (None, 1, True): + with self.assertRaises(TypeError): + self.builtin_tr.setStyle(invalid) + + def test_direction(self): + # All transform directions are supported + for direction in OCIO.TransformDirection.__members__.values(): + self.builtin_tr.setDirection(direction) + self.assertEqual(self.builtin_tr.getDirection(), direction) + + if direction != OCIO.TRANSFORM_DIR_UNKNOWN: + # Does not raise + self.assertIsNone(self.builtin_tr.validate()) + else: + # TRANSFORM_DIR_UNKNOWN raises OCIO Exception + with self.assertRaises(OCIO.Exception): + self.builtin_tr.validate() + + def test_constructor_keyword(self): + # Keyword args in order + builtin_tr1 = OCIO.BuiltinTransform(style=self.EXAMPLE_STYLE, + dir=OCIO.TRANSFORM_DIR_FORWARD) + + self.assertEqual(builtin_tr1.getStyle(), self.EXAMPLE_STYLE) + self.assertEqual(builtin_tr1.getDescription(), self.EXAMPLE_DESC) + self.assertEqual(builtin_tr1.getDirection(), + OCIO.TRANSFORM_DIR_FORWARD) + + # Keyword args out of order + builtin_tr2 = OCIO.BuiltinTransform(dir=OCIO.TRANSFORM_DIR_FORWARD, + style=self.EXAMPLE_STYLE) + + self.assertEqual(builtin_tr2.getStyle(), self.EXAMPLE_STYLE) + self.assertEqual(builtin_tr2.getDescription(), self.EXAMPLE_DESC) + self.assertEqual(builtin_tr2.getDirection(), + OCIO.TRANSFORM_DIR_FORWARD) + + def test_constructor_positional(self): + # Positional args + builtin_tr = OCIO.BuiltinTransform(self.EXAMPLE_STYLE, + OCIO.TRANSFORM_DIR_FORWARD) + + self.assertEqual(builtin_tr.getStyle(), self.EXAMPLE_STYLE) + self.assertEqual(builtin_tr.getDescription(), self.EXAMPLE_DESC) + self.assertEqual(builtin_tr.getDirection(), + OCIO.TRANSFORM_DIR_FORWARD) + + def test_str(self): + # str() and print() result matches C++ << operator + self.assertEqual(str(self.builtin_tr), self.DEFAULT_STR) diff --git a/tests/python/OpenColorIOTestSuite.py b/tests/python/OpenColorIOTestSuite.py index 8be9f61b28..96fd1600ba 100755 --- a/tests/python/OpenColorIOTestSuite.py +++ b/tests/python/OpenColorIOTestSuite.py @@ -31,6 +31,8 @@ import PyOpenColorIO as OCIO import ColorSpaceTest +import BuiltinTransformRegistryTest +import BuiltinTransformTest import CDLTransformTest #from MainTest import * #from ConstantsTest import * @@ -54,6 +56,8 @@ def suite(): loader = unittest.TestLoader() suite.addTest(loader.loadTestsFromModule(ColorSpaceTest)) + suite.addTest(loader.loadTestsFromModule(BuiltinTransformRegistryTest)) + suite.addTest(loader.loadTestsFromModule(BuiltinTransformTest)) suite.addTest(loader.loadTestsFromModule(CDLTransformTest)) #suite.addTest(MainTest("test_interface")) #suite.addTest(ConstantsTest("test_interface")) diff --git a/tests/python/UnitTestUtils.py b/tests/python/UnitTestUtils.py index ecb16784aa..91be0876bf 100644 --- a/tests/python/UnitTestUtils.py +++ b/tests/python/UnitTestUtils.py @@ -1,17 +1,32 @@ import os +import sys from random import randint -TEST_DATAFILES_DIR = os.path.join(os.getenv('BUILD_LOCATION', None), 'testdata') +# ----------------------------------------------------------------------------- +# Python 2/3 compatibility +# ----------------------------------------------------------------------------- +if sys.version_info.major >= 3: + STRING_TYPES = str +else: # Python 2 + STRING_TYPES = basestring -TEST_NAMES = ['default_name', 'HelloWorld', - 'Simple Colourspace', 'a1b2c3d4', 'RGBA.1&2*3#'] +# ----------------------------------------------------------------------------- +# Test data +# ----------------------------------------------------------------------------- +TEST_DATAFILES_DIR = os.path.join(os.getenv('BUILD_LOCATION'), 'testdata') + +TEST_NAMES = ['default_name', 'HelloWorld', 'Simple Colourspace', 'a1b2c3d4', + 'RGBA.1&2*3#'] TEST_DESCS = [ - 'These: < & " ' > are escape chars', 'this is a description', - 'The show reference space. This is a sensor referred linear ' - 'representation of the scene with primaries that correspond to\nscanned film. ' - '0.18 in this space corresponds to a properly\nexposed 18 % grey card.', + 'These: < & " ' > are escape chars', + 'this is a description', + + 'The show reference space. This is a sensor referred linear representation ' + 'of the scene with primaries that correspond to\nscanned film. 0.18 in ' + 'this space corresponds to a properly\nexposed 18 % grey card.', + 'A raw color space. Conversions to and from this space are no-ops.', 'how many transforms can we use?'] From 57f5a9630cf2a01b4585d94b81382f7ded6657b5 Mon Sep 17 00:00:00 2001 From: Michael Dolan Date: Wed, 10 Jun 2020 12:54:40 -0400 Subject: [PATCH 16/33] Add TSC meeting notes from 06-08-2020 (#1033) Signed-off-by: Michael Dolan Co-authored-by: Patrick Hodoul --- docs/tsc/meetings/2020-06-08.md | 122 ++++++++++++++++++++++++++++++++ 1 file changed, 122 insertions(+) create mode 100644 docs/tsc/meetings/2020-06-08.md diff --git a/docs/tsc/meetings/2020-06-08.md b/docs/tsc/meetings/2020-06-08.md new file mode 100644 index 0000000000..e792a7502e --- /dev/null +++ b/docs/tsc/meetings/2020-06-08.md @@ -0,0 +1,122 @@ + + + +Jube 8, 2020 + +Host: Michael Dolan + +Rotating Secretary: Michael Dolan + +Attendees: + * [X] Mark Boorer (_TSC_) - Industrial Light & Magic + * [X] Mei Chu (_TSC_) - Sony Pictures Imageworks + * [X] Sean Cooper (_TSC ACES TAC Rep_) - DNEG + * [X] Michael Dolan (_TSC Chair_) - Epic Games + * [X] Patrick Hodoul (_TSC_) - Autodesk + * [ ] John Mertic - Academy Software Foundation / Linux Foundation + * [X] Carol Payne (_TSC_) - Netflix + * [X] Mark Titchener (_TSC_) - Foundry + * [ ] Carl Rand (_TSC_) - Weta Digital + * [X] Doug Walker (_TSC Chief Architect_) - Autodesk + * [X] Kevin Wheatley (_TSC_) - Framestore + * [X] Bernard Lefebvre - Autodesk + +# **OCIO TSC Meeting Notes** + +* Move OCIO Slack to LF organization to ease sign-up? + - Michael: Emily and John reached out about the possibility of moving our + Slack channels to the ASWF Slack workspace. I didn't think we would want + to merge with their workspace since we have many active channels, but + John proposed that if we moved our existing workspace to the ASWF + organization, LF could setup self-sign-up, to make the space more + publicly accessible. Thoughts on that? + - TSC agrees that sounds good. + - Sean: Do they have paid access? Would be good to not have message limits, + since we are losing discussion history now. + - Carol: Can the existing discussion be migrated? + - **TODO**: Michael will follow up with LF for more details of their Slack + account. + +* OCIO docs discussion + - Carol: We are going to meet to discuss structure and writing of docs. + Maybe discuss in v2 working group? + - Doug: Time can be made available, but maybe a doc-focused meeting could + be held sooner. + - [Sean's straw-man docs for demo](https://seancooper.xyz/OpenColorIO-Docs/index.html) + - Sean: Best example of work is the API section, under Baker. Small but + complete example. Has generic class description at top, and API docs + below. Method signatures needs some work, but C++ and Python are grouped + together in tabs. In general, the goal is to have a page per class, and a + tab per language in each API section. Language tabs are ganged together + to avoid confusion while browsing docs. + - Docstrings are pulled from C++ headers, and from Python bindings via + autodoc. + - Doxygen is used to parse C++ headers. This is good for flexibility + without maintaining our own parsing code. Doxygen and Breathe convert + docs to Sphinx. + - It's a bit awkward if someone wants to modify a docstring. They would + need to modify the header, which means more traffic on the public + headers. Could get messy if we're not careful. It's a downside, but + in general we can create the outline and from there just update it + when the code changes. If you add additional methods or classes, they + also need to be addded to the reST doc structure. + - Currently cant' be super language specific in docs. + - Mark: Does it include text blocks which are stored somewhere else? + - Carol: The text part at the top might be nice to separate. If you are + changing API docs you are changing code. Maybe it would be safer to + separate descriptive sections. There may be times where we need to make + examples and reference something. Would be good to have control over that + text outside of header. + - Sean: It's just like that right now because of the current header + structure. We can decide what's in the header vs. what's in the reST. + Sphinx is nice because you can directly reference classes (with links), + which is hard to do with markdown. Still some quirks with the VuePress + theme that's being worked out. Some clean up needed. Remaining work is to + continue working on fleshing out API. Need to decide how to interface + with docs. How do people want to build? + - Michael: Needing to build the lib to build the docs could be a blocker + for something like RTD. + - Sean: Yeah, build time could be issue, since there is a timeout. Can + deploy Sphinx in RTD. We still need to add a version picker. Also need to + consider compiling code embedded in docs in CI to make sure it is still + valid. The old code base had examples that no longer worked. Also not + sure how to handle localization yet. Someone offered some language + translation if needed. + - Doug: How does this work fit with other things in documentation; + site-generators, etc. Does this proposal replace that? + - Sean: We haven't decided yet if Sphinx should just generate API docs and + something else build the website. Currently it's all through Sphinx. + Could go either way. We could have all the expository stuff on the + website, and API docs in RTD. It's flexible so we could do both. The + Doxyfy static site generator is user friendly, so could be used for the + website. Perhaps host API on RTD and host Doxyfy page on GH pages; two + deployments linked together. + - Carol: Worth seeing how much complexity is needed. A nice homepage and + separation of API docs all within one framework would be nice. Does + separating it make generation more complicated? + - Sean: Updating the headers requires recompiling python bindings. + - Mark B: There will be a lot of churn up front, but it should stabilize. + We could take the pain of rebuilding often up front, and it should get + better. It's not going to impact contributors long term. + - Sean: Complicated to find balance of being nice for contributors and nice + for documentation. The current design favors developers a bit more. So + far the work has mainly involved a slight change in header comment + formatting. There's still a lot of work to do for OCIO v2 docs, and + deciding what to cover and talk about. In theory much of the docs will + involve writing plain text. + - Carol: We'll set up a time to look over everything. It would be good to + discuss what makes contribution easier too. + - Sean: We can form a TODO list, so that interested contributors can pick + things to work on. + - Michael (post-TSC meeting note): This could implemented by adding issues + for each item to the documentation GH Project, which could be assigned + and tracked. + - **TODO**: Sean and Carol to plan a meeting to discuss structure and next + steps. + +* ACES Config + - Michael: Working on scheduling a meeting to discuss next steps, possibly + this Friday, but it is flexible if that conflicts with another meeting. + +* Items for next TSC meeting agenda: + - Carol: cineSync OCIO integration From 242a20a81bfa8e620f3d9c22c8a94dae4f41327a Mon Sep 17 00:00:00 2001 From: Mei Chu <33743518+meimchu@users.noreply.github.com> Date: Thu, 25 Jun 2020 20:51:23 -0700 Subject: [PATCH 17/33] Python unit test module LookTest update (#1027) * Initial update to python unit test module LookTest. Signed-off-by: Mei Chu * Updated PyLook and added some extra wrong type tests for LookTest.py Signed-off-by: Mei Chu * Updated LookTest and PyLook according to feedbacks. Signed-off-by: Mei Chu * Updated python LookTest according to further feedbacks. Signed-off-by: Mei Chu * Updated constructor method names per feedback. Signed-off-by: Mei Chu Co-authored-by: Patrick Hodoul --- src/bindings/python/PyLook.cpp | 12 +- tests/python/LookTest.py | 189 +++++++++++++++++++++++---- tests/python/OpenColorIOTestSuite.py | 4 +- 3 files changed, 175 insertions(+), 30 deletions(-) diff --git a/src/bindings/python/PyLook.cpp b/src/bindings/python/PyLook.cpp index f8c19a3659..7d74ade645 100644 --- a/src/bindings/python/PyLook.cpp +++ b/src/bindings/python/PyLook.cpp @@ -17,7 +17,7 @@ void bindPyLook(py::module & m) const std::string & processSpace, const TransformRcPtr & transform, const TransformRcPtr & inverseTransform, - const std::string & description) + const std::string & description) { LookRcPtr p = Look::Create(); if (!name.empty()) { p->setName(name.c_str()); } @@ -26,23 +26,23 @@ void bindPyLook(py::module & m) if (inverseTransform) { p->setInverseTransform(inverseTransform); } if (!description.empty()) { p->setDescription(description.c_str()); } return p; - }), + }), "name"_a = DEFAULT->getName(), "processSpace"_a = DEFAULT->getProcessSpace(), "transform"_a = DEFAULT->getTransform(), "inverseTransform"_a = DEFAULT->getInverseTransform(), - "description"_a = DEFAULT->getDescription()) + "description"_a = DEFAULT->getDescription()) .def("getName", &Look::getName) - .def("setName", &Look::setName, "name"_a) + .def("setName", &Look::setName, "name"_a.none(false)) .def("getProcessSpace", &Look::getProcessSpace) - .def("setProcessSpace", &Look::setProcessSpace, "processSpace"_a) + .def("setProcessSpace", &Look::setProcessSpace, "processSpace"_a.none(false)) .def("getTransform", &Look::getTransform) .def("setTransform", &Look::setTransform, "transform"_a) .def("getInverseTransform", &Look::getInverseTransform) .def("setInverseTransform", &Look::setInverseTransform, "transform"_a) .def("getDescription", &Look::getDescription) - .def("setDescription", &Look::setDescription, "description"_a); + .def("setDescription", &Look::setDescription, "description"_a.none(false)); defStr(cls); } diff --git a/tests/python/LookTest.py b/tests/python/LookTest.py index 78516c6080..2f5e0e4aac 100644 --- a/tests/python/LookTest.py +++ b/tests/python/LookTest.py @@ -1,28 +1,173 @@ # SPDX-License-Identifier: BSD-3-Clause # Copyright Contributors to the OpenColorIO Project. -import unittest, os, sys +import unittest +import os +import sys + import PyOpenColorIO as OCIO +from UnitTestUtils import TEST_NAMES, TEST_DESCS + class LookTest(unittest.TestCase): - - def test_interface(self): - lk = OCIO.Look() - lk.setName("coollook") - self.assertEqual("coollook", lk.getName()) - lk.setProcessSpace("somespace") - self.assertEqual("somespace", lk.getProcessSpace()) - lk.setDescription("this is a test") - self.assertEqual("this is a test", lk.getDescription()) - et = OCIO.ExponentTransform() - et.setValue([0.1, 0.2, 0.3, 0.4]) - lk.setTransform(et) - oet = lk.getTransform() - vals = oet.getValue() - self.assertAlmostEqual(0.2, vals[1], delta=1e-8) - iet = OCIO.ExponentTransform() - iet.setValue([-0.1, -0.2, -0.3, -0.4]) - lk.setInverseTransform(iet) - ioet = lk.getInverseTransform() - vals2 = ioet.getValue() - self.assertAlmostEqual(-0.2, vals2[1], delta=1e-8) + TEST_PROCESS_SPACES = ['raw', 'lnh', 'vd8', 'a.b.c.', '1-2-3-'] + TEST_EXP_VALUES = [0.1, 0.2, 0.3, 0.4] + + def setUp(self): + self.look = OCIO.Look() + + def tearDown(self): + self.look = None + + def test_name(self): + """ + Test the setName() and getName() methods. + """ + + # Default initialized name value is "" + self.assertEqual(self.look.getName(), '') + + for name in TEST_NAMES: + self.look.setName(name) + self.assertEqual(name, self.look.getName()) + + # Wrong type tests. + for invalid in (None, 1): + with self.assertRaises(TypeError): + self.look.setName(invalid) + + def test_process_space(self): + """ + Test the setProcessSpace() and getProcessName() methods. + """ + + # Default initialized process space value is "" + self.assertEqual(self.look.getProcessSpace(), '') + + for process_space in self.TEST_PROCESS_SPACES: + self.look.setProcessSpace(process_space) + self.assertEqual(process_space, self.look.getProcessSpace()) + + # Wrong type tests. + for invalid in (None, 1): + with self.assertRaises(TypeError): + self.look.setProcessSpace(invalid) + + def test_description(self): + """ + Test the setDescription() and getDescription() methods. + """ + + # Default initialized description value is "" + self.assertEqual(self.look.getDescription(), '') + + for desc in TEST_DESCS: + self.look.setDescription(desc) + self.assertEqual(desc, self.look.getDescription()) + + # Wrong type tests. + for invalid in (None, 1): + with self.assertRaises(TypeError): + self.look.setDescription(invalid) + + def test_transform(self): + """ + Test the setTransform() and getTransform() methods. + """ + + # Default initialized transform value is None + self.assertIsNone(self.look.getTransform()) + + exp_tr = OCIO.ExponentTransform() + exp_tr.setValue(self.TEST_EXP_VALUES) + self.look.setTransform(exp_tr) + out_exp_tr = self.look.getTransform() + self.assertListEqual(out_exp_tr.getValue(), self.TEST_EXP_VALUES) + + # Wrong type tests. + for invalid in (OCIO.ALLOCATION_UNIFORM, 1): + with self.assertRaises(TypeError): + self.look.setTransform(invalid) + + def test_inverse_transform(self): + """ + Test the setInverseTransform() and getInverseTransform() methods. + """ + + # Default initialized inverse transform value is None + self.assertIsNone(self.look.getInverseTransform()) + + exp_tr = OCIO.ExponentTransform() + inv_exp_values = [1.0 / v for v in self.TEST_EXP_VALUES] + exp_tr.setValue(inv_exp_values) + self.look.setInverseTransform(exp_tr) + inv_oet = self.look.getInverseTransform() + self.assertListEqual(inv_oet.getValue(), inv_exp_values) + + # Wrong type tests. + for invalid in (OCIO.ALLOCATION_UNIFORM, 1): + with self.assertRaises(TypeError): + self.look.setInverseTransform(invalid) + + def test_constructor_with_keyword(self): + """ + Test Look constructor with keywords and validate its values. + """ + + # With keywords in their proper order. + exp_tr = OCIO.ExponentTransform() + inv_exp_tr = OCIO.ExponentTransform() + look = OCIO.Look(name='coollook', + processSpace='somespace', + transform=exp_tr, + inverseTransform=inv_exp_tr, + description='this is a test') + + self.assertEqual(look.getName(), 'coollook') + self.assertEqual(look.getProcessSpace(), 'somespace') + self.assertIsInstance(look.getTransform(), type(exp_tr)) + self.assertIsInstance(look.getInverseTransform(), type(inv_exp_tr)) + self.assertEqual(look.getDescription(), 'this is a test') + + # With keyword not in their proper order. + exp_tr2 = OCIO.ExponentTransform() + inv_exp_tr2 = OCIO.ExponentTransform() + look2 = OCIO.Look(inverseTransform=inv_exp_tr, + description='this is a test', + name='coollook', + processSpace='somespace', + transform=exp_tr) + + self.assertEqual(look2.getName(), 'coollook') + self.assertEqual(look2.getProcessSpace(), 'somespace') + self.assertIsInstance(look2.getTransform(), type(exp_tr2)) + self.assertIsInstance(look2.getInverseTransform(), type(inv_exp_tr2)) + self.assertEqual(look2.getDescription(), 'this is a test') + + def test_constructor_with_positional(self): + """ + Test Look constructor without keywords and validate its values. + """ + + exp_tr = OCIO.ExponentTransform() + inv_exp_tr = OCIO.ExponentTransform() + look = OCIO.Look('coollook', + 'somespace', + exp_tr, + inv_exp_tr, + 'this is a test') + + self.assertEqual(look.getName(), 'coollook') + self.assertEqual(look.getProcessSpace(), 'somespace') + self.assertIsInstance(look.getTransform(), type(exp_tr)) + self.assertIsInstance(look.getInverseTransform(), type(inv_exp_tr)) + self.assertEqual(look.getDescription(), 'this is a test') + + def test_constructor_wrong_parameter_type(self): + """ + Test Look constructor with a wrong parameter type. + """ + + for invalid in (None, 1): + with self.assertRaises(TypeError): + look = OCIO.Look(invalid) diff --git a/tests/python/OpenColorIOTestSuite.py b/tests/python/OpenColorIOTestSuite.py index 96fd1600ba..b93ccb9de9 100755 --- a/tests/python/OpenColorIOTestSuite.py +++ b/tests/python/OpenColorIOTestSuite.py @@ -34,11 +34,11 @@ import BuiltinTransformRegistryTest import BuiltinTransformTest import CDLTransformTest +import LookTest #from MainTest import * #from ConstantsTest import * #from ConfigTest import * #from ContextTest import * -#from LookTest import * #from GpuShaderDescTest import * #from Baker import * #from TransformsTest import * @@ -59,12 +59,12 @@ def suite(): suite.addTest(loader.loadTestsFromModule(BuiltinTransformRegistryTest)) suite.addTest(loader.loadTestsFromModule(BuiltinTransformTest)) suite.addTest(loader.loadTestsFromModule(CDLTransformTest)) + suite.addTest(loader.loadTestsFromModule(LookTest)) #suite.addTest(MainTest("test_interface")) #suite.addTest(ConstantsTest("test_interface")) #suite.addTest(ConfigTest("test_interface")) #suite.addTest(ConfigTest("test_is_editable")) #suite.addTest(ContextTest("test_interface")) - #suite.addTest(LookTest("test_interface")) #suite.addTest(RangeTransformTest("test_interface")) #suite.addTest(RangeTransformTest("test_equality")) #suite.addTest(RangeTransformTest("test_validation")) From 75c449a6c856487203510157e7564112dc481db7 Mon Sep 17 00:00:00 2001 From: Michael Dolan Date: Sat, 27 Jun 2020 01:09:27 -0400 Subject: [PATCH 18/33] Add TSC meeting notes for 06-22-2020 (#1041) * Add TSC meeting notes for 06-22-2020 Signed-off-by: Michael Dolan * Fix typo Signed-off-by: Michael Dolan --- docs/tsc/meetings/2020-06-22.md | 86 +++++++++++++++++++++++++++++++++ 1 file changed, 86 insertions(+) create mode 100644 docs/tsc/meetings/2020-06-22.md diff --git a/docs/tsc/meetings/2020-06-22.md b/docs/tsc/meetings/2020-06-22.md new file mode 100644 index 0000000000..52d357713d --- /dev/null +++ b/docs/tsc/meetings/2020-06-22.md @@ -0,0 +1,86 @@ + + + +June 22, 2020 + +Host: Michael Dolan + +Rotating Secretary: Michael Dolan + +Attendees: + * [X] Mark Boorer (_TSC_) - Industrial Light & Magic + * [X] Mei Chu (_TSC_) - Sony Pictures Imageworks + * [ ] Sean Cooper (_TSC ACES TAC Rep_) - DNEG + * [X] Michael Dolan (_TSC Chair_) - Epic Games + * [X] Patrick Hodoul (_TSC_) - Autodesk + * [ ] John Mertic - Academy Software Foundation / Linux Foundation + * [X] Carol Payne (_TSC_) - Netflix + * [ ] Mark Titchener (_TSC_) - Foundry + * [ ] Carl Rand (_TSC_) - Weta Digital + * [X] Doug Walker (_TSC Chief Architect_) - Autodesk + * [X] Kevin Wheatley (_TSC_) - Framestore + * [X] Troy Sobotka + +# **OCIO TSC Meeting Notes** + +* GPU CI investigations: + - Infrastructure is in place for GPU CI on AWS. Credentials are for + organization-wide use so all projects can benefit. + - **TODO**: Michael will work with LF releng and JF Panisset on + implementation starting this week. + +* SIGGRAPH BoF: + - 30 minutes this year and virtual. With summer vacations coming up we + should have a plan in place. + - Doug: We may want to schedule a longer event to go into more detail, + could be after SIGGRAPH. Not sure if people will want to sit through full + week of online meetings. Could do 30 minute overview, and longer + "intro to v2" session after SIGGRAPH. + - Mark: Could use SIGGRAPH time to do presentation, but spin up Zoom + meeting to chat about it afterwords for an hour or two. + - Carol: Emily mentioned possibly doing Open Source Day as a separate thing + from SIGGRAPH. + - Doug: BoFs are separate from SIGGRAPH and free to all. Don't know exact + date yet, but thought it was positioned relative to the original SIGGRAPH + date. + - **TODO**: Double check with Emily whether ASWF Open Source Day will be + part of SIGGRAPH or separate, and if date is known. + - Michael: We had discussed with Emily the idea of creating some OCIO + videos. Perhaps this could intersect? + - Doug: Those videos may have been more for promotional purposes than + education. 5 minute videos. Educational video will need to be longer. + - Kevin: Is the scarce resource our time or that of people joining? People + can watch videos when they want, so the BoF room time could be used for + discussion. Usually the BoF is half presentation and half discussion. + - Michael: If we go that route, we'll need to make sure we communicate + to the community where to find the video ahead of time. + - Kevin: Could do offline presentation a week in advance, which would + result in less schedule conflicts. + - **TODO**: Determine BoF/in-depth presentation plan once more information + on Open Source Day is available. + +* Pull requests: + - Patrick: Some old PRs. Are any blockers? Bernard's review is important, + but there have been open CMake and Python PRs for a while. + - Michael: I can now address feedback on CMake PR, but can't merge until + Sean has CCLA in system. This raises the point that with many initiatives + ramping up and more contributors, getting CCLAs signed will be important. + If you haven't started the process yet, it can take some time, so + recommend starting soon. + - Doug: In EasyCLA instructions, says CLA manager at company should approve + all projects, which simplifies the process for companies already + contributing to another ASWF project. The CLA manager can add a company + email domain so that anyone with a company email address can be approved. + - Mei: For Python unit test PRs, I am responding to PR comments. Working on + completing tests for transforms first. + - Michael: Feel free to open GH issues for unit tests that have not been + completed. Others can then help and we can track the overall initiative. + +* New work on EGL support (#1039): + - Doug: New contributor doing work on EGL. Anyone have experience? + - Patrick: Window-system agnostic graphics APIs. On paper it's a good way + to improve GPU unit tests. + - Doug: JF proposed this originally as way to avoid Nvidia GRID licenses + for GPU tests. + - Patrick: It's mostly for headless machines. WIll require a lot of testing + but huge benefit to project. From b4f32be800d355f8e4788a1003a802d713dc7df2 Mon Sep 17 00:00:00 2001 From: Simran Date: Sat, 27 Jun 2020 15:10:27 +0200 Subject: [PATCH 19/33] Rename andriod-toolchain.cmake to android-toolchain.cmake (#1043) Signed-off-by: Simran Brucherseifer Co-authored-by: Patrick Hodoul --- .../{andriod-toolchain.cmake => android-toolchain.cmake} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename share/cmake/toolchains/{andriod-toolchain.cmake => android-toolchain.cmake} (100%) diff --git a/share/cmake/toolchains/andriod-toolchain.cmake b/share/cmake/toolchains/android-toolchain.cmake similarity index 100% rename from share/cmake/toolchains/andriod-toolchain.cmake rename to share/cmake/toolchains/android-toolchain.cmake From a718428168086e1a9fc923c6a0c64c8ce92cf3b5 Mon Sep 17 00:00:00 2001 From: Simran Date: Sat, 27 Jun 2020 15:56:21 +0200 Subject: [PATCH 20/33] Update links to EasyCLA docs (#1044) Signed-off-by: Simran Brucherseifer Co-authored-by: Patrick Hodoul --- CONTRIBUTING.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 43990dc9d0..bbafa465f9 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -84,12 +84,12 @@ can be merged. * 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](https://github.com/communitybridge/easycla/blob/master/docs/Sign-a-CLA-as-an-Individual-Contributor-to-GitHub.md). + [sign the CLA as an individual contributor](https://docs.linuxfoundation.org/docs/communitybridge/communitybridge-easycla/contributors/sign-a-cla-as-an-individual-contributor-to-github). * If you are writing the code as part of your job, or if there is any possibility that your employers might think they own any intellectual property you create, then you should use the - [Corporate Contributor Licence Agreement](https://github.com/communitybridge/easycla/blob/master/docs/Contribute-to-a-GitHub-Company-Project.md). + [Corporate Contributor Licence Agreement](https://docs.linuxfoundation.org/docs/communitybridge/communitybridge-easycla/contributors/contribute-to-a-github-company-project). The OCIO CLA's are the standard forms used by Linux Foundation projects and [recommended by the ASWF TAC](https://github.com/AcademySoftwareFoundation/tac/blob/master/process/contributing.md#contributor-license-agreement-cla). From 802a8af66f633f13dad1ad9a2c62c7a0a634d3b1 Mon Sep 17 00:00:00 2001 From: Michael Dolan Date: Sun, 28 Jun 2020 01:38:55 -0400 Subject: [PATCH 21/33] Add _ROOT messaging Signed-off-by: Michael Dolan --- CMakeLists.txt | 25 +++++++++++++++++-------- docs/CMakeLists.txt | 2 ++ share/cmake/macros/PackageUtils.cmake | 11 +++++++++++ src/CMakeLists.txt | 4 ++-- 4 files changed, 32 insertions(+), 10 deletions(-) create mode 100644 share/cmake/macros/PackageUtils.cmake diff --git a/CMakeLists.txt b/CMakeLists.txt index f833de8cf5..83cb710a26 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -84,22 +84,31 @@ option(OCIO_WARNING_AS_ERROR "Set build error level for CI testing" OFF) ############################################################################### # GPU configuration +include(PackageUtils) + if(OCIO_BUILD_GPU_TESTS OR OCIO_BUILD_APPS) - set(OCIO_GL_ENABLED ON) - find_package(OpenGL) - if(NOT OpenGL_FOUND) + set(OCIO_GL_ENABLED ON) + + find_package(OpenGL) + if(NOT OpenGL_FOUND) + package_root_message(OpenGL) set(OCIO_GL_ENABLED OFF) - endif() - if(NOT APPLE) + endif() + + if(NOT APPLE) find_package(GLEW) if(NOT GLEW_FOUND) + package_root_message(GLEW) set(OCIO_GL_ENABLED OFF) endif() - endif() + endif() + find_package(GLUT) if(NOT GLUT_FOUND) + package_root_message(GLUT) set(OCIO_GL_ENABLED OFF) - endif() + endif() + endif() ############################################################################### @@ -213,7 +222,7 @@ endif() # don't generally produce global targets. To guarantee all imported targets are # global, this module is included at the project root level. -include(share/cmake/modules/FindExtPackages.cmake) +include(FindExtPackages) ############################################################################### # Progress to other sources diff --git a/docs/CMakeLists.txt b/docs/CMakeLists.txt index 02a21489d4..c3991bf16c 100644 --- a/docs/CMakeLists.txt +++ b/docs/CMakeLists.txt @@ -145,6 +145,8 @@ install(DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/build-html/ ### PDF target ### find_package(LATEX) +package_root_message(LATEX) + if(PDFLATEX_COMPILER) add_custom_target(latex diff --git a/share/cmake/macros/PackageUtils.cmake b/share/cmake/macros/PackageUtils.cmake new file mode 100644 index 0000000000..60b7212b62 --- /dev/null +++ b/share/cmake/macros/PackageUtils.cmake @@ -0,0 +1,11 @@ +# SPDX-License-Identifier: BSD-3-Clause +# Copyright Contributors to the OpenColorIO Project. +# +# General CMake utility macros. +# + +macro(package_root_message package) + if(NOT "${${package}_FOUND}") + message(STATUS "Use \"${package}_ROOT\" to specify an install location") + endif() +endmacro() diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index f78654e02c..45dd12049e 100755 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -2,14 +2,14 @@ # Copyright Contributors to the OpenColorIO Project. # The presence of OpenImageIO allows additional ocio apps to be built. -# These apps may also require the building of openglbuilder from utils +# These apps may also require the building of oglapphelpers from libutils # but because the builder also needs GLEW, we only conditionally build # this lib # OpenImageIO # https://github.com/OpenImageIO/oiio find_package(OpenImageIO 2.1.9 CONFIG) - +package_root_message(OpenImageIO) # The order defines the architecture of the project i.e. layers and dependencies. From 2c6053c710986002ea7912b6ce738e503ba297ee Mon Sep 17 00:00:00 2001 From: Michael Dolan Date: Sun, 28 Jun 2020 01:53:06 -0400 Subject: [PATCH 22/33] Replace tabs with spaces Signed-off-by: Michael Dolan --- CMakeLists.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 83cb710a26..08f32624b6 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -91,21 +91,21 @@ if(OCIO_BUILD_GPU_TESTS OR OCIO_BUILD_APPS) find_package(OpenGL) if(NOT OpenGL_FOUND) - package_root_message(OpenGL) + package_root_message(OpenGL) set(OCIO_GL_ENABLED OFF) endif() if(NOT APPLE) find_package(GLEW) if(NOT GLEW_FOUND) - package_root_message(GLEW) + package_root_message(GLEW) set(OCIO_GL_ENABLED OFF) endif() endif() find_package(GLUT) if(NOT GLUT_FOUND) - package_root_message(GLUT) + package_root_message(GLUT) set(OCIO_GL_ENABLED OFF) endif() From cc66fe4dd88d6340587fd8b066e2b4980734f9bc Mon Sep 17 00:00:00 2001 From: Michael Dolan Date: Sun, 28 Jun 2020 01:55:01 -0400 Subject: [PATCH 23/33] Replace tabs with spaces Signed-off-by: Michael Dolan --- CMakeLists.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 08f32624b6..99ff3d42e8 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -91,14 +91,14 @@ if(OCIO_BUILD_GPU_TESTS OR OCIO_BUILD_APPS) find_package(OpenGL) if(NOT OpenGL_FOUND) - package_root_message(OpenGL) + package_root_message(OpenGL) set(OCIO_GL_ENABLED OFF) endif() if(NOT APPLE) find_package(GLEW) if(NOT GLEW_FOUND) - package_root_message(GLEW) + package_root_message(GLEW) set(OCIO_GL_ENABLED OFF) endif() endif() From 00e430c12ea37a220b04aaa9ce2b8ee3b7cc6223 Mon Sep 17 00:00:00 2001 From: Michael Dolan Date: Tue, 30 Jun 2020 15:52:11 -0400 Subject: [PATCH 24/33] Remove unnecessary oiiohelpers dependencies Signed-off-by: Michael Dolan --- src/libutils/oiiohelpers/CMakeLists.txt | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/libutils/oiiohelpers/CMakeLists.txt b/src/libutils/oiiohelpers/CMakeLists.txt index d34334b2ad..0fcadf1ccf 100644 --- a/src/libutils/oiiohelpers/CMakeLists.txt +++ b/src/libutils/oiiohelpers/CMakeLists.txt @@ -1,11 +1,6 @@ # SPDX-License-Identifier: BSD-3-Clause # Copyright Contributors to the OpenColorIO Project. -find_package(OpenGL REQUIRED) -if(NOT APPLE) - find_package(GLEW REQUIRED) -endif() - set(SOURCES oiiohelpers.cpp ) From f8504e86806a47f2490071b5a9c02408d7428bfe Mon Sep 17 00:00:00 2001 From: Bernard Lefebvre <37628108+BernardLefebvre@users.noreply.github.com> Date: Mon, 29 Jun 2020 08:49:08 -0400 Subject: [PATCH 25/33] Adsk Contrib - Add ViewingRules, DisplayViewTransform, and ViewingPipeline (#1038) * Add ViewingRules, DisplayViewTransform, and ViewingPipeline Signed-off-by: Bernard Lefebvre * Add version check to config sanity check. Signed-off-by: Bernard Lefebvre * Adjust comments Signed-off-by: Bernard Lefebvre * Update ViewingPipeline.cpp Fix indentation Signed-off-by: Bernard Lefebvre Co-authored-by: Patrick Hodoul --- include/OpenColorIO/OpenColorIO.h | 322 ++++- include/OpenColorIO/OpenColorTransforms.h | 101 +- include/OpenColorIO/OpenColorTypes.h | 39 +- src/OpenColorIO/CMakeLists.txt | 3 +- src/OpenColorIO/Categories.h | 102 -- src/OpenColorIO/ColorSpace.cpp | 80 +- src/OpenColorIO/Config.cpp | 1204 +++++++++++++---- src/OpenColorIO/Context.cpp | 2 +- src/OpenColorIO/CustomKeys.h | 80 ++ src/OpenColorIO/Display.cpp | 103 +- src/OpenColorIO/Display.h | 60 +- src/OpenColorIO/FileRules.cpp | 195 +-- src/OpenColorIO/LookParse.cpp | 2 +- src/OpenColorIO/OCIOYaml.cpp | 564 +++++++- src/OpenColorIO/OpBuilders.h | 17 +- src/OpenColorIO/ParseUtils.cpp | 13 +- src/OpenColorIO/ParseUtils.h | 5 +- src/OpenColorIO/Processor.cpp | 9 +- src/OpenColorIO/TokensManager.h | 102 ++ src/OpenColorIO/Transform.cpp | 16 +- src/OpenColorIO/ViewTransform.cpp | 26 +- src/OpenColorIO/ViewingRules.cpp | 482 +++++++ src/OpenColorIO/ViewingRules.h | 56 + .../fileformats/FormatMetadata.cpp | 6 +- .../ops/fixedfunction/FixedFunctionOpData.cpp | 4 +- src/OpenColorIO/ops/matrix/MatrixOpData.cpp | 4 +- .../transforms/ColorSpaceTransform.cpp | 55 +- .../transforms/DisplayTransform.cpp | 488 ------- .../transforms/DisplayViewTransform.cpp | 411 ++++++ src/OpenColorIO/transforms/LookTransform.cpp | 186 ++- src/apps/ocioconvert/main.cpp | 4 +- src/apps/ociodisplay/CMakeLists.txt | 1 + src/apps/ociodisplay/main.cpp | 29 +- src/bindings/python/CMakeLists.txt | 3 +- src/bindings/python/PyColorSpace.cpp | 7 +- src/bindings/python/PyColorSpaceTransform.cpp | 29 +- src/bindings/python/PyConfig.cpp | 160 ++- src/bindings/python/PyDisplayTransform.cpp | 76 -- .../python/PyDisplayViewTransform.cpp | 53 + src/bindings/python/PyLookTransform.cpp | 22 +- src/bindings/python/PyOpenColorIO.cpp | 1 + src/bindings/python/PyOpenColorIO.h | 5 +- src/bindings/python/PyTransform.cpp | 2 +- src/bindings/python/PyTransform.h | 2 +- src/bindings/python/PyViewingRules.cpp | 83 ++ src/libutils/apphelpers/CMakeLists.txt | 2 + .../apphelpers/DisplayViewHelpers.cpp | 35 +- src/libutils/apphelpers/DisplayViewHelpers.h | 1 + src/libutils/apphelpers/MixingHelpers.cpp | 7 +- src/libutils/apphelpers/ViewingPipeline.cpp | 372 +++++ src/libutils/apphelpers/ViewingPipeline.h | 106 ++ tests/apphelpers/CMakeLists.txt | 1 + tests/apphelpers/DisplayViewHelpers_tests.cpp | 51 +- tests/apphelpers/MixingHelpers_tests.cpp | 30 +- tests/apphelpers/ViewingPipeline_tests.cpp | 846 ++++++++++++ tests/cpu/CMakeLists.txt | 7 +- tests/cpu/ColorSpace_tests.cpp | 6 +- tests/cpu/Config_tests.cpp | 178 ++- tests/cpu/Display_tests.cpp | 233 ++++ tests/cpu/FileRules_tests.cpp | 19 +- tests/cpu/ParseUtils_tests.cpp | 10 +- tests/cpu/ViewingRules_tests.cpp | 509 +++++++ .../transforms/ColorSpaceTransform_tests.cpp | 103 +- .../cpu/transforms/DisplayTransform_tests.cpp | 643 --------- .../transforms/DisplayViewTransform_tests.cpp | 1020 ++++++++++++++ tests/cpu/transforms/LookTransform_tests.cpp | 445 ++++++ tests/python/ColorSpaceTest.py | 18 +- tests/python/ColorSpaceTransformTest.py | 137 ++ tests/python/ConfigTest.py | 732 +++++++--- tests/python/DisplayViewTransformTest.py | 222 +++ tests/python/OpenColorIOTestSuite.py | 11 +- tests/python/TransformsTest.py | 14 +- tests/python/UnitTestUtils.py | 18 +- tests/python/ViewingRulesTest.py | 242 ++++ 74 files changed, 8749 insertions(+), 2483 deletions(-) delete mode 100644 src/OpenColorIO/Categories.h create mode 100644 src/OpenColorIO/CustomKeys.h create mode 100644 src/OpenColorIO/TokensManager.h create mode 100644 src/OpenColorIO/ViewingRules.cpp create mode 100644 src/OpenColorIO/ViewingRules.h delete mode 100755 src/OpenColorIO/transforms/DisplayTransform.cpp create mode 100644 src/OpenColorIO/transforms/DisplayViewTransform.cpp delete mode 100644 src/bindings/python/PyDisplayTransform.cpp create mode 100644 src/bindings/python/PyDisplayViewTransform.cpp create mode 100644 src/bindings/python/PyViewingRules.cpp create mode 100644 src/libutils/apphelpers/ViewingPipeline.cpp create mode 100644 src/libutils/apphelpers/ViewingPipeline.h create mode 100644 tests/apphelpers/ViewingPipeline_tests.cpp create mode 100644 tests/cpu/Display_tests.cpp create mode 100644 tests/cpu/ViewingRules_tests.cpp delete mode 100644 tests/cpu/transforms/DisplayTransform_tests.cpp create mode 100644 tests/cpu/transforms/DisplayViewTransform_tests.cpp create mode 100644 tests/cpu/transforms/LookTransform_tests.cpp create mode 100644 tests/python/ColorSpaceTransformTest.py create mode 100644 tests/python/DisplayViewTransformTest.py create mode 100644 tests/python/ViewingRulesTest.py diff --git a/include/OpenColorIO/OpenColorIO.h b/include/OpenColorIO/OpenColorIO.h index 139ad6655e..5812f95b50 100644 --- a/include/OpenColorIO/OpenColorIO.h +++ b/include/OpenColorIO/OpenColorIO.h @@ -166,7 +166,7 @@ extern OCIOEXPORT void SetEnvVariable(const char * name, const char * value); // The color configuration (:cpp:class:`Config`) is the main object for // interacting with this library. It encapsulates all of the information // necessary to use customized :cpp:class:`ColorSpaceTransform` and -// :cpp:class:`DisplayTransform` operations. +// :cpp:class:`DisplayViewTransform` operations. // // See the :ref:`user-guide` for more information on // selecting, creating, and working with custom color configurations. @@ -494,41 +494,90 @@ class OCIOEXPORT Config // Where +/- prefixes are optionally allowed to denote forward/inverse // look specification. (And forward is assumed in the absence of either) + //!cpp:function:: Add shared view (or replace existing one with same name). + // Shared views are defined at config level and can be referenced by several + // displays. Either provide a view transform and a display color space or + // just a color space (and a null view transform). Looks, rule and description + // are optional, they can be null or empty. + // + // Shared views using a view transform may use the token + // for the color space (see :c:var:`OCIO_VIEW_USE_DISPLAY_NAME`). In that + // case, when the view is referenced in a display, the display color space + // that is used will be the one matching the display name. In other words, + // the view will be customized based on the display it is used in. + // :cpp:func:`Config::sanityCheck` will throw if the config does not contain + // the matching display color space. + // + // Will throw if view or colorSpaceName are null or empty. + void addSharedView(const char * view, const char * viewTransformName, + const char * colorSpaceName, const char * looks, + const char * ruleName, const char * description); + //!cpp:function:: Remove a shared view. Will throw if the view does not exist. + void removeSharedView(const char * view); + //!cpp:function:: const char * getDefaultDisplay() const; //!cpp:function:: int getNumDisplays() const; - //!cpp:function:: + //!cpp:function:: Will return "" if the index is invalid. const char * getDisplay(int index) const; //!cpp:function:: const char * getDefaultView(const char * display) const; - //!cpp:function:: + //!cpp:function:: Return the number of views attached to the display including the number of + // shared views if any. Return 0 if display does not exist. int getNumViews(const char * display) const; //!cpp:function:: const char * getView(const char * display, int index) const; - //!cpp:function:: Returns the view_transform attribute of the (display, view) pair. + //!cpp:function:: If the config has ViewingRules, get the number of active Views for this + // colorspace. (If there are no rules, it returns all of them.) + int getNumViews(const char * display, const char * colorspaceName) const; + //!cpp:function:: + const char * getView(const char * display, const char * colorspaceName, int index) const; + + //!cpp:function:: Returns the view_transform attribute of the (display, view) pair. View can + // be a shared view of the display. If display is null or empty, config shared views are used. const char * getDisplayViewTransformName(const char * display, const char * view) const; //!cpp:function:: Returns the colorspace attribute of the (display, view) pair. // (Note that this may be either a color space or a display color space.) - const char * getDisplayColorSpaceName(const char * display, const char * view) const; + const char * getDisplayViewColorSpaceName(const char * display, const char * view) const; //!cpp:function:: Returns the looks attribute of a (display, view) pair. - const char * getDisplayLooks(const char * display, const char * view) const; + const char * getDisplayViewLooks(const char * display, const char * view) const; + //!cpp:function:: Returns the rule attribute of a (display, view) pair. + const char * getDisplayViewRule(const char * display, const char * view) const noexcept; + //!cpp:function:: Returns the description attribute of a (display, view) pair. + const char * getDisplayViewDescription(const char * display, const char * view) const noexcept; //!cpp:function:: For the (display, view) pair, specify which color space and look to use. // If a look is not desired, then just pass a null or empty string. - void addDisplay(const char * display, const char * view, - const char * colorSpaceName, const char * looks); - - //!cpp:function:: For the (display, view) pair, specify a viewTransform + displayColorSpace - // to use. (Looks work the same as above.) - void addDisplay(const char * display, const char * view, const char * viewTransform, - const char * displayColorSpaceName, const char * looks); + void addDisplayView(const char * display, const char * view, + const char * colorSpaceName, const char * looks); + + //!cpp:function:: For the (display, view) pair, specify the color space or alternatively + // specify the view transform and display color space. The looks, viewing rule, and + // description are optional. Pass a null or empty string for any optional arguments. + // If the view already exists, it is replaced. + // + // Will throw if: + // * Display, view or colorSpace are null or empty. + // * Display already has a shared view with the same name. + void addDisplayView(const char * display, const char * view, const char * viewTransformName, + const char * colorSpaceName, const char * looks, + const char * ruleName, const char * description); + + //!cpp:function:: Add a (reference to a) shared view to a display. The shared view must be + // part of the config. See :cpp:func:`Config::addSharedView`. + // This will throw if: + // * Display or view are null or empty. + // * Display already has a view (shared or not) with the same name. + void addDisplaySharedView(const char * display, const char * sharedView); //!cpp:function:: Remove the view and the display if no more views. It does not remove - // the associated color space. - void removeDisplay(const char * display, const char * view); + // the associated color space. If the view name is a shared view, it only removes the + // reference to the view from the display but the shared view, remains in the config. + // Will throw if the view does not exist. + void removeDisplayView(const char * display, const char * view); //!cpp:function:: void clearDisplays(); @@ -557,6 +606,35 @@ class OCIOEXPORT Config //!cpp:function:: const char * getActiveViews() const; + //!cpp:function:: Get all displays in the config, ignoring the active_displays list. + int getNumDisplaysAll() const; + //!cpp:function:: + const char * getDisplayAll(int index) const; + + //!cpp:function:: Get either the shared or display-defined views for a display. The + // active_views list is ignored. Passing a null or empty display (with type=VIEW_SHARED) + // returns the contents of the shared_views section of the config. Return 0 if display + // does not exist. + int getNumViews(ViewType type, const char * display) const; + //!cpp:function:: + const char * getView(ViewType type, const char * display, int index) const; + + /////////////////////////////////////////////////////////////////////////// + //!rst:: .. _cfgviewingrules_section: + // + // Viewing Rules + // ^^^^^^^^^^^^^ + // + // See :cpp:class:`ViewingRules`. + + //!cpp:function:: Get read-only version of the viewing rules. + ConstViewingRulesRcPtr getViewingRules() const noexcept; + + //!cpp:function:: Set viewing rules. + // .. note:: + // The argument is cloned. + void setViewingRules(ConstViewingRulesRcPtr viewingRules); + /////////////////////////////////////////////////////////////////////////// //!rst:: .. _cfgluma_section: // @@ -680,31 +758,31 @@ class OCIOEXPORT Config //!cpp:function:: ConstProcessorRcPtr getProcessor(const ConstContextRcPtr & context, - const ConstColorSpaceRcPtr & srcColorSpace, - const ConstColorSpaceRcPtr & dstColorSpace) const; + const ConstColorSpaceRcPtr & srcColorSpace, + const ConstColorSpaceRcPtr & dstColorSpace) const; //!cpp:function:: ConstProcessorRcPtr getProcessor(const ConstColorSpaceRcPtr & srcColorSpace, - const ConstColorSpaceRcPtr & dstColorSpace) const; + const ConstColorSpaceRcPtr & dstColorSpace) const; //!cpp:function:: // .. note:: // Names can be colorspace name, role name, or a combination of both. - ConstProcessorRcPtr getProcessor(const char * srcName, - const char * dstName) const; + ConstProcessorRcPtr getProcessor(const char * srcColorSpaceName, + const char * dstColorSpaceName) const; //!cpp:function:: ConstProcessorRcPtr getProcessor(const ConstContextRcPtr & context, - const char * srcName, - const char * dstName) const; + const char * srcColorSpaceName, + const char * dstColorSpaceName) const; - //!rst:: Get the processor to apply a DisplayTransform for a display and view. Refer to the + //!rst:: Get the processor to apply a DisplayViewTransform for a display and view. Refer to the // Display/View Registration section above for more info on the display and view arguments. //!cpp:function:: - ConstProcessorRcPtr getProcessor(const char * inputColorSpaceName, + ConstProcessorRcPtr getProcessor(const char * srcColorSpaceName, const char * display, const char * view) const; //!cpp:function:: ConstProcessorRcPtr getProcessor(const ConstContextRcPtr & context, - const char * inputColorSpaceName, + const char * srcColorSpaceName, const char * display, const char * view) const; //!rst:: Get the processor for the specified transform. @@ -713,14 +791,14 @@ class OCIOEXPORT Config // functionality (such as to apply an individual LUT file). //!cpp:function:: - ConstProcessorRcPtr getProcessor(const ConstTransformRcPtr& transform) const; + ConstProcessorRcPtr getProcessor(const ConstTransformRcPtr & transform) const; //!cpp:function:: - ConstProcessorRcPtr getProcessor(const ConstTransformRcPtr& transform, - TransformDirection direction) const; + ConstProcessorRcPtr getProcessor(const ConstTransformRcPtr & transform, + TransformDirection direction) const; //!cpp:function:: ConstProcessorRcPtr getProcessor(const ConstContextRcPtr & context, - const ConstTransformRcPtr& transform, - TransformDirection direction) const; + const ConstTransformRcPtr & transform, + TransformDirection direction) const; //!rst: Get a processor to convert between color spaces in two separate configs. @@ -728,40 +806,40 @@ class OCIOEXPORT Config // is scene-referred) or the role cie_xyz_d65_interchange (when srcName is display-referred) // defined. An exception is thrown if that is not the case. static ConstProcessorRcPtr GetProcessor(const ConstConfigRcPtr & srcConfig, - const char * srcName, + const char * srcColorSpaceName, const ConstConfigRcPtr & dstConfig, - const char * dstName); + const char * dstColorSpaceName); //!cpp:function:: static ConstProcessorRcPtr GetProcessor(const ConstContextRcPtr & srcContext, const ConstConfigRcPtr & srcConfig, - const char * srcName, + const char * srcColorSpaceName, const ConstContextRcPtr & dstContext, const ConstConfigRcPtr & dstConfig, - const char * dstName); + const char * dstColorSpaceName); //!cpp:function:: The srcInterchangeName and dstInterchangeName must refer to a pair of // color spaces in the two configs that are the same. A role name may also be used. static ConstProcessorRcPtr GetProcessor(const ConstConfigRcPtr & srcConfig, - const char * srcName, + const char * srcColorSpaceName, const char * srcInterchangeName, const ConstConfigRcPtr & dstConfig, - const char * dstName, + const char * dstColorSpaceName, const char * dstInterchangeName); //!cpp:function:: static ConstProcessorRcPtr GetProcessor(const ConstContextRcPtr & srcContext, const ConstConfigRcPtr & srcConfig, - const char * srcName, + const char * srcColorSpaceName, const char * srcInterchangeName, const ConstContextRcPtr & dstContext, const ConstConfigRcPtr & dstConfig, - const char * dstName, + const char * dstColorSpaceName, const char * dstInterchangeName); //!cpp:function:: Config(const Config &) = delete; //!cpp:function:: Config& operator= (const Config &) = delete; - //!cpp:function:: + //!cpp:function:: Do not use (needed only for pybind11). ~Config(); private: @@ -777,6 +855,8 @@ class OCIOEXPORT Config extern OCIOEXPORT std::ostream& operator<< (std::ostream&, const Config&); + + /////////////////////////////////////////////////////////////////////////// //!rst:: .. _filerules_section: // @@ -881,7 +961,7 @@ class FileRules size_t getNumCustomKeys(size_t ruleIndex) const; //!cpp:function:: Get name of key. const char * getCustomKeyName(size_t ruleIndex, size_t key) const; - //!cpp:function:: Get name of value. + //!cpp:function:: Get value for the key. const char * getCustomKeyValue(size_t ruleIndex, size_t key) const; //!cpp:function:: Adds a key/value or replace value if key exists. Setting a NULL or an // empty value will erase the key. @@ -922,7 +1002,7 @@ class FileRules FileRules(const FileRules &) = delete; //!cpp:function:: FileRules & operator= (const FileRules &) = delete; - //!cpp:function:: + //!cpp:function:: Do not use (needed only for pybind11). virtual ~FileRules(); private: @@ -938,6 +1018,121 @@ class FileRules const Impl * getImpl() const { return m_impl; } }; +extern OCIOEXPORT std::ostream & operator<< (std::ostream &, const FileRules &); + + + + +/////////////////////////////////////////////////////////////////////////// +//!rst:: .. _viewingrules_section: +// +// ViewingRules +// ************ +// Viewing Rules allow config authors to filter the list of views an application should offer +// based on the color space of an image. For example, a config may define a large number of +// views but not all of them may be appropriate for use with all color spaces. E.g., some views +// may be intended for use with scene-linear color space encodings and others with video color +// space encodings. +// +// Each rule has a name key for applications to refer to the rule. Name values must be unique +// (using case insensitive comparison). Viewing Rules may also have the following keys: +// +// * colorspaces: Either a single colorspace name or a list of names. +// +// * encodings: One or more strings to be found in the colorspace's encoding attribute. +// Either this attribute or colorspaces must be present, but not both. +// +// * custom : Allows arbitrary key / value string pairs, similar to FileRules. +// +// Getters and setters are using the rule position, they will throw if the position is not +// valid. +// + +//!cpp:class:: +class ViewingRules +{ +public: + //!cpp:function:: Creates ViewingRules for a Config. + static ViewingRulesRcPtr Create(); + + //!cpp:function:: The method clones the content decoupling the two instances. + ViewingRulesRcPtr createEditableCopy() const; + + //!cpp:function:: + size_t getNumEntries() const noexcept; + + //!cpp:function:: Get the index from the rule name. Will throw if there is no rule named + // ruleName. + size_t getIndexForRule(const char * ruleName) const; + + //!cpp:function:: Get name of the rule. Will throw if ruleIndex is invalid. + const char * getName(size_t ruleIndex) const; + + //!cpp:function:: Get number of colorspaces. Will throw if ruleIndex is invalid. + size_t getNumColorSpaces(size_t ruleIndex) const; + //!cpp:function:: Get colorspace name. Will throw if ruleIndex or colorSpaceIndex is invalid. + const char * getColorSpace(size_t ruleIndex, size_t colorSpaceIndex) const; + //!cpp:function:: Add colorspace name. Will throw if: + // * RuleIndex is invalid. + // * :cpp:func:`ViewingRules::getNumEncodings` is not 0. + void addColorSpace(size_t ruleIndex, const char * colorSpace); + //!cpp:function:: Remove colorspace. Will throw if ruleIndex or colorSpaceIndex is invalid. + void removeColorSpace(size_t ruleIndex, size_t colorSpaceIndex); + + //!cpp:function:: Get number of encodings. Will throw if ruleIndex is invalid. + size_t getNumEncodings(size_t ruleIndex) const; + //!cpp:function:: Get encoding name. Will throw if ruleIndex or encodingIndex is invalid. + const char * getEncoding(size_t ruleIndex, size_t encodingIndex) const; + //!cpp:function:: Add encoding name. Will throw if: + // * RuleIndex is invalid. + // * :cpp:func:`ViewingRules::getNumColorSpaces` is not 0. + void addEncoding(size_t ruleIndex, const char * encoding); + //!cpp:function:: Remove encoding. Will throw if ruleIndex or encodingIndex is invalid. + void removeEncoding(size_t ruleIndex, size_t encodingIndex); + + //!cpp:function:: Get number of key/value pairs. Will throw if ruleIndex is invalid. + size_t getNumCustomKeys(size_t ruleIndex) const; + //!cpp:function:: Get name of key. Will throw if ruleIndex or keyIndex is invalid. + const char * getCustomKeyName(size_t ruleIndex, size_t keyIndex) const; + //!cpp:function:: Get value for the key. Will throw if ruleIndex or keyIndex is invalid. + const char * getCustomKeyValue(size_t ruleIndex, size_t keyIndex) const; + //!cpp:function:: Adds a key/value or replace value if key exists. Setting a NULL or an + // empty value will erase the key. Will throw if ruleIndex is invalid. + void setCustomKey(size_t ruleIndex, const char * key, const char * value); + + //!cpp:function:: Insert a rule at a given ruleIndex. Rule currently at ruleIndex will be + // pushed to index: ruleIndex + 1. If ruleIndex is :cpp:func:`ViewingRules::getNumEntries` + // new rule will be added at the end. Will throw if: + // * RuleIndex is invalid (must be less than or equal to + // cpp:func:`ViewingRules::getNumEntries`). + // * RuleName already exists. + void insertRule(size_t ruleIndex, const char * ruleName); + + //!cpp:function:: Remove a rule. Throws if ruleIndex is not valid. + void removeRule(size_t ruleIndex); + + ViewingRules(const ViewingRules &) = delete; + ViewingRules & operator= (const ViewingRules &) = delete; + //!cpp:function:: Do not use (needed only for pybind11). + virtual ~ViewingRules(); + +private: + ViewingRules(); + + static void deleter(ViewingRules* c); + + friend class Config; + + class Impl; + Impl * m_impl; + Impl * getImpl() { return m_impl; } + const Impl * getImpl() const { return m_impl; } +}; + +extern OCIOEXPORT std::ostream & operator<< (std::ostream &, const ViewingRules &); + + + /////////////////////////////////////////////////////////////////////////// //!rst:: .. _colorspace_section: @@ -1003,7 +1198,7 @@ class OCIOEXPORT ColorSpace void setBitDepth(BitDepth bitDepth); //!cpp:function:: A display color space will use the display-referred reference space. - ReferenceSpaceType getReferenceSpaceType() const; + ReferenceSpaceType getReferenceSpaceType() const noexcept; /////////////////////////////////////////////////////////////////////////// //!rst:: @@ -1037,23 +1232,45 @@ class OCIOEXPORT ColorSpace //!cpp:function:: Clear all the categories. void clearCategories(); + /////////////////////////////////////////////////////////////////////////// + //!rst:: + // Encodings + // ^^^^^^^^^ + // It is sometimes useful for applications to group color spaces based on how the color values + // are digitally encoded. For example, images in scene-linear, logarithmic, video, and data + // color spaces could have different default views. Unlike the Family and EqualityGroup + // attributes of a color space, the list of Encodings is predefined in the OCIO documentation + // (rather than being config-specific) to make it easier for applications to utilize. + // + // Here is an example config entry that could appear under a ColorSpace: + // encoding: scene-linear + // + // Encoding strings are not case-sensitive. Although users may add their own encodings, the + // strings will typically come from a fixed set listed in the documentation (similar to roles). + + //!cpp:function:: + const char * getEncoding() const noexcept; + //!cpp:function:: + void setEncoding(const char * encoding); + + /////////////////////////////////////////////////////////////////////////// //!rst:: // Data // ^^^^ - // ColorSpaces that are data are treated a bit special. Basically, any - // colorspace transforms you try to apply to them are ignored. (Think - // of applying a gamut mapping transform to an ID pass). Also, the - // :cpp:class:`DisplayTransform` process obeys special 'data min' and - // 'data max' args. + // ColorSpaces that are data are treated a bit special. Basically, any colorspace transforms + // you try to apply to them are ignored. (Think of applying a gamut mapping transform to an + // ID pass). However, the setDataBypass method on ColorSpaceTransform and DisplayViewTransform + // allow applications to process data when necessary. (Think of sending mattes to an HDR + // monitor.) // // This is traditionally used for pixel data that represents non-color // pixel data, such as normals, point positions, ID information, etc. //!cpp:function:: - bool isData() const; + bool isData() const noexcept; //!cpp:function:: - void setIsData(bool isData); + void setIsData(bool isData) noexcept; /////////////////////////////////////////////////////////////////////////// //!rst:: @@ -1064,9 +1281,9 @@ class OCIOEXPORT ColorSpace // allocation to maximize bit efficiency. //!cpp:function:: - Allocation getAllocation() const; + Allocation getAllocation() const noexcept; //!cpp:function:: - void setAllocation(Allocation allocation); + void setAllocation(Allocation allocation) noexcept; //!rst:: // Specify the optional variable values to configure the allocation. @@ -1107,7 +1324,7 @@ class OCIOEXPORT ColorSpace ColorSpace(const ColorSpace &) = delete; //!cpp:function:: ColorSpace& operator= (const ColorSpace &) = delete; - //!cpp:function:: + //!cpp:function:: Do not use (needed only for pybind11). ~ColorSpace(); private: @@ -1294,6 +1511,7 @@ class OCIOEXPORT Look extern OCIOEXPORT std::ostream& operator<< (std::ostream&, const Look&); + /////////////////////////////////////////////////////////////////////////// //!rst:: .. _view_transform_section: // diff --git a/include/OpenColorIO/OpenColorTransforms.h b/include/OpenColorIO/OpenColorTransforms.h index 09112e5750..39db89a67d 100644 --- a/include/OpenColorIO/OpenColorTransforms.h +++ b/include/OpenColorIO/OpenColorTransforms.h @@ -194,7 +194,7 @@ class OCIOEXPORT BuiltinTransform : public Transform //!cpp:function:: virtual const char * getDescription() const noexcept = 0; - //!cpp:function:: To never use i.e. only needed for the Python bindings with pybind11. + //!cpp:function:: Do not use (needed only for pybind11). virtual ~BuiltinTransform() = default; protected: @@ -351,9 +351,14 @@ class OCIOEXPORT ColorSpaceTransform : public Transform //!cpp:function:: void setDst(const char * dst); + //!cpp:function:: Data color spaces do not get processed when true (which is the default). + bool getDataBypass() const noexcept; //!cpp:function:: - ColorSpaceTransform & operator=(const ColorSpaceTransform &) = delete; + void setDataBypass(bool enabled) noexcept; + //!cpp:function:: + ColorSpaceTransform & operator=(const ColorSpaceTransform &) = delete; + //!cpp:function:: Do not use (needed only for pybind11). virtual ~ColorSpaceTransform(); private: @@ -375,11 +380,11 @@ extern OCIOEXPORT std::ostream & operator<<(std::ostream &, const ColorSpaceTran //!rst:: ////////////////////////////////////////////////////////////////// //!cpp:class:: -class OCIOEXPORT DisplayTransform : public Transform +class OCIOEXPORT DisplayViewTransform : public Transform { public: //!cpp:function:: - static DisplayTransformRcPtr Create(); + static DisplayViewTransformRcPtr Create(); //!cpp:function:: TransformRcPtr createEditableCopy() const override; @@ -393,77 +398,39 @@ class OCIOEXPORT DisplayTransform : public Transform void validate() const override; //!cpp:function:: - const char * getInputColorSpaceName() const; - //!cpp:function:: Step 0. Specify the incoming color space. - void setInputColorSpaceName(const char * name); - - //!cpp:function:: - ConstTransformRcPtr getLinearCC() const; - //!cpp:function:: Step 1: Apply a Color Correction, in ROLE_SCENE_LINEAR. - void setLinearCC(const ConstTransformRcPtr & cc); - - //!cpp:function:: - ConstTransformRcPtr getColorTimingCC() const; - //!cpp:function:: Step 2: Apply a color correction, in ROLE_COLOR_TIMING. - void setColorTimingCC(const ConstTransformRcPtr & cc); - - //!cpp:function:: - ConstTransformRcPtr getChannelView() const; - //!cpp:function:: Step 3: Apply the Channel Viewing Swizzle (mtx). - void setChannelView(const ConstTransformRcPtr & transform); + const char * getSrc() const; + //!cpp:function:: Specify the incoming color space. + void setSrc(const char * name); //!cpp:function:: const char * getDisplay() const; - //!cpp:function:: Step 4: Apply the output display transform - // This is controlled by the specification of (display, view) + //!cpp:function:: Specify which display to use. void setDisplay(const char * display); //!cpp:function:: const char * getView() const; - //!cpp:function:: Specify which view transform to use + //!cpp:function:: Specify which view transform to use. void setView(const char * view); //!cpp:function:: - ConstTransformRcPtr getDisplayCC() const; - //!cpp:function:: Step 5: Apply a post display transform color correction - void setDisplayCC(const ConstTransformRcPtr & cc); - - + bool getLooksBypass() const; + //!cpp:function:: Looks will be bypassed when true (the default is false). + void setLooksBypass(bool bypass); //!cpp:function:: - const char * getLooksOverride() const; - //!cpp:function:: A user can optionally override the looks that are, - // by default, used with the expected display / view combination. - // A common use case for this functionality is in an image viewing - // app, where per-shot looks are supported. If for some reason - // a per-shot look is not defined for the current Context, the - // Config::getProcessor fcn will not succeed by default. Thus, - // with this mechanism the viewing app could override to looks = "", - // and this will allow image display to continue (though hopefully) - // the interface would reflect this fallback option.) - // - // Looks is a potentially comma (or colon) delimited list of lookNames, - // Where +/- prefixes are optionally allowed to denote forward/inverse - // look specification. (And forward is assumed in the absence of either) - void setLooksOverride(const char * looks); + bool getDataBypass() const noexcept; + //!cpp:function:: Data color spaces do not get processed when true (which is the default). + void setDataBypass(bool bypass) noexcept; - //!cpp:function:: - bool getLooksOverrideEnabled() const; - //!cpp:function:: Specify whether the lookOverride should be used, - // or not. This is a separate flag, as it's often useful to override - // "looks" to an empty string. - void setLooksOverrideEnabled(bool enabled); - - //!cpp:function:: - DisplayTransform & operator=(const DisplayTransform &); - //!cpp:function:: - virtual ~DisplayTransform(); + //!cpp:function:: Do not use (needed only for pybind11). + virtual ~DisplayViewTransform(); private: - DisplayTransform(); - DisplayTransform(const DisplayTransform &); + DisplayViewTransform(); + DisplayViewTransform(const DisplayViewTransform &) = delete; + DisplayViewTransform & operator=(const DisplayViewTransform &) = delete; - static void deleter(DisplayTransform * t); + static void deleter(DisplayViewTransform * t); class Impl; Impl * m_impl; @@ -472,7 +439,7 @@ class OCIOEXPORT DisplayTransform : public Transform }; //!cpp:function:: -extern OCIOEXPORT std::ostream & operator<<(std::ostream &, const DisplayTransform &); +extern OCIOEXPORT std::ostream & operator<<(std::ostream &, const DisplayViewTransform &); //!rst:: ////////////////////////////////////////////////////////////////// @@ -1115,9 +1082,21 @@ class OCIOEXPORT LookTransform : public Transform // look specification. (And forward is assumed in the absence of either) void setLooks(const char * looks); + bool getSkipColorSpaceConversion() const; //!cpp:function:: - LookTransform & operator=(const LookTransform &) = delete; + void setSkipColorSpaceConversion(bool skip); + + //!cpp:function:: Return the name of the color space after applying looks in the forward + // direction but without converting to the destination color space. This is equivalent + // to the process space of the last look in the look sequence (and takes into account that + // a look fall-back may be used). + static const char * GetLooksResultColorSpace(const ConstConfigRcPtr & config, + const ConstContextRcPtr & context, + const char * looks); + //!cpp:function:: + LookTransform & operator=(const LookTransform &) = delete; + //!cpp:function:: Do not use (needed only for pybind11). virtual ~LookTransform(); private: diff --git a/include/OpenColorIO/OpenColorTypes.h b/include/OpenColorIO/OpenColorTypes.h index 97aa40e07f..318ddb1ffd 100644 --- a/include/OpenColorIO/OpenColorTypes.h +++ b/include/OpenColorIO/OpenColorTypes.h @@ -41,6 +41,12 @@ typedef OCIO_SHARED_PTR ConstFileRulesRcPtr; //!cpp:type:: typedef OCIO_SHARED_PTR FileRulesRcPtr; +class OCIOEXPORT ViewingRules; +//!cpp:type:: +typedef OCIO_SHARED_PTR ConstViewingRulesRcPtr; +//!cpp:type:: +typedef OCIO_SHARED_PTR ViewingRulesRcPtr; + class OCIOEXPORT ColorSpace; //!cpp:type:: typedef OCIO_SHARED_PTR ConstColorSpaceRcPtr; @@ -162,11 +168,11 @@ typedef OCIO_SHARED_PTR ConstColorSpaceTransformRcPtr //!cpp:type:: typedef OCIO_SHARED_PTR ColorSpaceTransformRcPtr; -class OCIOEXPORT DisplayTransform; +class OCIOEXPORT DisplayViewTransform; //!cpp:type:: -typedef OCIO_SHARED_PTR ConstDisplayTransformRcPtr; +typedef OCIO_SHARED_PTR ConstDisplayViewTransformRcPtr; //!cpp:type:: -typedef OCIO_SHARED_PTR DisplayTransformRcPtr; +typedef OCIO_SHARED_PTR DisplayViewTransformRcPtr; class OCIOEXPORT DynamicProperty; //!cpp:type:: @@ -310,6 +316,13 @@ enum ColorSpaceVisibility COLORSPACE_ALL }; +//!cpp:type:: +enum ViewType +{ + VIEW_SHARED = 0, + VIEW_DISPLAY_DEFINED +}; + //!cpp:type:: enum ColorSpaceDirection { @@ -712,9 +725,12 @@ abstract ways of asking for common colorspaces, without referring to them by hardcoded names. Internal:: + Extracting color space from file path - (ROLE_DEFAULT) - GetGPUDisplayTransform - (ROLE_SCENE_LINEAR (fstop exposure)) - (ROLE_COLOR_TIMING (ASCColorCorrection)) +App Helpers:: + ViewingPipeline - (ROLE_SCENE_LINEAR (LinearCC for exposure)) + (ROLE_COLOR_TIMING (ColorTimingCC)) + MixingColorSpaceManager - (ROLE_COLOR_PICKING) External Plugins (currently known):: @@ -772,6 +788,19 @@ extern OCIOEXPORT const char * ROLE_TEXTURE_PAINT; // another display transform in the host app for preview. extern OCIOEXPORT const char * ROLE_MATTE_PAINT; +/*!rst:: +Shared View +*********** + +*/ + +//!rst:: +// .. c:var:: const char * OCIO_VIEW_USE_DISPLAY_NAME +// +// A shared view using this for the color space name will use a display color space that +// has the same name as the display the shared view is used by. +extern OCIOEXPORT const char * OCIO_VIEW_USE_DISPLAY_NAME; + /*!rst:: FormatMetadata ************** diff --git a/src/OpenColorIO/CMakeLists.txt b/src/OpenColorIO/CMakeLists.txt index 4f23df26f1..cabad4248f 100755 --- a/src/OpenColorIO/CMakeLists.txt +++ b/src/OpenColorIO/CMakeLists.txt @@ -115,7 +115,7 @@ set(SOURCES transforms/BuiltinTransform.cpp transforms/CDLTransform.cpp transforms/ColorSpaceTransform.cpp - transforms/DisplayTransform.cpp + transforms/DisplayViewTransform.cpp transforms/ExponentTransform.cpp transforms/ExponentWithLinearTransform.cpp transforms/ExposureContrastTransform.cpp @@ -130,6 +130,7 @@ set(SOURCES transforms/Lut3DTransform.cpp transforms/MatrixTransform.cpp transforms/RangeTransform.cpp + ViewingRules.cpp ViewTransform.cpp ) diff --git a/src/OpenColorIO/Categories.h b/src/OpenColorIO/Categories.h deleted file mode 100644 index ae82ca69b2..0000000000 --- a/src/OpenColorIO/Categories.h +++ /dev/null @@ -1,102 +0,0 @@ -// SPDX-License-Identifier: BSD-3-Clause -// Copyright Contributors to the OpenColorIO Project. - - -#ifndef INCLUDED_OCIO_CATEGORIES_H -#define INCLUDED_OCIO_CATEGORIES_H - -#include -#include - -#include - -#include "PrivateTypes.h" -#include "utils/StringUtils.h" - -namespace OCIO_NAMESPACE -{ - -class CategoriesManager -{ -public: - CategoriesManager() = default; - CategoriesManager(const CategoriesManager &) = delete; - virtual ~CategoriesManager() = default; - CategoriesManager & operator=(const CategoriesManager &) = default; - - typedef StringUtils::StringVec Categories; - - Categories::const_iterator findCategory(const char * category) const - { - if (!category || !*category) return m_categories.end(); - - // NB: Categories are not case-sensitive and whitespace is stripped. - const std::string ref(StringUtils::Trim(StringUtils::Lower(category))); - - for (auto itr = m_categories.begin(); itr != m_categories.end(); ++itr) - { - if (StringUtils::Trim(StringUtils::Lower(*itr)) == ref) - { - return itr; - } - } - - return m_categories.end(); - } - - bool hasCategory(const char * category) const - { - return findCategory(category) != m_categories.end(); - } - - void addCategory(const char * category) - { - if (findCategory(category) == m_categories.end()) - { - m_categories.push_back(StringUtils::Trim(category)); - } - } - - void removeCategory(const char * category) - { - if (!category || !*category) return; - - // NB: Categories are not case-sensitive and whitespace is stripped. - const std::string ref(StringUtils::Trim(StringUtils::Lower(category))); - - for (auto itr = m_categories.begin(); itr != m_categories.end(); ++itr) - { - if (StringUtils::Trim(StringUtils::Lower(*itr)) == ref) - { - m_categories.erase(itr); - return; - } - } - - return; - } - - int getNumCategories() const - { - return static_cast(m_categories.size()); - } - - const char * getCategory(int index) const - { - if (index<0 || index >= (int)m_categories.size()) return nullptr; - - return m_categories[index].c_str(); - } - - void clearCategories() - { - m_categories.clear(); - } - -private: - Categories m_categories; -}; - -} // namespace OCIO_NAMESPACE - -#endif diff --git a/src/OpenColorIO/ColorSpace.cpp b/src/OpenColorIO/ColorSpace.cpp index 4193a4f92d..19c42f2c11 100644 --- a/src/OpenColorIO/ColorSpace.cpp +++ b/src/OpenColorIO/ColorSpace.cpp @@ -7,7 +7,7 @@ #include -#include "Categories.h" +#include "TokensManager.h" #include "PrivateTypes.h" #include "utils/StringUtils.h" @@ -15,13 +15,14 @@ namespace OCIO_NAMESPACE { -class ColorSpace::Impl : public CategoriesManager +class ColorSpace::Impl { public: std::string m_name; std::string m_family; std::string m_equalityGroup; std::string m_description; + std::string m_encoding; BitDepth m_bitDepth{ BIT_DEPTH_UNKNOWN }; bool m_isData{ false }; @@ -37,11 +38,11 @@ class ColorSpace::Impl : public CategoriesManager bool m_toRefSpecified{ false }; bool m_fromRefSpecified{ false }; - Impl() = delete; + TokensManager m_categories; + Impl() = delete; explicit Impl(ReferenceSpaceType referenceSpace) - : CategoriesManager() - , m_referenceSpaceType(referenceSpace) + : m_referenceSpaceType(referenceSpace) { } @@ -53,13 +54,11 @@ class ColorSpace::Impl : public CategoriesManager { if (this != &rhs) { - *dynamic_cast(this) - = *dynamic_cast(&rhs); - m_name = rhs.m_name; m_family = rhs.m_family; m_equalityGroup = rhs.m_equalityGroup; m_description = rhs.m_description; + m_encoding = rhs.m_encoding; m_bitDepth = rhs.m_bitDepth; m_isData = rhs.m_isData; m_referenceSpaceType = rhs.m_referenceSpaceType; @@ -76,6 +75,7 @@ class ColorSpace::Impl : public CategoriesManager m_toRefSpecified = rhs.m_toRefSpecified; m_fromRefSpecified = rhs.m_fromRefSpecified; + m_categories = rhs.m_categories; } return *this; } @@ -171,55 +171,65 @@ void ColorSpace::setBitDepth(BitDepth bitDepth) bool ColorSpace::hasCategory(const char * category) const { - return getImpl()->hasCategory(category); + return getImpl()->m_categories.hasToken(category); } void ColorSpace::addCategory(const char * category) { - getImpl()->addCategory(category); + getImpl()->m_categories.addToken(category); } void ColorSpace::removeCategory(const char * category) { - getImpl()->removeCategory(category); + getImpl()->m_categories.removeToken(category); } int ColorSpace::getNumCategories() const { - return getImpl()->getNumCategories(); + return getImpl()->m_categories.getNumTokens(); } const char * ColorSpace::getCategory(int index) const { - return getImpl()->getCategory(index); + return getImpl()->m_categories.getToken(index); } void ColorSpace::clearCategories() { - getImpl()->clearCategories(); + getImpl()->m_categories.clearTokens(); +} + +const char * ColorSpace::getEncoding() const noexcept +{ + return getImpl()->m_encoding.c_str(); } -bool ColorSpace::isData() const +void ColorSpace::setEncoding(const char * encoding) +{ + getImpl()->m_encoding = encoding; +} + +bool ColorSpace::isData() const noexcept { return getImpl()->m_isData; } -void ColorSpace::setIsData(bool val) +void ColorSpace::setIsData(bool val) noexcept { getImpl()->m_isData = val; } -ReferenceSpaceType ColorSpace::getReferenceSpaceType() const +ReferenceSpaceType ColorSpace::getReferenceSpaceType() const noexcept { return getImpl()->m_referenceSpaceType; } -Allocation ColorSpace::getAllocation() const +Allocation ColorSpace::getAllocation() const noexcept { return getImpl()->m_allocation; } -void ColorSpace::setAllocation(Allocation allocation) +void ColorSpace::setAllocation(Allocation allocation) noexcept { getImpl()->m_allocation = allocation; } @@ -294,9 +304,21 @@ std::ostream & operator<< (std::ostream & os, const ColorSpace & cs) break; } os << "name=" << cs.getName() << ", "; - os << "family=" << cs.getFamily() << ", "; - os << "equalityGroup=" << cs.getEqualityGroup() << ", "; - os << "bitDepth=" << BitDepthToString(cs.getBitDepth()) << ", "; + std::string str{ cs.getFamily() }; + if (!str.empty()) + { + os << "family=" << str << ", "; + } + str = cs.getEqualityGroup(); + if (!str.empty()) + { + os << "equalityGroup=" << str << ", "; + } + const auto bd = cs.getBitDepth(); + if (bd != BIT_DEPTH_UNKNOWN) + { + os << "bitDepth=" << BitDepthToString(bd) << ", "; + } os << "isData=" << BoolToString(cs.isData()); if (numVars) { @@ -307,6 +329,20 @@ std::ostream & operator<< (std::ostream & os, const ColorSpace & cs) os << " " << vars[i]; } } + if (cs.getNumCategories()) + { + StringUtils::StringVec categories; + for (int i = 0; i < cs.getNumCategories(); ++i) + { + categories.push_back(cs.getCategory(i)); + } + os << ", categories=" << StringUtils::Join(categories, ','); + } + str = cs.getEncoding(); + if (!str.empty()) + { + os << ", encoding=" << str; + } os << ">"; if(cs.getTransform(COLORSPACE_DIR_TO_REFERENCE)) diff --git a/src/OpenColorIO/Config.cpp b/src/OpenColorIO/Config.cpp index d616fcdf74..c4a9b899ef 100644 --- a/src/OpenColorIO/Config.cpp +++ b/src/OpenColorIO/Config.cpp @@ -27,6 +27,7 @@ #include "PrivateTypes.h" #include "Processor.h" #include "utils/StringUtils.h" +#include "ViewingRules.h" namespace OCIO_NAMESPACE @@ -38,6 +39,10 @@ const char * OCIO_ACTIVE_VIEWS_ENVVAR = "OCIO_ACTIVE_VIEWS"; const char * OCIO_INACTIVE_COLORSPACES_ENVVAR = "OCIO_INACTIVE_COLORSPACES"; const char * OCIO_OPTIMIZATION_FLAGS_ENVVAR = "OCIO_OPTIMIZATION_FLAGS"; +// A shared view using this for the color space name will use a display color space that +// has the same name as the display the shared view is used by. +const char * OCIO_VIEW_USE_DISPLAY_NAME = ""; + namespace { @@ -167,10 +172,10 @@ void GetColorSpaceReferences(std::set & colorSpaceNames, colorSpaceNames.insert(context->resolveStringVar(colorSpaceTransform->getSrc())); colorSpaceNames.insert(context->resolveStringVar(colorSpaceTransform->getDst())); } - else if(ConstDisplayTransformRcPtr displayTransform = \ - DynamicPtrCast(transform)) + else if(ConstDisplayViewTransformRcPtr displayViewTransform = \ + DynamicPtrCast(transform)) { - colorSpaceNames.insert(displayTransform->getInputColorSpaceName()); + colorSpaceNames.insert(displayViewTransform->getSrc()); } else if(ConstLookTransformRcPtr lookTransform = \ DynamicPtrCast(transform)) @@ -198,6 +203,42 @@ void FindAvailableName(const ColorSpaceSetRcPtr & colorspaces, std::string & csn } } +// Views are stored in two vectors of objects, using pointers to temporarily group them. +typedef std::vector ViewPtrVec; + +StringUtils::StringVec GetViewNames(const ViewPtrVec & views) +{ + StringUtils::StringVec viewNames; + for (const auto & view : views) + { + viewNames.push_back(view->m_name); + } + return viewNames; +} + +std::ostringstream GetDisplayViewPrefixErrorMsg(const std::string & display, const View & view) +{ + std::ostringstream oss; + oss << "Config failed sanitycheck. "; + if (display.empty()) + { + oss << "Shared "; + } + else + { + oss << "Display '" << display << "' has a "; + } + if (view.m_name.empty()) + { + oss << "view with an empty name."; + } + else + { + oss << "view '" << view.m_name << "' "; + } + return oss; +} + } // namespace @@ -244,6 +285,8 @@ class Config::Impl StringUtils::StringVec m_activeDisplaysEnvOverride; StringUtils::StringVec m_activeViews; StringUtils::StringVec m_activeViewsEnvOverride; + ViewVec m_sharedViews; + ViewingRulesRcPtr m_viewingRules; std::vector m_viewTransforms; @@ -268,6 +311,7 @@ class Config::Impl m_minorVersion(0), m_context(Context::Create()), m_allColorSpaces(ColorSpaceSet::Create()), + m_viewingRules(ViewingRules::Create()), m_strictParsing(true), m_sanity(SANITY_UNKNOWN), m_fileRules(FileRules::Create()) @@ -277,7 +321,7 @@ class Config::Impl activeDisplays = StringUtils::Trim(activeDisplays); if (!activeDisplays.empty()) { - SplitStringEnvStyle(m_activeDisplaysEnvOverride, activeDisplays.c_str()); + m_activeDisplaysEnvOverride = SplitStringEnvStyle(activeDisplays); } std::string activeViews; @@ -285,7 +329,7 @@ class Config::Impl activeViews = StringUtils::Trim(activeViews); if (!activeViews.empty()) { - SplitStringEnvStyle(m_activeViewsEnvOverride, activeViews.c_str()); + m_activeViewsEnvOverride = SplitStringEnvStyle(activeViews); } m_defaultLumaCoefs.resize(3); @@ -336,6 +380,8 @@ class Config::Impl m_activeDisplaysEnvOverride = rhs.m_activeDisplaysEnvOverride; m_activeDisplaysStr = rhs.m_activeDisplaysStr; m_displayCache = rhs.m_displayCache; + m_viewingRules = rhs.m_viewingRules->createEditableCopy(); + m_sharedViews = rhs.m_sharedViews; // Deep copy view transforms. m_viewTransforms.clear(); @@ -359,6 +405,20 @@ class Config::Impl return *this; } + ConstColorSpaceRcPtr getColorSpace(const char * name) const + { + // Check to see if the name is a color space. + ConstColorSpaceRcPtr cs = m_allColorSpaces->getColorSpace(name); + if (!cs) + { + // Check to see if the name is a role. + const char * csname = LookupRole(m_roles, name); + cs = m_allColorSpaces->getColorSpace(csname); + } + + return cs; + } + // Only search for a color space name (i.e. not for a role name). int getColorSpaceIndex(const char * csname) const { @@ -374,6 +434,56 @@ class Config::Impl StringUtils::StringVec buildInactiveColorSpaceList() const; void refreshActiveColorSpaces(); + ConstViewTransformRcPtr getViewTransform(const char * name) const noexcept + { + const std::string namelower = StringUtils::Lower(name); + + for (const auto & vt : m_viewTransforms) + { + if (StringUtils::Lower(vt->getName()) == namelower) + { + return vt; + } + } + + return ConstViewTransformRcPtr(); + } + + ConstLookRcPtr getLook(const char * name) const + { + const std::string namelower = StringUtils::Lower(name); + + for (const auto & look : m_looksList) + { + if (StringUtils::Lower(look->getName()) == namelower) + { + return look; + } + } + + return ConstLookRcPtr(); + } + + ViewPtrVec getViews(const Display & display) const + { + ViewPtrVec views; + for (const auto & view : display.m_views) + { + views.push_back(&view); + } + + for (const auto & shared : display.m_sharedViews) + { + ViewVec::const_iterator sharedView = FindView(m_sharedViews, shared.c_str()); + if (sharedView != m_sharedViews.end()) + { + const View * viewPtr = &(*sharedView); + views.push_back(viewPtr); + } + } + return views; + } + // Any time you modify the state of the config, you must call this // to reset internal cache states. You also should do this in a // thread safe manner by acquiring the m_cacheidMutex. @@ -435,6 +545,169 @@ class Config::Impl } } + // Sanity check view object that can be a config defined shared view or a display-defined view. + void sanityCheckView(const std::string & display, const View & view) const + { + if (view.m_name.empty()) + { + std::ostringstream os{ GetDisplayViewPrefixErrorMsg(display, view) }; + m_sanitytext = os.str(); + throw Exception(m_sanitytext.c_str()); + } + + const bool sharedViewWithViewTransform = display.empty() && !view.m_viewTransform.empty(); + + // Validate color space name is not empty. + if (view.m_colorspace.empty()) + { + std::ostringstream os{ GetDisplayViewPrefixErrorMsg(display, view) }; + os << "does not refer to a color space."; + m_sanitytext = os.str(); + throw Exception(m_sanitytext.c_str()); + } + // USE_DISPLAY_NAME can only be used by shared views. + if (!sharedViewWithViewTransform && view.useDisplayNameForColorspace()) + { + std::ostringstream os{ GetDisplayViewPrefixErrorMsg(display, view) }; + os << "can not use '" << OCIO_VIEW_USE_DISPLAY_NAME; + os << "' keyword for the color space name."; + m_sanitytext = os.str(); + throw Exception(m_sanitytext.c_str()); + } + + // If USE_DISPLAY_NAME is not present, a valid color space must be specified. + if (!view.useDisplayNameForColorspace() && !hasColorSpace(view.m_colorspace.c_str())) + { + std::ostringstream os{ GetDisplayViewPrefixErrorMsg(display, view) }; + os << "refers to a color space, '" << view.m_colorspace << "', "; + os << "which is not defined."; + m_sanitytext = os.str(); + throw Exception(m_sanitytext.c_str()); + } + + // If there is a view transform, it must exist and its color space must be a + // display-referred color space. + if (!view.m_viewTransform.empty()) + { + if (!getViewTransform(view.m_viewTransform.c_str())) + { + std::ostringstream os{ GetDisplayViewPrefixErrorMsg(display, view) }; + os << "refers to a view transform, '" << view.m_viewTransform << "', "; + os << "which is not defined."; + m_sanitytext = os.str(); + throw Exception(m_sanitytext.c_str()); + } + + if (!view.useDisplayNameForColorspace()) + { + auto cs = m_allColorSpaces->getColorSpace(view.m_colorspace.c_str()); + if (cs->getReferenceSpaceType() != REFERENCE_SPACE_DISPLAY) + { + std::ostringstream os{ GetDisplayViewPrefixErrorMsg(display, view) }; + os << "refers to a color space, '" << view.m_colorspace << "', "; + os << "that is not a display-referred color space."; + m_sanitytext = os.str(); + throw Exception(m_sanitytext.c_str()); + } + } + } + + // Confirm looks references exist. + LookParseResult looks; + const LookParseResult::Options & options = looks.parse(view.m_looks); + + for (const auto & option : options) + { + for (const auto & token : option) + { + const std::string look = token.name; + + if (!look.empty() && !getLook(look.c_str())) + { + std::ostringstream os{ GetDisplayViewPrefixErrorMsg(display, view) }; + os << "refers to a look, '" << look << "', "; + os << "which is not defined."; + m_sanitytext = os.str(); + throw Exception(m_sanitytext.c_str()); + } + } + } + + if (!view.m_rule.empty()) + { + size_t ruleIndex{ 0 }; + if (!FindRule(m_viewingRules, view.m_rule, ruleIndex)) + { + std::ostringstream os{ GetDisplayViewPrefixErrorMsg(display, view) }; + os << "refers to a viewing rule, '" << view.m_rule << "', "; + os << "which is not defined."; + m_sanitytext = os.str(); + throw Exception(m_sanitytext.c_str()); + } + } + } + + // Check a shared view used in a display. View itself has already been checked. + void sanityCheckSharedView(const std::string & display, const ViewVec & viewsOfDisplay, + const std::string & sharedView) const + { + // Is the name already used for a display-defined view? + // This should never happen because this is checked when adding a view. + const auto viewIt = FindView(viewsOfDisplay, sharedView); + if (viewIt != viewsOfDisplay.end()) + { + std::ostringstream os; + os << "Config failed sanitycheck. "; + os << "The display '" << display << "' "; + os << "contains a shared view '" << sharedView; + os << "' that is already defined as a view."; + m_sanitytext = os.str(); + throw Exception(m_sanitytext.c_str()); + } + // Is the shared view defined? + const auto sharedViewIt = FindView(m_sharedViews, sharedView); + if (sharedViewIt == m_sharedViews.end()) + { + std::ostringstream os; + os << "Config failed sanitycheck. "; + os << "The display '" << display << "' "; + os << "contains a shared view '" << sharedView; + os << "' that is not defined."; + m_sanitytext = os.str(); + throw Exception(m_sanitytext.c_str()); + } + else + { + if (!((*sharedViewIt).m_viewTransform.empty()) && + ((*sharedViewIt).useDisplayNameForColorspace())) + { + // Shared views using a view transform can omit the colorspace, in that case + // the color space to use should be named from the display. + const auto displayCS = m_allColorSpaces->getColorSpace(display.c_str()); + if (!displayCS) + { + std::ostringstream os; + os << "Config failed sanitycheck. The display '" << display << "' "; + os << "contains a shared view '" << (*sharedViewIt).m_name; + os << "' which does not define a color space and there is " + "no color space that matches the display name."; + m_sanitytext = os.str(); + throw Exception(m_sanitytext.c_str()); + } + if (displayCS->getReferenceSpaceType() != REFERENCE_SPACE_DISPLAY) + { + std::ostringstream os; + os << "Config failed sanitycheck. The display '" << display << "' "; + os << "contains a shared view '" << (*sharedViewIt).m_name; + os << "that refers to a color space, '" << display << "', "; + os << "that is not a display-referred color space."; + m_sanitytext = os.str(); + throw Exception(m_sanitytext.c_str()); + } + } + } + } + void setInactiveColorSpaces(const char * inactiveColorSpaces) { m_inactiveColorSpaceNamesConf @@ -452,6 +725,145 @@ class Config::Impl void checkVersionConsistency(ConstTransformRcPtr & transform) const; void checkVersionConsistency() const; + const View * getView(const char * display, const char * view) const + { + if (!view || !*view) return nullptr; + + bool searchShared = !display || !*display; + + DisplayMap::const_iterator iter = m_displays.end(); + if (!searchShared) + { + iter = FindDisplay(m_displays, display); + if (iter == m_displays.end()) return nullptr; + + const StringUtils::StringVec & sharedViews = iter->second.m_sharedViews; + searchShared = StringUtils::Contain(sharedViews, view); + } + + const ViewVec & views = searchShared ? m_sharedViews : iter->second.m_views; + const auto & viewIt = FindView(views, view); + + if (viewIt != views.end()) + { + return &(*viewIt); + } + return nullptr; + } + + // Filter/reorder views using the active views if defined. + StringUtils::StringVec getActiveViews(const StringUtils::StringVec & views) const + { + StringUtils::StringVec activeViews; + if (!m_activeViewsEnvOverride.empty()) + { + const StringUtils::StringVec orderedViews + = IntersectStringVecsCaseIgnore(m_activeViewsEnvOverride, views); + + if (!orderedViews.empty()) + { + activeViews = orderedViews; + } + } + else if (!m_activeViews.empty()) + { + const StringUtils::StringVec orderedViews + = IntersectStringVecsCaseIgnore(m_activeViews, views); + + if (!orderedViews.empty()) + { + activeViews = orderedViews; + } + } + + if (activeViews.empty()) + { + activeViews = views; + } + return activeViews; + } + + // Get all active views from a display with a rule that refers to color space or an encoding + // referred by color space. Note that views that do not have viewing rules are all returned. + // ViewNames, created from views, is returned as parameter. + StringUtils::StringVec getFilteredViews(StringUtils::StringVec & viewNames, + const ViewPtrVec & views, + const char * imageCSName) const + { + ConstColorSpaceRcPtr imageColorSpace = getColorSpace(imageCSName); + if (!imageColorSpace) + { + std::ostringstream os; + os << "Could not find source color space '" << imageCSName << "'."; + throw Exception(os.str().c_str()); + } + + const std::string viewEncoding{ imageColorSpace->getEncoding() }; + + viewNames = GetViewNames(views); + StringUtils::StringVec activeViews = getActiveViews(viewNames); + + const std::string imageColorSpaceName{ StringUtils::Lower(imageCSName) }; + StringUtils::StringVec filteredActiveViews; + for (const auto & view : activeViews) + { + const auto idx = FindInStringVecCaseIgnore(viewNames, view); + const auto & ruleName = views[idx]->m_rule; + size_t ruleIdx{ 0 }; + if (ruleName.empty()) + { + // Include all views that do not have a rule. + filteredActiveViews.push_back(view); + } + else if (FindRule(m_viewingRules, ruleName, ruleIdx)) + { + const size_t numcs = m_viewingRules->getNumColorSpaces(ruleIdx); + bool added = false; + for (size_t csIdx = 0; csIdx < numcs; ++csIdx) + { + // Rule can use role names. + const char * rolename = m_viewingRules->getColorSpace(ruleIdx, csIdx); + const char * csname = LookupRole(m_roles, rolename); + + const std::string csName{ *csname ? csname : rolename }; + if (StringUtils::Lower(csName) == imageColorSpaceName) + { + // Include a view if its rule contains the image's color space. + filteredActiveViews.push_back(view); + added = true; + break; + } + } + if (!added && !viewEncoding.empty()) + { + const size_t numEnc = m_viewingRules->getNumEncodings(ruleIdx); + for (size_t encIdx = 0; encIdx < numEnc; ++encIdx) + { + const std::string encName{ m_viewingRules->getEncoding(ruleIdx, encIdx) }; + if (StringUtils::Lower(encName) == viewEncoding) + { + // Include a view if its rule contains the image's color space encoding. + filteredActiveViews.push_back(view); + break; + } + } + } + } + } + return filteredActiveViews; + } + + void updateDisplayCache() const + { + if (m_displayCache.empty()) + { + ComputeDisplays(m_displayCache, + m_displays, + m_activeDisplays, + m_activeDisplaysEnvOverride); + } + + } }; /////////////////////////////////////////////////////////////////////////// @@ -696,16 +1108,40 @@ void Config::sanityCheck() const ///// DISPLAYS / VIEWS - int numviews = 0; + // Viewing rules. + + try + { + auto colorSpaceAccessor = std::bind(&Config::getColorSpace, this, std::placeholders::_1); + getImpl()->m_viewingRules->getImpl()->sanityCheck(colorSpaceAccessor, + getImpl()->m_allColorSpaces); + } + catch (const Exception & e) + { + std::ostringstream os; + os << "Config failed sanitycheck. Viewing rules failed sanitycheck with: "; + os << e.what(); + getImpl()->m_sanitytext = os.str(); + throw Exception(getImpl()->m_sanitytext.c_str()); + } + + // Shared views. + for (const auto & view : getImpl()->m_sharedViews) + { + getImpl()->sanityCheckView("", view); + } + + int numdisplays = 0; - // Confirm all Display transforms refer to colorspaces that exit. + // Confirm all Display transforms refer to colorspaces that exist. for(DisplayMap::const_iterator iter = getImpl()->m_displays.begin(); iter != getImpl()->m_displays.end(); ++iter) { const std::string display = iter->first; - const ViewVec & views = iter->second; - if(views.empty()) + const ViewVec & views = iter->second.m_views; + const StringUtils::StringVec & sharedViews = iter->second.m_sharedViews; + if(views.empty() && sharedViews.empty()) { std::ostringstream os; os << "Config failed sanitycheck. "; @@ -714,95 +1150,23 @@ void Config::sanityCheck() const getImpl()->m_sanitytext = os.str(); throw Exception(getImpl()->m_sanitytext.c_str()); } + ++numdisplays; - // Confirm view references exist. - for(unsigned int i=0; im_sanitytext = os.str(); - throw Exception(getImpl()->m_sanitytext.c_str()); - } - - if(!getImpl()->hasColorSpace(views[i].m_colorspace.c_str())) - { - std::ostringstream os; - os << "Config failed sanitycheck. "; - os << "The display '" << display << "' "; - os << " view '" << views[i].m_name << "' "; - os << "refers to a color space, '" << views[i].m_colorspace << "', "; - os << "which is not defined."; - getImpl()->m_sanitytext = os.str(); - throw Exception(getImpl()->m_sanitytext.c_str()); - } - - // If there is a view transform, it must exist and its color space must be a - // display-referred color space. - if (!views[i].m_viewTransform.empty()) - { - if (!getViewTransform(views[i].m_viewTransform.c_str())) - { - std::ostringstream os; - os << "Config failed sanitycheck. "; - os << "The display '" << display << "' "; - os << " view '" << views[i].m_name << "' "; - os << "refers to a view transform, '" << views[i].m_viewTransform << "', "; - os << "which is not defined."; - getImpl()->m_sanitytext = os.str(); - throw Exception(getImpl()->m_sanitytext.c_str()); - } - - auto cs = getImpl()->m_allColorSpaces->getColorSpace(views[i].m_colorspace.c_str()); - if (cs->getReferenceSpaceType() != REFERENCE_SPACE_DISPLAY) - { - std::ostringstream os; - os << "Config failed sanitycheck. "; - os << "The display '" << display << "' "; - os << " view '" << views[i].m_name << "' "; - os << "refers to a color space, '" << views[i].m_colorspace << "', "; - os << "that is not a display-referred color space."; - getImpl()->m_sanitytext = os.str(); - throw Exception(getImpl()->m_sanitytext.c_str()); - } - } - - // Confirm looks references exist. - LookParseResult looks; - const LookParseResult::Options & options = looks.parse(views[i].m_looks); - - for(unsigned int optionindex=0; - optionindex < options.size(); - ++optionindex) - { - for(unsigned int tokenindex=0; - tokenindex < options[optionindex].size(); - ++tokenindex) - { - std::string look = options[optionindex][tokenindex].name; - - if(!look.empty() && !getLook(look.c_str())) - { - std::ostringstream os; - os << "Config failed sanitycheck. "; - os << "The display '" << display << "' "; - os << "refers to a look, '" << look << "', "; - os << "which is not defined."; - getImpl()->m_sanitytext = os.str(); - throw Exception(getImpl()->m_sanitytext.c_str()); - } - } - } + getImpl()->sanityCheckSharedView(display, views, sharedView); + } - ++numviews; + // Confirm view references exist. + for(const auto & view : views) + { + getImpl()->sanityCheckView(display, view); } } // Confirm at least one display entry exists. - if (numviews == 0) + if (numdisplays == 0) { std::ostringstream os; os << "Config failed sanitycheck. "; @@ -1008,12 +1372,31 @@ void Config::sanityCheck() const ///// FileRules - if (getMajorVersion() >= 2) + // All Config objects have a fileRules object, regardless of version. This object is + // initialized to have a defaultRule with the color space set to "default" (i.e., the default + // role). The fileRules->sanityCheck call will validate that all color spaces used in rules + // exist, or if they are roles that they point to a color space that exists. Because this would + // cause sanityCheck to improperly fail on v1 configs (since they are not required to actually + // contain file rules), we don't do this check on v1 configs when there is only one rule. + if (getMajorVersion() >= 2 || getImpl()->m_fileRules->getNumEntries() != 1) { - auto colorSpaceAccessor = std::bind(&Config::getColorSpace, this, std::placeholders::_1); - getImpl()->m_fileRules->getImpl()->sanityCheck(colorSpaceAccessor); + try + { + auto colorSpaceAccessor = std::bind(&Config::getColorSpace, this, std::placeholders::_1); + getImpl()->m_fileRules->getImpl()->sanityCheck(colorSpaceAccessor); + } + catch (const Exception & e) + { + std::ostringstream os; + os << "Config failed sanitycheck. File rules failed with: "; + os << e.what(); + getImpl()->m_sanitytext = os.str(); + throw Exception(getImpl()->m_sanitytext.c_str()); + } } + getImpl()->checkVersionConsistency(); + // Everything is groovy. getImpl()->m_sanity = Impl::SANITY_SANE; } @@ -1052,7 +1435,7 @@ const char * Config::getDescription() const void Config::setDescription(const char * description) { - getImpl()->m_description = description; + getImpl()->m_description = description ? description : ""; AutoMutex lock(getImpl()->m_cacheidMutex); getImpl()->resetCacheIDs(); @@ -1067,6 +1450,7 @@ ConstContextRcPtr Config::getCurrentContext() const void Config::addEnvironmentVar(const char * name, const char * defaultValue) { + if (!name || !*name) return; if(defaultValue) { getImpl()->m_env[std::string(name)] = std::string(defaultValue); @@ -1097,6 +1481,7 @@ const char * Config::getEnvironmentVarNameByIndex(int index) const const char * Config::getEnvironmentVarDefault(const char * name) const { + if (!name || !*name) return ""; return LookupEnvironment(getImpl()->m_env, name); } @@ -1137,7 +1522,7 @@ const char * Config::getSearchPath() const void Config::setSearchPath(const char * path) { - getImpl()->m_context->setSearchPath(path); + getImpl()->m_context->setSearchPath(path ? path : ""); AutoMutex lock(getImpl()->m_cacheidMutex); getImpl()->resetCacheIDs(); @@ -1163,6 +1548,7 @@ void Config::clearSearchPaths() void Config::addSearchPath(const char * path) { + if (!path || !*path) return; getImpl()->m_context->addSearchPath(path); AutoMutex lock(getImpl()->m_cacheidMutex); @@ -1176,7 +1562,7 @@ const char * Config::getWorkingDir() const void Config::setWorkingDir(const char * dirname) { - getImpl()->m_context->setWorkingDir(dirname); + getImpl()->m_context->setWorkingDir(dirname ? dirname : ""); AutoMutex lock(getImpl()->m_cacheidMutex); getImpl()->resetCacheIDs(); @@ -1393,16 +1779,7 @@ const char * Config::getColorSpaceNameByIndex(SearchReferenceSpaceType searchRef // Note: works from the list of all color spaces. ConstColorSpaceRcPtr Config::getColorSpace(const char * name) const { - // Check to see if the name is a color space. - ConstColorSpaceRcPtr cs = getImpl()->m_allColorSpaces->getColorSpace(name); - if (!cs) - { - // Check to see if the name is a role. - const char * csname = LookupRole(getImpl()->m_roles, name); - cs = getImpl()->m_allColorSpaces->getColorSpace(csname); - } - - return cs; + return getImpl()->getColorSpace(name); } int Config::getNumColorSpaces() const @@ -1509,20 +1886,46 @@ bool Config::isColorSpaceUsed(const char * name) const noexcept } } + // Check for all shared views. + + for (const auto & view : getImpl()->m_sharedViews) + { + const char * csName = view.m_colorspace.c_str(); + if (0 == Platform::Strcasecmp(csName, name)) + { + return true; + } + } + // Check for all (display, view) pairs (i.e. active and inactive ones). for (const auto & display : getImpl()->m_displays) { const char * dispName = display.first.c_str(); - for (const auto & view : display.second) + for (const auto & view : display.second.m_views) { const char * viewName = view.m_name.c_str(); - const char * csName = getDisplayColorSpaceName(dispName, viewName); + const char * csName = getDisplayViewColorSpaceName(dispName, viewName); if (0 == Platform::Strcasecmp(csName, name)) { return true; } } + for (const auto & sharedView : display.second.m_sharedViews) + { + auto viewIt = FindView(getImpl()->m_sharedViews, sharedView); + if (viewIt != getImpl()->m_sharedViews.end()) + { + if (!((*viewIt).m_viewTransform.empty()) && + (*viewIt).useDisplayNameForColorspace()) + { + if (0 == Platform::Strcasecmp(dispName, name)) + { + return true; + } + } + } + } } // Check for 'process_space' from look. @@ -1537,7 +1940,7 @@ bool Config::isColorSpaceUsed(const char * name) const noexcept { return true; } - } + } // Check the file rules. @@ -1611,6 +2014,8 @@ void Config::setStrictParsingEnabled(bool enabled) // Roles void Config::setRole(const char * role, const char * colorSpaceName) { + if (!role || !*role) return; + // Set the role if(colorSpaceName) { @@ -1637,6 +2042,7 @@ int Config::getNumRoles() const bool Config::hasRole(const char * role) const { + if (!role || !*role) return false; const char* rname = LookupRole(getImpl()->m_roles, role); return rname && *rname; } @@ -1658,34 +2064,88 @@ const char * Config::getRoleColorSpace(int index) const // // Display/View Registration -const char * Config::getDefaultDisplay() const + +ConstViewingRulesRcPtr Config::getViewingRules() const noexcept { - return getDisplay(0); + return getImpl()->m_viewingRules; } +void Config::setViewingRules(ConstViewingRulesRcPtr viewingRules) +{ + getImpl()->m_viewingRules = viewingRules->createEditableCopy(); -int Config::getNumDisplays() const + AutoMutex lock(getImpl()->m_cacheidMutex); + getImpl()->resetCacheIDs(); +} + +void Config::addSharedView(const char * view, const char * viewTransform, + const char * colorSpace, const char * looks, + const char * rule, const char * description) { - if(getImpl()->m_displayCache.empty()) + if (!view || !*view) { - ComputeDisplays(getImpl()->m_displayCache, - getImpl()->m_displays, - getImpl()->m_activeDisplays, - getImpl()->m_activeDisplaysEnvOverride); + throw Exception("Shared view could not be added to config, view name has to be a " + "non-empty name."); } - return static_cast(getImpl()->m_displayCache.size()); + if (!colorSpace || !*colorSpace) + { + throw Exception("Shared view could not be added to config, color space name has to be a " + "non-empty name."); + } + + ViewVec & views = getImpl()->m_sharedViews; + AddView(views, view, viewTransform, colorSpace, looks, rule, description); + + getImpl()->m_displayCache.clear(); + + AutoMutex lock(getImpl()->m_cacheidMutex); + getImpl()->resetCacheIDs(); } -const char * Config::getDisplay(int index) const +void Config::removeSharedView(const char * view) { - if(getImpl()->m_displayCache.empty()) + if (!view || !*view) { - ComputeDisplays(getImpl()->m_displayCache, - getImpl()->m_displays, - getImpl()->m_activeDisplays, - getImpl()->m_activeDisplaysEnvOverride); + throw Exception("Shared view could not be removed from config, view name has to be " + "a non-empty name."); } + ViewVec & views = getImpl()->m_sharedViews; + auto viewIt = FindView(views, view); + + if (viewIt != views.end()) + { + views.erase(viewIt); + + getImpl()->m_displayCache.clear(); + + AutoMutex lock(getImpl()->m_cacheidMutex); + getImpl()->resetCacheIDs(); + } + else + { + std::ostringstream os; + os << "Shared view could not be removed from config. A shared view named '" + << view << "' could be be found."; + throw Exception(os.str().c_str()); + } +} + +const char * Config::getDefaultDisplay() const +{ + return getDisplay(0); +} + +int Config::getNumDisplays() const +{ + getImpl()->updateDisplayCache(); + + return static_cast(getImpl()->m_displayCache.size()); +} + +const char * Config::getDisplay(int index) const +{ + getImpl()->updateDisplayCache(); if(index>=0 && index < static_cast(getImpl()->m_displayCache.size())) { @@ -1702,105 +2162,94 @@ const char * Config::getDefaultView(const char * display) const int Config::getNumViews(const char * display) const { - if(getImpl()->m_displayCache.empty()) - { - ComputeDisplays(getImpl()->m_displayCache, - getImpl()->m_displays, - getImpl()->m_activeDisplays, - getImpl()->m_activeDisplaysEnvOverride); - } - - if(!display) return 0; + if (!display || !*display) return 0; - DisplayMap::const_iterator iter = find_display_const(getImpl()->m_displays, display); + DisplayMap::const_iterator iter = FindDisplay(getImpl()->m_displays, display); if(iter == getImpl()->m_displays.end()) return 0; - const ViewVec & views = iter->second; + const ViewPtrVec views = getImpl()->getViews(iter->second); - StringUtils::StringVec masterViews; - for(unsigned int i=0; igetActiveViews(masterViews); + return static_cast(activeViews.size()); +} - if(!getImpl()->m_activeViewsEnvOverride.empty()) - { - const StringUtils::StringVec orderedViews - = IntersectStringVecsCaseIgnore(getImpl()->m_activeViewsEnvOverride, masterViews); +const char * Config::getView(const char * display, int index) const +{ + if (!display || !*display) return ""; - if(!orderedViews.empty()) - { - return static_cast(orderedViews.size()); - } - } - else if(!getImpl()->m_activeViews.empty()) + // Include all displays, do not limit to active displays. Consider active views only. + DisplayMap::const_iterator iter = FindDisplay(getImpl()->m_displays, display); + if(iter == getImpl()->m_displays.end()) return ""; + + const ViewPtrVec views = getImpl()->getViews(iter->second); + + const StringUtils::StringVec masterViews{ GetViewNames(views) }; + StringUtils::StringVec activeViews = getImpl()->getActiveViews(masterViews); + + if (index < 0 || static_cast(index) >= activeViews.size()) { - const StringUtils::StringVec orderedViews - = IntersectStringVecsCaseIgnore(getImpl()->m_activeViews, masterViews); + return ""; + } + int idx = FindInStringVecCaseIgnore(masterViews, activeViews[index]); - if(!orderedViews.empty()) - { - return static_cast(orderedViews.size()); - } + if(idx >= 0 && static_cast(idx) < views.size()) + { + return views[idx]->m_name.c_str(); } - return static_cast(masterViews.size()); + return ""; } -const char * Config::getView(const char * display, int index) const +int Config::getNumViews(const char * display, const char * colorspace) const { - if(getImpl()->m_displayCache.empty()) - { - ComputeDisplays(getImpl()->m_displayCache, - getImpl()->m_displays, - getImpl()->m_activeDisplays, - getImpl()->m_activeDisplaysEnvOverride); - } + if (!display || !*display || !colorspace || !*colorspace) return 0; - if(!display) return ""; + DisplayMap::const_iterator iter = FindDisplay(getImpl()->m_displays, display); + if (iter == getImpl()->m_displays.end()) return 0; - DisplayMap::const_iterator iter = find_display_const(getImpl()->m_displays, display); - if(iter == getImpl()->m_displays.end()) return ""; + const ViewPtrVec views = getImpl()->getViews(iter->second); - const ViewVec & views = iter->second; + StringUtils::StringVec viewNames; + const StringUtils::StringVec filteredViews{ getImpl()->getFilteredViews(viewNames, + views, + colorspace) }; - StringUtils::StringVec masterViews; - for(unsigned int i = 0; i < views.size(); ++i) - { - masterViews.push_back(views[i].m_name); - } + return static_cast(filteredViews.size()); +} - int idx = index; +const char * Config::getView(const char * display, const char * colorspace, int index) const +{ + if (!display || !*display || !colorspace || !*colorspace) return ""; - if(!getImpl()->m_activeViewsEnvOverride.empty()) - { - const StringUtils::StringVec orderedViews - = IntersectStringVecsCaseIgnore(getImpl()->m_activeViewsEnvOverride, masterViews); + DisplayMap::const_iterator iter = FindDisplay(getImpl()->m_displays, display); + if (iter == getImpl()->m_displays.end()) return ""; - if(!orderedViews.empty()) - { - idx = FindInStringVecCaseIgnore(masterViews, orderedViews[index]); - } - } - else if(!getImpl()->m_activeViews.empty()) - { - const StringUtils::StringVec orderedViews - = IntersectStringVecsCaseIgnore(getImpl()->m_activeViews, masterViews); + const ViewPtrVec views = getImpl()->getViews(iter->second); - if(!orderedViews.empty()) + StringUtils::StringVec viewNames; + const StringUtils::StringVec filteredViews{ getImpl()->getFilteredViews(viewNames, + views, + colorspace) }; + int idx = index; + + if (!filteredViews.empty()) + { + if (index < 0 || static_cast(index) >= filteredViews.size()) { - idx = FindInStringVecCaseIgnore(masterViews, orderedViews[index]); + return ""; } + idx = FindInStringVecCaseIgnore(viewNames, filteredViews[index]); } - if(idx >= 0) + if (idx >= 0 && static_cast(idx) < views.size()) { - return views[idx].m_name.c_str(); + return views[idx]->m_name.c_str(); } - if(!views.empty()) + if (!views.empty()) { - return views[0].m_name.c_str(); + return views[0]->m_name.c_str(); } return ""; @@ -1808,110 +2257,196 @@ const char * Config::getView(const char * display, int index) const const char * Config::getDisplayViewTransformName(const char * display, const char * view) const { - if (!display || !view) return ""; + const View * viewPtr = getImpl()->getView(display, view); - DisplayMap::const_iterator iter = find_display_const(getImpl()->m_displays, display); - if (iter == getImpl()->m_displays.end()) return ""; + if (!viewPtr) return ""; + return viewPtr->m_viewTransform.c_str(); +} - const ViewVec & views = iter->second; - const int index = find_view(views, view); - if (index<0) return ""; +const char * Config::getDisplayViewColorSpaceName(const char * display, const char * view) const +{ + const View * viewPtr = getImpl()->getView(display, view); - return views[index].m_viewTransform.c_str(); + if (!viewPtr) return ""; + return viewPtr->m_colorspace.c_str(); } -const char * Config::getDisplayColorSpaceName(const char * display, const char * view) const +const char * Config::getDisplayViewLooks(const char * display, const char * view) const { - if(!display || !view) return ""; + const View * viewPtr = getImpl()->getView(display, view); - DisplayMap::const_iterator iter = find_display_const(getImpl()->m_displays, display); - if(iter == getImpl()->m_displays.end()) return ""; + if (!viewPtr) return ""; + return viewPtr->m_looks.c_str(); +} - const ViewVec & views = iter->second; - const int index = find_view(views, view); - if(index<0) return ""; +const char * Config::getDisplayViewRule(const char * display, const char * view) const noexcept +{ + const View * viewPtr = getImpl()->getView(display, view); - return views[index].m_colorspace.c_str(); + return viewPtr ? viewPtr->m_rule.c_str() : ""; } -const char * Config::getDisplayLooks(const char * display, const char * view) const +const char * Config::getDisplayViewDescription(const char * display, const char * view) const noexcept { - if(!display || !view) return ""; + const View * viewPtr = getImpl()->getView(display, view); - DisplayMap::const_iterator iter = find_display_const(getImpl()->m_displays, display); - if(iter == getImpl()->m_displays.end()) return ""; + return viewPtr ? viewPtr->m_description.c_str() : ""; +} - const ViewVec & views = iter->second; - const int index = find_view(views, view); - if(index<0) return ""; +void Config::addDisplaySharedView(const char * display, const char * sharedView) +{ + if (!display || !*display) + { + throw Exception("Shared view could not be added to display: non-empty display name " + "is needed."); + } + if (!sharedView || !*sharedView) + { + throw Exception("Shared view could not be added to display: non-empty view name " + "is needed."); + } - return views[index].m_looks.c_str(); -} + bool invalidateCache = false; + DisplayMap::iterator iter = FindDisplay(getImpl()->m_displays, display); + if (iter == getImpl()->m_displays.end()) + { + const auto curSize = getImpl()->m_displays.size(); + getImpl()->m_displays.resize(curSize + 1); + getImpl()->m_displays[curSize].first = display; + iter = std::prev(getImpl()->m_displays.end()); + invalidateCache = true; + } + const ViewVec & existingViews = iter->second.m_views; + auto viewIt = FindView(existingViews, sharedView); + if (viewIt != existingViews.end()) + { + std::ostringstream os; + os << "There is already a view named '" << sharedView; + os << "' in the display '" << display << "'."; + throw Exception(os.str().c_str()); + } -void Config::addDisplay(const char * display, const char * view, - const char * colorSpaceName, const char * looks) + StringUtils::StringVec & views = iter->second.m_sharedViews; + if (StringUtils::Contain(views, sharedView)) + { + std::ostringstream os; + os << "There is already a shared view named '" << sharedView; + os << "' in the display '" << display << "'."; + throw Exception(os.str().c_str()); + } + views.push_back(sharedView); + if (invalidateCache) + { + getImpl()->m_displayCache.clear(); + } + AutoMutex lock(getImpl()->m_cacheidMutex); + getImpl()->resetCacheIDs(); +} + +void Config::addDisplayView(const char * display, const char * view, + const char * colorSpace, const char * looks) { - addDisplay(display, view, nullptr, colorSpaceName, looks); + addDisplayView(display, view, nullptr, colorSpace, looks, nullptr, nullptr); } -void Config::addDisplay(const char * display, const char * view, const char * viewTransform, - const char * displayColorSpaceName, const char * looks) +void Config::addDisplayView(const char * display, const char * view, const char * viewTransform, + const char * colorSpace, const char * looks, + const char * rule, const char * description) { - if (!display || !view || !displayColorSpaceName) return; + if (!display || !*display) + { + throw Exception("View could not be added to display in config: a non-empty display " + "name is needed."); + } + if (!view || !*view) + { + throw Exception("View could not be added to display in config: a non-empty view " + "name is needed."); + } + if (!colorSpace || !*colorSpace) + { + throw Exception("View could not be added to display in config: a non-empty color space " + "name is needed."); + } - AddDisplay(getImpl()->m_displays, display, view, viewTransform, displayColorSpaceName, looks); - getImpl()->m_displayCache.clear(); + DisplayMap::iterator iter = FindDisplay(getImpl()->m_displays, display); + if (iter == getImpl()->m_displays.end()) + { + const auto curSize = getImpl()->m_displays.size(); + getImpl()->m_displays.resize(curSize + 1); + getImpl()->m_displays[curSize].first = display; + getImpl()->m_displays[curSize].second.m_views.push_back(View(view, viewTransform, + colorSpace, looks, rule, + description)); + getImpl()->m_displayCache.clear(); + } + else + { + if (StringUtils::Contain(iter->second.m_sharedViews, view)) + { + std::ostringstream os; + os << "There is already a shared view named '" << view; + os << "' in the display '" << display << "'."; + throw Exception(os.str().c_str()); + } + + ViewVec & views = iter->second.m_views; + AddView(views, view, viewTransform, colorSpace, looks, rule, description); + } AutoMutex lock(getImpl()->m_cacheidMutex); getImpl()->resetCacheIDs(); } -void Config::removeDisplay(const char * display, const char * view) +void Config::removeDisplayView(const char * display, const char * view) { - if(!display || !view) return; + if (!display || !*display) + { + throw Exception("Can't remove a view from a display with an empty display name."); + } + if (!view || !*view) + { + throw Exception("Can't remove a view from a display with an empty view name."); + } const std::string displayNameRef(display); - const std::string viewNameRef(view); // Check if the display exists. - DisplayMap::iterator iter = find_display(getImpl()->m_displays, display); + DisplayMap::iterator iter = FindDisplay(getImpl()->m_displays, display); if (iter==getImpl()->m_displays.end()) { - return; + std::ostringstream os; + os << "Could not find a display named '" << display << "' to be removed from config."; + throw Exception(os.str().c_str()); } - // Check if the display needs to be removed also. + ViewVec & views = iter->second.m_views; + StringUtils::StringVec & sharedViews = iter->second.m_sharedViews; - const bool removeDisplay = iter->second.size()<=1; - if (removeDisplay) + const std::string viewNameRef(view); + if (!StringUtils::Remove(sharedViews, view)) { - if (iter->second.size()==1 && !StrEqualsCaseIgnore(viewNameRef, iter->second[0].m_name)) + // view is not a shared view. + // Is it a view? + auto viewIt = FindView(views, view); + if (viewIt == views.end()) { - // The display does not have the view. - return; + std::ostringstream os; + os << "Could not find a view named '" << view; + os << " to be removed from the display named '" << display << "'."; + throw Exception(os.str().c_str()); } - } - // Remove the display/view pair. + views.erase(viewIt); + } - if (removeDisplay) + // Check if the display needs to be removed also. + if (views.empty() && sharedViews.empty()) { getImpl()->m_displays.erase(iter); } - else - { - ViewVec & views = iter->second; - - views.erase(std::remove_if(views.begin(), - views.end(), - [viewNameRef](const View & view) - { - return StrEqualsCaseIgnore(view.m_name, viewNameRef); - } ), - views.end()); - } getImpl()->m_displayCache.clear(); @@ -1931,7 +2466,7 @@ void Config::clearDisplays() void Config::setActiveDisplays(const char * displays) { getImpl()->m_activeDisplays.clear(); - SplitStringEnvStyle(getImpl()->m_activeDisplays, displays); + getImpl()->m_activeDisplays = SplitStringEnvStyle(displays); getImpl()->m_displayCache.clear(); @@ -1948,7 +2483,7 @@ const char * Config::getActiveDisplays() const void Config::setActiveViews(const char * views) { getImpl()->m_activeViews.clear(); - SplitStringEnvStyle(getImpl()->m_activeViews, views); + getImpl()->m_activeViews = SplitStringEnvStyle(views); getImpl()->m_displayCache.clear(); @@ -1962,6 +2497,80 @@ const char * Config::getActiveViews() const return getImpl()->m_activeViewsStr.c_str(); } +int Config::getNumDisplaysAll() const +{ + return static_cast(getImpl()->m_displays.size()); +} + +const char * Config::getDisplayAll(int index) const +{ + if (index >= 0 || index < static_cast(getImpl()->m_displays.size())) + { + return getImpl()->m_displays[index].first.c_str(); + } + + return ""; +} + +int Config::getNumViews(ViewType type, const char * display) const +{ + if (!display || !*display) + { + return static_cast(getImpl()->m_sharedViews.size()); + } + DisplayMap::const_iterator iter = FindDisplay(getImpl()->m_displays, display); + if (iter == getImpl()->m_displays.end()) return 0; + + switch (type) + { + case VIEW_SHARED: + return static_cast(iter->second.m_sharedViews.size()); + break; + case VIEW_DISPLAY_DEFINED: + return static_cast(iter->second.m_views.size()); + break; + } + return 0; +} + +const char * Config::getView(ViewType type, const char * display, int index) const +{ + if (!display || !*display) + { + if (index >= 0 || index < static_cast(getImpl()->m_sharedViews.size())) + { + return getImpl()->m_sharedViews[index].m_name.c_str(); + } + return ""; + } + + DisplayMap::const_iterator iter = FindDisplay(getImpl()->m_displays, display); + if(iter == getImpl()->m_displays.end()) return ""; + + switch (type) + { + case VIEW_SHARED: + { + const StringUtils::StringVec & views = iter->second.m_sharedViews; + if (index >= 0 && index < static_cast(views.size())) + { + return views[index].c_str(); + } + break; + } + case VIEW_DISPLAY_DEFINED: + { + const ViewVec & views = iter->second.m_views; + if (index >= 0 && index < static_cast(views.size())) + { + return views[index].m_name.c_str(); + } + break; + } + } + + return ""; +} /////////////////////////////////////////////////////////////////////////// @@ -1982,17 +2591,7 @@ void Config::setDefaultLumaCoefs(const double * c3) ConstLookRcPtr Config::getLook(const char * name) const { - const std::string namelower = StringUtils::Lower(name); - - for(unsigned int i=0; im_looksList.size(); ++i) - { - if(StringUtils::Lower(getImpl()->m_looksList[i]->getName()) == namelower) - { - return getImpl()->m_looksList[i]; - } - } - - return ConstLookRcPtr(); + return getImpl()->getLook(name); } int Config::getNumLooks() const @@ -2052,17 +2651,7 @@ int Config::getNumViewTransforms() const noexcept ConstViewTransformRcPtr Config::getViewTransform(const char * name) const noexcept { - const std::string namelower = StringUtils::Lower(name); - - for (auto vt : getImpl()->m_viewTransforms) - { - if (StringUtils::Lower(vt->getName()) == namelower) - { - return vt; - } - } - - return ConstViewTransformRcPtr(); + return getImpl()->getViewTransform(name); } const char * Config::getViewTransformNameByIndex(int index) const noexcept @@ -2101,7 +2690,9 @@ void Config::addViewTransform(const ConstViewTransformRcPtr & viewTransform) if (!viewTransform->getTransform(VIEWTRANSFORM_DIR_TO_REFERENCE) && !viewTransform->getTransform(VIEWTRANSFORM_DIR_FROM_REFERENCE)) { - throw Exception("Cannot add view transform with no transform."); + std::ostringstream os; + os << "Cannot add view transform '" << name << "' with no transform."; + throw Exception(os.str().c_str()); } const std::string namelower = StringUtils::Lower(name); @@ -2146,11 +2737,6 @@ ConstFileRulesRcPtr Config::getFileRules() const noexcept void Config::setFileRules(ConstFileRulesRcPtr fileRules) { - if (getMajorVersion() < 2) - { - throw Exception("Only config version 2 or higher can accept file rules."); - } - getImpl()->m_fileRules = fileRules->createEditableCopy(); AutoMutex lock(getImpl()->m_cacheidMutex); @@ -2176,23 +2762,23 @@ bool Config::filepathOnlyMatchesDefaultRule(const char * filePath) const /////////////////////////////////////////////////////////////////////////// ConstProcessorRcPtr Config::getProcessor(const ConstColorSpaceRcPtr & src, - const ConstColorSpaceRcPtr & dst) const + const ConstColorSpaceRcPtr & dst) const { ConstContextRcPtr context = getCurrentContext(); return getProcessor(context, src, dst); } ConstProcessorRcPtr Config::getProcessor(const ConstContextRcPtr & context, - const ConstColorSpaceRcPtr & src, - const ConstColorSpaceRcPtr & dst) const + const ConstColorSpaceRcPtr & src, + const ConstColorSpaceRcPtr & dst) const { - if(!src) + if (!src) { - throw Exception("Config::GetProcessor failed. Source color space is null."); + throw Exception("Can't get processor: source color space is null."); } - if(!dst) + if (!dst) { - throw Exception("Config::GetProcessor failed. Destination color space is null."); + throw Exception("Can't get processor: destination color space is null."); } ProcessorRcPtr processor = Processor::Create(); @@ -2233,19 +2819,19 @@ ConstProcessorRcPtr Config::getProcessor(const ConstContextRcPtr & context, } -ConstProcessorRcPtr Config::getProcessor(const char * inputColorSpaceName, +ConstProcessorRcPtr Config::getProcessor(const char * srcColorSpaceName, const char * display, const char * view) const { ConstContextRcPtr context = getCurrentContext(); - return getProcessor(context, inputColorSpaceName, display, view); + return getProcessor(context, srcColorSpaceName, display, view); } ConstProcessorRcPtr Config::getProcessor(const ConstContextRcPtr & context, - const char * inputColorSpaceName, + const char * srcColorSpaceName, const char * display, const char * view) const { - auto dt = DisplayTransform::Create(); - dt->setInputColorSpaceName(inputColorSpaceName); + auto dt = DisplayViewTransform::Create(); + dt->setSrc(srcColorSpaceName); dt->setDisplay(display); dt->setView(view); dt->validate(); @@ -2729,6 +3315,34 @@ void Config::Impl::checkVersionConsistency() const throw Exception("Only version 2 (or higher) can have FileRules."); } + // Check for ViewingRules. + + if (m_majorVersion < 2 && m_viewingRules->getNumEntries() != 0) + { + throw Exception("Only version 2 (or higher) can have viewing rules."); + } + + // Check for shared views. + + if (m_majorVersion < 2) + { + if (m_sharedViews.size() != 0) + { + throw Exception("Only version 2 (or higher) can have shared views."); + } + for (const auto & display : m_displays) + { + const StringUtils::StringVec & sharedViews = display.second.m_sharedViews; + if (!sharedViews.empty()) + { + std::ostringstream os; + os << "Config failed sanitycheck. The display '" << display.first << "' "; + os << "uses shared views and config version is less than 2."; + throw Exception(os.str().c_str()); + } + } + } + // Check for the DisplayColorSpaces. if (m_majorVersion < 2) diff --git a/src/OpenColorIO/Context.cpp b/src/OpenColorIO/Context.cpp index 0d93a6d5b8..06e7faa80f 100644 --- a/src/OpenColorIO/Context.cpp +++ b/src/OpenColorIO/Context.cpp @@ -337,7 +337,7 @@ const char * Context::resolveFileLocation(const char * filename) const } std::ostringstream errortext; errortext << "The specified absolute file reference "; - errortext << "'" << expandedfullpath << "' could not be located. "; + errortext << "'" << expandedfullpath << "' could not be located."; throw Exception(errortext.str().c_str()); } } diff --git a/src/OpenColorIO/CustomKeys.h b/src/OpenColorIO/CustomKeys.h new file mode 100644 index 0000000000..6b93a74d2e --- /dev/null +++ b/src/OpenColorIO/CustomKeys.h @@ -0,0 +1,80 @@ +// SPDX-License-Identifier: BSD-3-Clause +// Copyright Contributors to the OpenColorIO Project. + + +#ifndef INCLUDED_OCIO_CUSTOMKEYS_H +#define INCLUDED_OCIO_CUSTOMKEYS_H + + +#include +#include +#include + +#include + +namespace OCIO_NAMESPACE +{ + +class CustomKeysContainer +{ +public: + CustomKeysContainer() = default; + CustomKeysContainer(const CustomKeysContainer &) = default; + CustomKeysContainer & operator=(const CustomKeysContainer &) = default; + + using CustomKeys = std::map; + + size_t getSize() const noexcept + { + return m_customKeys.size(); + } + + const char * getName(size_t key) const + { + validateIndex(key); + auto cust = std::next(m_customKeys.begin(), key); + return (*cust).first.c_str(); + } + + const char * getValue(size_t key) const + { + validateIndex(key); + auto cust = std::next(m_customKeys.begin(), key); + return (*cust).second.c_str(); + } + + void set(const char * key, const char * value) + { + if (!key || !*key) + { + throw Exception("Key has to be a non-empty string."); + } + if (value && *value) + { + m_customKeys[key] = value; + } + else + { + m_customKeys.erase(key); + } + } + +private: + void validateIndex(size_t key) const + { + const auto numKeys = getSize(); + if (key >= numKeys) + { + std::ostringstream oss; + oss << "Key index '" << key << "' is invalid, there are '" << numKeys + << "' custom keys."; + throw Exception(oss.str().c_str()); + } + } + + CustomKeys m_customKeys; +}; + +} // namespace OCIO_NAMESPACE + +#endif // INCLUDED_OCIO_CUSTOMKEYS_H diff --git a/src/OpenColorIO/Display.cpp b/src/OpenColorIO/Display.cpp index e80f4154a1..4280b99231 100644 --- a/src/OpenColorIO/Display.cpp +++ b/src/OpenColorIO/Display.cpp @@ -7,82 +7,67 @@ #include "Display.h" #include "ParseUtils.h" +#include "Platform.h" namespace OCIO_NAMESPACE { -DisplayMap::iterator find_display(DisplayMap & displays, const std::string & display) +DisplayMap::iterator FindDisplay(DisplayMap & displays, const std::string & name) { - for(DisplayMap::iterator iter = displays.begin(); - iter != displays.end(); - ++iter) - { - if(StrEqualsCaseIgnore(display, iter->first)) return iter; - } - return displays.end(); + return std::find_if(displays.begin(), displays.end(), + [name](DisplayPair & display) + { + return 0 == Platform::Strcasecmp(name.c_str(), display.first.c_str()); + }); } -DisplayMap::const_iterator find_display_const(const DisplayMap & displays, const std::string & display) +DisplayMap::const_iterator FindDisplay(const DisplayMap & displays, const std::string & name) { - for(DisplayMap::const_iterator iter = displays.begin(); - iter != displays.end(); - ++iter) - { - if(StrEqualsCaseIgnore(display, iter->first)) return iter; - } - return displays.end(); + return std::find_if(displays.begin(), displays.end(), + [name](const DisplayPair & display) + { + return 0 == Platform::Strcasecmp(name.c_str(), display.first.c_str()); + }); } -int find_view(const ViewVec & vec, const std::string & name) +ViewVec::const_iterator FindView(const ViewVec & vec, const std::string & name) { - for(unsigned int i=0; isecond; - int index = find_view(views, view); - if (index < 0) - { - views.push_back( View(view, viewTransform, displayColorSpace, looks) ); - } - else - { - views[index].m_viewTransform = viewTransform ? viewTransform : ""; - views[index].m_colorspace = displayColorSpace; - views[index].m_looks = looks ? looks : ""; - } + (*view).m_viewTransform = viewTransform ? viewTransform : ""; + (*view).m_colorspace = displayColorSpace ? displayColorSpace : ""; + (*view).m_looks = looks ? looks : ""; + (*view).m_rule = rule ? rule : ""; + (*view).m_description = description ? description : ""; } } @@ -94,11 +79,9 @@ void ComputeDisplays(StringUtils::StringVec & displayCache, displayCache.clear(); StringUtils::StringVec displayMasterList; - for(DisplayMap::const_iterator iter = displays.begin(); - iter != displays.end(); - ++iter) + for(const auto & display : displays) { - displayMasterList.push_back(iter->first); + displayMasterList.push_back(display.first); } // Apply the env override if it's not empty. diff --git a/src/OpenColorIO/Display.h b/src/OpenColorIO/Display.h index 9d6d214077..4729bc4efa 100644 --- a/src/OpenColorIO/Display.h +++ b/src/OpenColorIO/Display.h @@ -11,6 +11,7 @@ #include +#include "Platform.h" #include "PrivateTypes.h" #include "utils/StringUtils.h" @@ -18,46 +19,69 @@ namespace OCIO_NAMESPACE { -// Displays +// View can be part of the list of views of a display or the list of shared views of a config. struct View { std::string m_name; - std::string m_viewTransform; // Added for v2, might be empty. + std::string m_viewTransform; // Might be empty. std::string m_colorspace; - std::string m_looks; + std::string m_looks; // Might be empty. + std::string m_rule; // Might be empty. + std::string m_description; // Might be empty. View() = default; View(const char * name, const char * viewTransform, const char * colorspace, - const char * looks) + const char * looks, + const char * rule, + const char * description) : m_name(name) , m_viewTransform(viewTransform ? viewTransform : "") - , m_colorspace(colorspace) + , m_colorspace(colorspace ? colorspace : "") , m_looks(looks ? looks : "") + , m_rule(rule ? rule : "") + , m_description(description ? description : "") { } + + // Make sure that csname is not null. + static bool UseDisplayName(const char * csname) + { + return csname && 0 == Platform::Strcasecmp(csname, OCIO_VIEW_USE_DISPLAY_NAME); + } + bool useDisplayNameForColorspace() const + { + return UseDisplayName(m_colorspace.c_str()); + } }; typedef std::vector ViewVec; +ViewVec::const_iterator FindView(const ViewVec & vec, const std::string & name); +ViewVec::iterator FindView(ViewVec & vec, const std::string & name); + +void AddView(ViewVec & views, const char * name, const char * viewTransform, + const char * displayColorSpace, const char * looks, + const char * rule, const char * description); + +// Display can be part of the list of displays (DisplayMap) of a config. +struct Display +{ + // List of views defined by the display. + ViewVec m_views; + // List of references to shared views defined be a config. + StringUtils::StringVec m_sharedViews; +}; + // In 0.6, the Yaml lib changed their implementation of a Yaml::Map from a C++ map // to a std::vector< std::pair<> >. We made the same change here so that the Display list // can remain in config order but we left the "Map" in the name since it refers to a Yaml::Map. -typedef std::vector> DisplayMap; // Pair is (display name : ViewVec) - -DisplayMap::iterator find_display(DisplayMap & displays, const std::string & display); -DisplayMap::const_iterator find_display_const(const DisplayMap & displays, const std::string & display); - -int find_view(const ViewVec & vec, const std::string & name); +typedef std::pair DisplayPair; +typedef std::vector DisplayMap; // Pair is (display name : ViewVec) -// Note: displayColorSpace has to be a display-referred color space if viewTransform is not empty. -void AddDisplay(DisplayMap & displays, - const char * display, - const char * view, - const char * viewTransform, - const char * displayColorSpace, - const char * looks); +DisplayMap::iterator FindDisplay(DisplayMap & displays, const std::string & display); +DisplayMap::const_iterator FindDisplay(const DisplayMap & displays, const std::string & display); void ComputeDisplays(StringUtils::StringVec & displayCache, const DisplayMap & displays, diff --git a/src/OpenColorIO/FileRules.cpp b/src/OpenColorIO/FileRules.cpp index ae869c14df..3b9a9e0757 100644 --- a/src/OpenColorIO/FileRules.cpp +++ b/src/OpenColorIO/FileRules.cpp @@ -9,6 +9,7 @@ #include +#include "CustomKeys.h" #include "FileRules.h" #include "PathUtils.h" #include "Platform.h" @@ -91,32 +92,34 @@ std::string ConvertToRegularExpression(const char * globPattern, bool ignoreCase std::string regexPattern; const size_t globSize = globString.size(); - for (size_t i = 0; i < globSize; ++i) + size_t nextIdx = 0; + for (size_t idx = 0; idx < globSize; idx = nextIdx) { - if (globString[i] == '.') { regexPattern += "\\."; continue; } - if (globString[i] == '?') { regexPattern += "."; continue; } - if (globString[i] == '*') { regexPattern += ".*"; continue; } + nextIdx = idx + 1; + if (globString[idx] == '.') { regexPattern += "\\."; continue; } + if (globString[idx] == '?') { regexPattern += "."; continue; } + if (globString[idx] == '*') { regexPattern += ".*"; continue; } // Escape regex characters. - if (globString[i] == '+') { regexPattern += "\\+"; continue; } - if (globString[i] == '^') { regexPattern += "\\^"; continue; } - if (globString[i] == '$') { regexPattern += "\\$"; continue; } - if (globString[i] == '{') { regexPattern += "\\{"; continue; } - if (globString[i] == '}') { regexPattern += "\\}"; continue; } - if (globString[i] == '(') { regexPattern += "\\("; continue; } - if (globString[i] == ')') { regexPattern += "\\)"; continue; } - if (globString[i] == '|') { regexPattern += "\\|"; continue; } - - if (globString[i] == ']') + if (globString[idx] == '+') { regexPattern += "\\+"; continue; } + if (globString[idx] == '^') { regexPattern += "\\^"; continue; } + if (globString[idx] == '$') { regexPattern += "\\$"; continue; } + if (globString[idx] == '{') { regexPattern += "\\{"; continue; } + if (globString[idx] == '}') { regexPattern += "\\}"; continue; } + if (globString[idx] == '(') { regexPattern += "\\("; continue; } + if (globString[idx] == ')') { regexPattern += "\\)"; continue; } + if (globString[idx] == '|') { regexPattern += "\\|"; continue; } + + if (globString[idx] == ']') { - ThrowInvalidRegex(globPattern, globPattern + i); + ThrowInvalidRegex(globPattern, globPattern + idx); } // Full processing from '[' to ']'. - if (globString[i] == '[') + if (globString[idx] == '[') { std::string subString("["); - size_t end = i + 1; // +1 to bypass the '[' + size_t end = idx + 1; // +1 to bypass the '[' while (globString[end] != ']' && end < globSize) { if (globString[end] == '!') @@ -146,13 +149,13 @@ std::string ConvertToRegularExpression(const char * globPattern, bool ignoreCase { if (globString[end - 1] != '\\') { - ThrowInvalidRegex(globPattern, &globString[i]); + ThrowInvalidRegex(globPattern, &globString[idx]); } subString += globString[end]; } else if (globString[end] == '[') { - ThrowInvalidRegex(globPattern, &globString[i]); + ThrowInvalidRegex(globPattern, &globString[idx]); } else { @@ -169,7 +172,7 @@ std::string ConvertToRegularExpression(const char * globPattern, bool ignoreCase if (end >= globSize) { - ThrowInvalidRegex(globPattern, &globString[i]); + ThrowInvalidRegex(globPattern, &globString[idx]); } else if (subString == "[]") { @@ -182,11 +185,11 @@ std::string ConvertToRegularExpression(const char * globPattern, bool ignoreCase // Keep the result. regexPattern += subString; - i = end; + nextIdx = end + 1; continue; } - regexPattern += globString[i]; + regexPattern += globString[idx]; } return regexPattern; @@ -274,8 +277,6 @@ class FileRule FILE_RULE_GLOB }; - using CustomKeys = std::map; - FileRule() = delete; FileRule(const FileRule &) = delete; FileRule & operator=(const FileRule &) = delete; @@ -298,12 +299,12 @@ class FileRule FileRuleRcPtr clone() const { FileRuleRcPtr rule = std::make_shared(m_name.c_str()); - + + rule->m_customKeys = m_customKeys; rule->m_colorSpace = m_colorSpace; rule->m_pattern = m_pattern; rule->m_extension = m_extension; rule->m_regex = m_regex; - rule->m_customKeys = m_customKeys; rule->m_type = m_type; return rule; @@ -424,43 +425,6 @@ class FileRule } } - size_t getNumCustomKeys() const - { - return m_customKeys.size(); - } - - const char * getCustomKeyName(size_t key) const - { - validateKeyIndex(key); - auto cust = std::next(m_customKeys.begin(), key); - return (*cust).first.c_str(); - } - - const char * getCustomKeyValue(size_t key) const - { - validateKeyIndex(key); - auto cust = std::next(m_customKeys.begin(), key); - return (*cust).second.c_str(); - } - - void setCustomKey(const char * key, const char * value) - { - if (!key || !*key) - { - std::ostringstream oss; - oss << "File rules: rule named '" << m_name << "': key has to be a non empty string."; - throw Exception(oss.str().c_str()); - } - if (value && *value) - { - m_customKeys[key] = value; - } - else - { - m_customKeys.erase(key); - } - } - bool matches(const Config & config, const char * path) const { switch (m_type) @@ -509,25 +473,15 @@ class FileRule } } + CustomKeysContainer m_customKeys; + private: - void validateKeyIndex(size_t key) const - { - const auto numKeys = getNumCustomKeys(); - if (key >= numKeys) - { - std::ostringstream oss; - oss << "File rules: rule named '" << m_name << "': key index '" << key - << "' is invalid, there are '" << numKeys << "' custom keys."; - throw Exception(oss.str().c_str()); - } - } std::string m_name; mutable std::string m_colorSpace; std::string m_pattern; std::string m_extension; std::string m_regex; - CustomKeys m_customKeys; RuleType m_type{ FILE_RULE_GLOB }; }; @@ -603,7 +557,7 @@ void FileRules::Impl::validateNewRule(size_t ruleIndex, const char * name) const { if (!name || !*name) { - throw Exception("File rules: rule should have a non empty name."); + throw Exception("File rules: rule should have a non-empty name."); } auto existingRule = std::find_if(m_rules.begin(), m_rules.end(), [name](const FileRuleRcPtr & rule) @@ -746,25 +700,57 @@ void FileRules::setColorSpace(size_t ruleIndex, const char * colorSpace) size_t FileRules::getNumCustomKeys(size_t ruleIndex) const { m_impl->validatePosition(ruleIndex, Impl::DEFAULT_ALLOWED); - return m_impl->m_rules[ruleIndex]->getNumCustomKeys(); + return m_impl->m_rules[ruleIndex]->m_customKeys.getSize(); } const char * FileRules::getCustomKeyName(size_t ruleIndex, size_t key) const { m_impl->validatePosition(ruleIndex, Impl::DEFAULT_ALLOWED); - return m_impl->m_rules[ruleIndex]->getCustomKeyName(key); + try + { + return m_impl->m_rules[ruleIndex]->m_customKeys.getName(key); + } + catch (Exception & e) + { + std::ostringstream oss; + oss << "File rules: the custom key access for file rule '" + << std::string(m_impl->m_rules[ruleIndex]->getName()) + << "' failed: " << e.what(); + throw Exception(oss.str().c_str()); + } } const char * FileRules::getCustomKeyValue(size_t ruleIndex, size_t key) const { m_impl->validatePosition(ruleIndex, Impl::DEFAULT_ALLOWED); - return m_impl->m_rules[ruleIndex]->getCustomKeyValue(key); + try + { + return m_impl->m_rules[ruleIndex]->m_customKeys.getValue(key); + } + catch (Exception & e) + { + std::ostringstream oss; + oss << "File rules: the custom key access for file rule '" + << std::string(m_impl->m_rules[ruleIndex]->getName()) + << "' failed: " << e.what(); + throw Exception(oss.str().c_str()); + } } void FileRules::setCustomKey(size_t ruleIndex, const char * key, const char * value) { m_impl->validatePosition(ruleIndex, Impl::DEFAULT_ALLOWED); - m_impl->m_rules[ruleIndex]->setCustomKey(key, value); + try + { + m_impl->m_rules[ruleIndex]->m_customKeys.set(key, value); + } + catch (Exception & e) + { + std::ostringstream oss; + oss << "File rules: rule named '" << std::string(m_impl->m_rules[ruleIndex]->getName()) + << "' error: " << e.what(); + throw Exception(oss.str().c_str()); + } } void FileRules::insertRule(size_t ruleIndex, const char * name, const char * colorSpace, @@ -840,5 +826,54 @@ bool FileRules::Impl::filepathOnlyMatchesDefaultRule(const Config & config, cons return (rulePos + 1) == m_rules.size(); } +std::ostream & operator<< (std::ostream & os, const FileRules & fr) +{ + const size_t numRules = fr.getNumEntries(); + for (size_t r = 0; r < numRules; ++r) + { + os << ""; + if (r + 1 != numRules) + { + os << "\n"; + } + } + return os; +} } // namespace OCIO_NAMESPACE diff --git a/src/OpenColorIO/LookParse.cpp b/src/OpenColorIO/LookParse.cpp index d0e5427ec3..809d0e89b0 100644 --- a/src/OpenColorIO/LookParse.cpp +++ b/src/OpenColorIO/LookParse.cpp @@ -79,7 +79,7 @@ const LookParseResult::Options & LookParseResult::parse(const std::string & look LookParseResult::Tokens tokens; vec.clear(); - SplitStringEnvStyle(vec, options[optionsindex].c_str()); + vec = SplitStringEnvStyle(options[optionsindex]); for(unsigned int i=0; ifirst; const YAML::Node& second = iter->second; @@ -347,6 +346,16 @@ inline void load(const YAML::Node& node, View& v) load(second, stringval); v.m_looks = stringval; } + else if (key == "rule") + { + load(second, stringval); + v.m_rule = stringval; + } + else if (key == "description") + { + load(second, stringval); + v.m_description = stringval; + } else { LogUnknownKeyWarning(node, first); @@ -390,6 +399,14 @@ inline void save(YAML::Emitter& out, const View & view) { out << YAML::Key << "looks" << YAML::Value << view.m_looks; } + if (!view.m_rule.empty()) + { + out << YAML::Key << "rule" << YAML::Value << view.m_rule; + } + if (!view.m_description.empty()) + { + out << YAML::Key << "description" << YAML::Value << view.m_description; + } out << YAML::EndMap; } @@ -406,6 +423,17 @@ inline void EmitBaseTransformKeyValues(YAML::Emitter & out, } } +inline void EmitTransformName(YAML::Emitter & out, + const FormatMetadata & metadata) +{ + const FormatMetadataImpl data = dynamic_cast(metadata); + const std::string & name{ data.getAttributeValue(METADATA_NAME) }; + if (!name.empty()) + { + out << YAML::Key << "name" << YAML::Value << name; + } +} + // AllocationTransform inline void load(const YAML::Node& node, AllocationTransformRcPtr& t) @@ -601,6 +629,12 @@ inline void load(const YAML::Node& node, CDLTransformRcPtr& t) load(second, val); t->setDirection(val); } + else if (key == "name") + { + std::string name; + load(second, name); + t->getFormatMetadata().addAttribute(METADATA_NAME, name.c_str()); + } else { LogUnknownKeyWarning(node, first); @@ -613,6 +647,8 @@ inline void save(YAML::Emitter& out, ConstCDLTransformRcPtr t) out << YAML::VerbatimTag("CDLTransform"); out << YAML::Flow << YAML::BeginMap; + EmitTransformName(out, t->getFormatMetadata()); + std::vector slope(3); t->getSlope(&slope[0]); if (!IsVecEqualToOne(&slope[0], 3)) @@ -688,6 +724,12 @@ inline void load(const YAML::Node& node, ColorSpaceTransformRcPtr& t) load(second, val); t->setDirection(val); } + else if(key == "data_bypass") + { + bool val; + load(second, val); + t->setDataBypass(val); + } else { LogUnknownKeyWarning(node, first); @@ -701,6 +743,92 @@ inline void save(YAML::Emitter& out, ConstColorSpaceTransformRcPtr t) out << YAML::Flow << YAML::BeginMap; out << YAML::Key << "src" << YAML::Value << t->getSrc(); out << YAML::Key << "dst" << YAML::Value << t->getDst(); + const bool bypass = t->getDataBypass(); + if (!bypass) + { + out << YAML::Key << "data_bypass" << YAML::Value << bypass; + } + + EmitBaseTransformKeyValues(out, t); + out << YAML::EndMap; +} + +// DisplayViewTransform + +inline void load(const YAML::Node& node, DisplayViewTransformRcPtr& t) +{ + t = DisplayViewTransform::Create(); + + std::string key, stringval; + bool boolval{ true }; + + for (Iterator iter = node.begin(); + iter != node.end(); + ++iter) + { + const YAML::Node& first = iter->first; + const YAML::Node& second = iter->second; + + load(first, key); + + if (second.IsNull() || !second.IsDefined()) continue; + + if (key == "src") + { + load(second, stringval); + t->setSrc(stringval.c_str()); + } + else if (key == "display") + { + load(second, stringval); + t->setDisplay(stringval.c_str()); + } + else if (key == "view") + { + load(second, stringval); + t->setView(stringval.c_str()); + } + else if (key == "direction") + { + TransformDirection val; + load(second, val); + t->setDirection(val); + } + else if (key == "looks_bypass") + { + load(second, boolval); + t->setLooksBypass(boolval); + } + else if (key == "data_bypass") + { + load(second, boolval); + t->setDataBypass(boolval); + } + else + { + LogUnknownKeyWarning(node, first); + } + } +} + +inline void save(YAML::Emitter& out, ConstDisplayViewTransformRcPtr t) +{ + out << YAML::VerbatimTag("DisplayViewTransform"); + out << YAML::Flow << YAML::BeginMap; + out << YAML::Key << "src" << YAML::Value << t->getSrc(); + out << YAML::Key << "display" << YAML::Value << t->getDisplay(); + out << YAML::Key << "view" << YAML::Value << t->getView(); + const bool looksBypass = t->getLooksBypass(); + if (looksBypass) + { + out << YAML::Key << "looks_bypass" << YAML::Value << looksBypass; + } + const bool dataBypass = t->getDataBypass(); + if (!dataBypass) + { + out << YAML::Key << "data_bypass" << YAML::Value << dataBypass; + } + EmitBaseTransformKeyValues(out, t); out << YAML::EndMap; } @@ -761,6 +889,12 @@ inline void load(const YAML::Node& node, ExponentTransformRcPtr& t) load(second, val); t->setDirection(val); } + else if(key == "name") + { + std::string name; + load(second, name); + t->getFormatMetadata().addAttribute(METADATA_NAME, name.c_str()); + } else { LogUnknownKeyWarning(node, first); @@ -773,6 +907,8 @@ inline void save(YAML::Emitter& out, ConstExponentTransformRcPtr t) out << YAML::VerbatimTag("ExponentTransform"); out << YAML::Flow << YAML::BeginMap; + EmitTransformName(out, t->getFormatMetadata()); + double value[4]; t->getValue(value); if (value[0] == value[1] && value[0] == value[2] && value[3] == 1.) @@ -897,6 +1033,12 @@ inline void load(const YAML::Node& node, ExponentWithLinearTransformRcPtr& t) load(second, val); t->setDirection(val); } + else if(key == "name") + { + std::string name; + load(second, name); + t->getFormatMetadata().addAttribute(METADATA_NAME, name.c_str()); + } else { LogUnknownKeyWarning(node.Tag(), first); @@ -928,6 +1070,8 @@ inline void save(YAML::Emitter& out, ConstExponentWithLinearTransformRcPtr t) out << YAML::VerbatimTag("ExponentWithLinearTransform"); out << YAML::Flow << YAML::BeginMap; + EmitTransformName(out, t->getFormatMetadata()); + std::vector v; double gamma[4]; @@ -1091,6 +1235,12 @@ inline void load(const YAML::Node& node, ExposureContrastTransformRcPtr& t) load(second, val); t->setDirection(val); } + else if (key == "name") + { + std::string name; + load(second, name); + t->getFormatMetadata().addAttribute(METADATA_NAME, name.c_str()); + } else { LogUnknownKeyWarning(node, first); @@ -1120,6 +1270,8 @@ inline void save(YAML::Emitter& out, ConstExposureContrastTransformRcPtr t) out << YAML::VerbatimTag("ExposureContrastTransform"); out << YAML::Flow << YAML::BeginMap; + EmitTransformName(out, t->getFormatMetadata()); + out << YAML::Key << "style"; out << YAML::Value << YAML::Flow << ExposureContrastStyleToString(t->getStyle()); @@ -1260,6 +1412,12 @@ inline void load(const YAML::Node& node, FixedFunctionTransformRcPtr& t) load(second, val); t->setDirection(val); } + else if(key == "name") + { + std::string name; + load(second, name); + t->getFormatMetadata().addAttribute(METADATA_NAME, name.c_str()); + } else { LogUnknownKeyWarning(node.Tag(), first); @@ -1272,6 +1430,8 @@ inline void save(YAML::Emitter& out, ConstFixedFunctionTransformRcPtr t) out << YAML::VerbatimTag("FixedFunctionTransform"); out << YAML::Flow << YAML::BeginMap; + EmitTransformName(out, t->getFormatMetadata()); + out << YAML::Key << "style"; out << YAML::Value << YAML::Flow << FixedFunctionStyleToString(t->getStyle()); @@ -1334,6 +1494,12 @@ inline void load(const YAML::Node& node, GroupTransformRcPtr& t) load(second, val); t->setDirection(val); } + else if(key == "name") + { + std::string name; + load(second, name); + t->getFormatMetadata().addAttribute(METADATA_NAME, name.c_str()); + } else { LogUnknownKeyWarning(node, first); @@ -1345,6 +1511,8 @@ inline void save(YAML::Emitter& out, ConstGroupTransformRcPtr t) { out << YAML::VerbatimTag("GroupTransform"); out << YAML::BeginMap; + + EmitTransformName(out, t->getFormatMetadata()); EmitBaseTransformKeyValues(out, t); out << YAML::Key << "children"; @@ -1451,6 +1619,12 @@ inline void load(const YAML::Node& node, LogAffineTransformRcPtr& t) load(second, val); t->setDirection(val); } + else if(key == "name") + { + std::string name; + load(second, name); + t->getFormatMetadata().addAttribute(METADATA_NAME, name.c_str()); + } else { LogUnknownKeyWarning(node, first); @@ -1489,6 +1663,8 @@ inline void save(YAML::Emitter& out, ConstLogAffineTransformRcPtr t) out << YAML::VerbatimTag("LogAffineTransform"); out << YAML::Flow << YAML::BeginMap; + EmitTransformName(out, t->getFormatMetadata()); + double logSlope[3] = { 1.0, 1.0, 1.0 }; double linSlope[3] = { 1.0, 1.0, 1.0 }; double linOffset[3] = { 0.0, 0.0, 0.0 }; @@ -1587,6 +1763,12 @@ inline void load(const YAML::Node & node, LogCameraTransformRcPtr & t) load(second, val); t->setDirection(val); } + else if (key == "name") + { + std::string name; + load(second, name); + t->getFormatMetadata().addAttribute(METADATA_NAME, name.c_str()); + } else { LogUnknownKeyWarning(node, first); @@ -1613,6 +1795,8 @@ inline void save(YAML::Emitter& out, ConstLogCameraTransformRcPtr t) out << YAML::VerbatimTag("LogCameraTransform"); out << YAML::Flow << YAML::BeginMap; + EmitTransformName(out, t->getFormatMetadata()); + double logSlope[3] = { 1.0, 1.0, 1.0 }; double linSlope[3] = { 1.0, 1.0, 1.0 }; double linOffset[3] = { 0.0, 0.0, 0.0 }; @@ -1687,6 +1871,12 @@ inline void load(const YAML::Node& node, LogTransformRcPtr& t) load(second, val); t->setDirection(val); } + else if (key == "name") + { + std::string name; + load(second, name); + t->getFormatMetadata().addAttribute(METADATA_NAME, name.c_str()); + } else { LogUnknownKeyWarning(node.Tag(), first); @@ -1698,6 +1888,9 @@ inline void save(YAML::Emitter& out, ConstLogTransformRcPtr t) { out << YAML::VerbatimTag("LogTransform"); out << YAML::Flow << YAML::BeginMap; + + EmitTransformName(out, t->getFormatMetadata()); + const double baseVal = t->getBase(); if (baseVal != 2.0) { @@ -1816,6 +2009,12 @@ inline void load(const YAML::Node& node, MatrixTransformRcPtr& t) load(second, val); t->setDirection(val); } + else if(key == "name") + { + std::string name; + load(second, name); + t->getFormatMetadata().addAttribute(METADATA_NAME, name.c_str()); + } else { LogUnknownKeyWarning(node, first); @@ -1828,6 +2027,8 @@ inline void save(YAML::Emitter& out, ConstMatrixTransformRcPtr t) out << YAML::VerbatimTag("MatrixTransform"); out << YAML::Flow << YAML::BeginMap; + EmitTransformName(out, t->getFormatMetadata()); + std::vector matrix(16, 0.0); t->getMatrix(&matrix[0]); if(!IsM44Identity(&matrix[0])) @@ -1904,6 +2105,12 @@ inline void load(const YAML::Node& node, RangeTransformRcPtr& t) load(second, dir); t->setDirection(dir); } + else if(key == "name") + { + std::string name; + load(second, name); + t->getFormatMetadata().addAttribute(METADATA_NAME, name.c_str()); + } else { LogUnknownKeyWarning(node, first); @@ -1916,6 +2123,8 @@ inline void save(YAML::Emitter& out, ConstRangeTransformRcPtr t) out << YAML::VerbatimTag("RangeTransform"); out << YAML::Flow << YAML::BeginMap; + EmitTransformName(out, t->getFormatMetadata()); + if(t->hasMinInValue()) { out << YAML::Key << "minInValue"; @@ -1989,7 +2198,12 @@ void load(const YAML::Node& node, TransformRcPtr& t) load(node, temp); t = temp; } - // TODO: DisplayTransform + else if (type == "DisplayViewTransform") + { + DisplayViewTransformRcPtr temp; + load(node, temp); + t = temp; + } else if(type == "ExponentTransform") { ExponentTransformRcPtr temp; @@ -2094,6 +2308,9 @@ void save(YAML::Emitter& out, ConstTransformRcPtr t) else if(ConstColorSpaceTransformRcPtr ColorSpace_tran = \ DynamicPtrCast(t)) save(out, ColorSpace_tran); + else if (ConstDisplayViewTransformRcPtr Display_tran = \ + DynamicPtrCast(t)) + save(out, Display_tran); else if(ConstExponentTransformRcPtr Exponent_tran = \ DynamicPtrCast(t)) save(out, Exponent_tran); @@ -2203,6 +2420,11 @@ inline void load(const YAML::Node& node, ColorSpaceRcPtr& cs) cs->addCategory(name.c_str()); } } + else if (key == "encoding") + { + load(second, stringval); + cs->setEncoding(stringval.c_str()); + } else if(key == "allocation") { Allocation val; @@ -2293,6 +2515,13 @@ inline void save(YAML::Emitter& out, ConstColorSpaceRcPtr cs) out << YAML::Flow << YAML::Value << categories; } + const std::string is{ cs->getEncoding() }; + if (!is.empty()) + { + out << YAML::Key << "encoding"; + out << YAML::Value << is; + } + out << YAML::Key << "allocation" << YAML::Value; save(out, cs->getAllocation()); if(cs->getAllocationNumVars() > 0) @@ -2763,6 +2992,154 @@ inline void save(YAML::Emitter & out, ConstFileRulesRcPtr & fr, size_t position) out << YAML::EndMap; } +// Viewing rules + +inline void load(const YAML::Node & node, ViewingRulesRcPtr & vr) +{ + if (node.Tag() != "Rule") + return; + + std::string key, stringval; + std::string name; + StringUtils::StringVec colorspaces, encodings; + StringUtils::StringVec keyVals; + + for (const auto & iter : node) + { + const YAML::Node & first = iter.first; + const YAML::Node & second = iter.second; + + load(first, key); + + if (second.IsNull() || !second.IsDefined()) continue; + + if (key == ViewingRuleUtils::Name) + { + load(second, stringval); + name = stringval; + } + else if (key == ViewingRuleUtils::ColorSpaces) + { + if (second.Type() == YAML::NodeType::Sequence) + { + load(second, colorspaces); + } + else + { + // If a single value is supplied... + load(second, stringval); + colorspaces.emplace_back(stringval); + } + } + else if (key == ViewingRuleUtils::Encodings) + { + if (second.Type() == YAML::NodeType::Sequence) + { + load(second, encodings); + } + else + { + // If a single value is supplied... + load(second, stringval); + encodings.emplace_back(stringval); + } + } + else if (key == ViewingRuleUtils::CustomKey) + { + CustomKeysLoader kv; + loadCustomKeys(second, kv); + keyVals = kv.m_keyVals; + } + else + { + LogUnknownKeyWarning(node, first); + } + } + + try + { + const auto pos = vr->getNumEntries(); + vr->insertRule(pos, name.c_str()); + + for (const auto & cs : colorspaces) + { + vr->addColorSpace(pos, cs.c_str()); + } + for (const auto & is : encodings) + { + vr->addEncoding(pos, is.c_str()); + } + + const auto numKeyVal = keyVals.size() / 2; + for (size_t i = 0; i < numKeyVal; ++i) + { + vr->setCustomKey(pos, keyVals[i * 2].c_str(), keyVals[i * 2 + 1].c_str()); + } + } + catch (Exception & ex) + { + std::ostringstream os; + os << "File rules: " << ex.what(); + throwError(node, os.str().c_str()); + } +} + +inline void save(YAML::Emitter & out, ConstViewingRulesRcPtr & vr, size_t position) +{ + out << YAML::VerbatimTag("Rule"); + out << YAML::Flow; + out << YAML::BeginMap; + out << YAML::Key << ViewingRuleUtils::Name << YAML::Value << vr->getName(position); + const size_t numcs = vr->getNumColorSpaces(position); + if (numcs == 1) + { + out << YAML::Key << ViewingRuleUtils::ColorSpaces; + out << YAML::Value << vr->getColorSpace(position, 0); + } + else if (numcs > 1) + { + StringUtils::StringVec colorspaces; + for (size_t i = 0; i < numcs; ++i) + { + colorspaces.emplace_back(vr->getColorSpace(position, i)); + } + out << YAML::Key << ViewingRuleUtils::ColorSpaces; + out << YAML::Value << YAML::Flow << colorspaces; + } + const size_t numenc = vr->getNumEncodings(position); + if (numenc == 1) + { + out << YAML::Key << ViewingRuleUtils::Encodings; + out << YAML::Value << vr->getEncoding(position, 0); + } + else if (numenc > 1) + { + StringUtils::StringVec encodings; + for (size_t i = 0; i < numenc; ++i) + { + encodings.emplace_back(vr->getEncoding(position, i)); + } + out << YAML::Key << ViewingRuleUtils::Encodings; + out << YAML::Value << YAML::Flow << encodings; + } + const auto numKeys = vr->getNumCustomKeys(position); + if (numKeys) + { + out << YAML::Key << ViewingRuleUtils::CustomKey; + out << YAML::Value; + out << YAML::BeginMap; + + for (size_t i = 0; i < numKeys; ++i) + { + out << YAML::Key << vr->getCustomKeyName(position, i) + << YAML::Value << vr->getCustomKeyValue(position, i); + } + out << YAML::EndMap; + } + out << YAML::EndMap; +} + + // Config inline void load(const YAML::Node& node, ConfigRcPtr & config, const char* filename) @@ -2839,9 +3216,9 @@ inline void load(const YAML::Node& node, ConfigRcPtr & config, const char* filen LogWarning(os.str()); } - bool rulesFound = false; - bool defaultRuleFound = false; - auto rules = config->getFileRules()->createEditableCopy(); + bool fileRulesFound = false; + bool defaultFileRuleFound = false; + auto fileRules = config->getFileRules()->createEditableCopy(); CheckDuplicates(node); @@ -2961,12 +3338,12 @@ inline void load(const YAML::Node& node, ConfigRcPtr & config, const char* filen { if (val.Tag() == "Rule") { - if (defaultRuleFound) + if (defaultFileRuleFound) { throwError(second, "The 'file_rules' Default rule has to be " "the last rule."); } - load(val, rules, defaultRuleFound); + load(val, fileRules, defaultFileRuleFound); } else { @@ -2977,13 +3354,60 @@ inline void load(const YAML::Node& node, ConfigRcPtr & config, const char* filen } } - if (!defaultRuleFound) + if (!defaultFileRuleFound) { throwError(first, "The 'file_rules' does not contain a Default ."); } - rulesFound = true; + fileRulesFound = true; + } + else if (key == "viewing_rules") + { + if (config->getMajorVersion() < 2) + { + throwError(first, "Config v1 can't use 'viewing_rules'."); + } + + if (second.Type() != YAML::NodeType::Sequence) + { + throwError(second, "The 'viewing_rules' field needs to be a (- !) list."); + } + + auto viewingRules = ViewingRules::Create(); + for (const auto & val : second) + { + if (val.Tag() == "Rule") + { + load(val, viewingRules); + } + else + { + std::ostringstream os; + os << "Unknown element found in viewing_rules:"; + os << val.Tag() << ". Only Rule(s) are currently handled."; + LogWarning(os.str()); + } + } + + config->setViewingRules(viewingRules); + } + else if (key == "shared_views") + { + if (second.Type() != YAML::NodeType::Sequence) + { + throwValueError(node.Tag(), first, "The view list is a sequence."); + } + + for (const auto & val : second) + { + View view; + load(val, view); + config->addSharedView(view.m_name.c_str(), + view.m_viewTransform.c_str(), view.m_colorspace.c_str(), + view.m_looks.c_str(), view.m_rule.c_str(), + view.m_description.c_str()); + } } - else if(key == "displays") + else if (key == "displays") { if(second.Type() != YAML::NodeType::Map) { @@ -3003,10 +3427,24 @@ inline void load(const YAML::Node& node, ConfigRcPtr & config, const char* filen for (const auto & val : dsecond) { - View view; - load(val, view); - config->addDisplay(display.c_str(), view.m_name.c_str(), view.m_viewTransform.c_str(), - view.m_colorspace.c_str(), view.m_looks.c_str()); + if (val.Tag() == "View") + { + View view; + load(val, view); + config->addDisplayView(display.c_str(), view.m_name.c_str(), + view.m_viewTransform.c_str(), view.m_colorspace.c_str(), + view.m_looks.c_str(), view.m_rule.c_str(), + view.m_description.c_str()); + } + else if (val.Tag() == "Views") + { + StringUtils::StringVec views; + load(val, views); + for (const auto & sharedView : views) + { + config->addDisplaySharedView(display.c_str(), sharedView.c_str()); + } + } } } } @@ -3163,7 +3601,7 @@ inline void load(const YAML::Node& node, ConfigRcPtr & config, const char* filen } auto defaultCS = config->getColorSpace(ROLE_DEFAULT); - if (!rulesFound) + if (!fileRulesFound) { if (!defaultCS && config->getMajorVersion() >= 2) { @@ -3176,8 +3614,8 @@ inline void load(const YAML::Node& node, ConfigRcPtr & config, const char* filen // If default role is also defined. if (defaultCS) { - const auto defaultRule = rules->getNumEntries() - 1; - const std::string defaultRuleCS{ rules->getColorSpace(defaultRule) }; + const auto defaultRule = fileRules->getNumEntries() - 1; + const std::string defaultRuleCS{ fileRules->getColorSpace(defaultRule) }; if (defaultRuleCS != ROLE_DEFAULT) { if (defaultRuleCS != defaultCS->getName()) @@ -3190,7 +3628,7 @@ inline void load(const YAML::Node& node, ConfigRcPtr & config, const char* filen } } } - config->setFileRules(rules); + config->setFileRules(fileRules); } config->setEnvironmentMode(mode); @@ -3332,28 +3770,77 @@ inline void save(YAML::Emitter & out, const Config & config) out << YAML::Newline; } - // Displays + // Viewing rules + if (configMajorVersion >= 2) + { + auto rules = config.getViewingRules(); + const auto numRules = rules->getNumEntries(); + if (numRules) + { + out << YAML::Newline; + out << YAML::Key << "viewing_rules"; + out << YAML::Value << YAML::BeginSeq; + for (size_t i = 0; i < numRules; ++i) + { + save(out, rules, i); + } + out << YAML::EndSeq; + out << YAML::Newline; + } + } + + // Shared views + const int numSharedViews = config.getNumViews(VIEW_SHARED, nullptr); + if (numSharedViews) + { + out << YAML::Newline; + out << YAML::Key << "shared_views"; + out << YAML::Value << YAML::BeginSeq; + for (int v = 0; v < numSharedViews; ++v) + { + const char * name = config.getView(VIEW_SHARED, nullptr, v); + const View dview{ name, + config.getDisplayViewTransformName(nullptr, name), + config.getDisplayViewColorSpaceName(nullptr, name), + config.getDisplayViewLooks(nullptr, name), + config.getDisplayViewRule(nullptr, name), + config.getDisplayViewDescription(nullptr, name) }; + save(out, dview); + } + out << YAML::EndSeq; + out << YAML::Newline; + } + + // Displays. out << YAML::Newline; out << YAML::Key << "displays"; out << YAML::Value << YAML::BeginMap; - for(int i = 0; i < config.getNumDisplays(); ++i) + // All displays are saved (not just active ones). + for(int i = 0; i < config.getNumDisplaysAll(); ++i) { - const char* display = config.getDisplay(i); + const char* display = config.getDisplayAll(i); out << YAML::Key << display; out << YAML::Value << YAML::BeginSeq; - for(int v = 0; v < config.getNumViews(display); ++v) - { - View dview; - dview.m_name = config.getView(display, v); - dview.m_viewTransform = config.getDisplayViewTransformName(display, - dview.m_name.c_str()); - dview.m_colorspace = config.getDisplayColorSpaceName(display, dview.m_name.c_str()); - if(config.getDisplayLooks(display, dview.m_name.c_str()) != NULL) - { - dview.m_looks = config.getDisplayLooks(display, dview.m_name.c_str()); - } + for(int v = 0; v < config.getNumViews(VIEW_DISPLAY_DEFINED, display); ++v) + { + const char * name = config.getView(VIEW_DISPLAY_DEFINED, display, v); + const View dview{ name, + config.getDisplayViewTransformName(display, name), + config.getDisplayViewColorSpaceName(display, name), + config.getDisplayViewLooks(display, name), + config.getDisplayViewRule(display, name), + config.getDisplayViewDescription(display, name) }; save(out, dview); - + } + StringUtils::StringVec sharedViews; + for (int v = 0; v < config.getNumViews(VIEW_SHARED, display); ++v) + { + sharedViews.push_back(config.getView(VIEW_SHARED, display, v)); + } + if (!sharedViews.empty()) + { + out << YAML::VerbatimTag("Views"); + out << YAML::Flow << sharedViews; } out << YAML::EndSeq; } @@ -3364,19 +3851,18 @@ inline void save(YAML::Emitter & out, const Config & config) out << YAML::Key << "active_displays"; StringUtils::StringVec active_displays; if(config.getActiveDisplays() != NULL && strlen(config.getActiveDisplays()) > 0) - SplitStringEnvStyle(active_displays, config.getActiveDisplays()); + active_displays = SplitStringEnvStyle(config.getActiveDisplays()); out << YAML::Value << YAML::Flow << active_displays; out << YAML::Key << "active_views"; StringUtils::StringVec active_views; if(config.getActiveViews() != NULL && strlen(config.getActiveViews()) > 0) - SplitStringEnvStyle(active_views, config.getActiveViews()); + active_views = SplitStringEnvStyle(config.getActiveViews()); out << YAML::Value << YAML::Flow << active_views; const std::string inactiveCSs = config.getInactiveColorSpaces(); if (!inactiveCSs.empty()) { - StringUtils::StringVec inactive_colorspaces; - SplitStringEnvStyle(inactive_colorspaces, inactiveCSs.c_str()); + const StringUtils::StringVec inactive_colorspaces{ SplitStringEnvStyle(inactiveCSs) }; out << YAML::Key << "inactive_colorspaces"; out << YAML::Value << YAML::Flow << inactive_colorspaces; } diff --git a/src/OpenColorIO/OpBuilders.h b/src/OpenColorIO/OpBuilders.h index 419a02254d..5ef9b0bc80 100644 --- a/src/OpenColorIO/OpBuilders.h +++ b/src/OpenColorIO/OpBuilders.h @@ -46,17 +46,20 @@ void BuildColorSpaceOps(OpRcPtrVec & ops, const Config & config, const ConstContextRcPtr & context, const ConstColorSpaceRcPtr & srcColorSpace, - const ConstColorSpaceRcPtr & dstColorSpace); + const ConstColorSpaceRcPtr & dstColorSpace, + bool dataBypass); void BuildColorSpaceToReferenceOps(OpRcPtrVec & ops, const Config & config, const ConstContextRcPtr & context, - const ConstColorSpaceRcPtr & srcColorSpace); + const ConstColorSpaceRcPtr & srcColorSpace, + bool dataBypass); void BuildColorSpaceFromReferenceOps(OpRcPtrVec & ops, const Config & config, const ConstContextRcPtr & context, - const ConstColorSpaceRcPtr & dstColorSpace); + const ConstColorSpaceRcPtr & dstColorSpace, + bool dataBypass); void BuildReferenceConversionOps(OpRcPtrVec & ops, const Config & config, @@ -67,7 +70,7 @@ void BuildReferenceConversionOps(OpRcPtrVec & ops, void BuildDisplayOps(OpRcPtrVec & ops, const Config & config, const ConstContextRcPtr & context, - const DisplayTransform & transform, + const DisplayViewTransform & transform, TransformDirection dir); void BuildExponentOp(OpRcPtrVec & ops, @@ -126,7 +129,7 @@ void BuildLookOps(OpRcPtrVec & ops, void BuildLookOps(OpRcPtrVec & ops, ConstColorSpaceRcPtr & currentColorSpace, - bool skipColorSpaceConversions, + bool skipColorSpaceConversion, const Config & config, const ConstContextRcPtr & context, const LookParseResult & looks); @@ -151,6 +154,10 @@ void BuildRangeOp(OpRcPtrVec & ops, const RangeTransform & transform, TransformDirection dir); +const char * LooksResultColorSpace(const Config & config, + const ConstContextRcPtr & context, + const LookParseResult & looks); + } // namespace OCIO_NAMESPACE #endif diff --git a/src/OpenColorIO/ParseUtils.cpp b/src/OpenColorIO/ParseUtils.cpp index 191d823a78..76e72d70d2 100644 --- a/src/OpenColorIO/ParseUtils.cpp +++ b/src/OpenColorIO/ParseUtils.cpp @@ -588,7 +588,7 @@ bool StringVecToIntVec(std::vector &intArray, //////////////////////////////////////////////////////////////////////////// -// read the next non empty line, and store it in 'line' +// read the next non-empty line, and store it in 'line' // return 'true' on success bool nextline(std::istream &istream, std::string &line) @@ -615,15 +615,9 @@ bool StrEqualsCaseIgnore(const std::string & a, const std::string & b) return 0 == Platform::Strcasecmp(a.c_str(), b.c_str()); } -// If a ',' is in the string, split on it -// If a ':' is in the string, split on it -// Otherwise, assume a single string. -// Also, strip whitespace from all parts. - -void SplitStringEnvStyle(StringUtils::StringVec & outputvec, const char * str) +StringUtils::StringVec SplitStringEnvStyle(const std::string & str) { - if (!str) return; - + StringUtils::StringVec outputvec; const std::string s = StringUtils::Trim(str); if (StringUtils::Find(s, ",") != std::string::npos) { @@ -642,6 +636,7 @@ void SplitStringEnvStyle(StringUtils::StringVec & outputvec, const char * str) { val = StringUtils::Trim(val); } + return outputvec; } std::string JoinStringEnvStyle(const StringUtils::StringVec & outputvec) diff --git a/src/OpenColorIO/ParseUtils.h b/src/OpenColorIO/ParseUtils.h index 2b4e2f8216..095e8b206f 100644 --- a/src/OpenColorIO/ParseUtils.h +++ b/src/OpenColorIO/ParseUtils.h @@ -41,7 +41,7 @@ bool StringVecToIntVec(std::vector & intArray, ////////////////////////////////////////////////////////////////////////// -// read the next non empty line, and store it in 'line' +// read the next non-empty line, and store it in 'line' // return 'true' on success bool nextline(std::istream &istream, std::string &line); @@ -52,8 +52,7 @@ bool StrEqualsCaseIgnore(const std::string & a, const std::string & b); // If a ':' is in the string, split on it // Otherwise, assume a single string. // Also, strip whitespace from all parts. - -void SplitStringEnvStyle(StringUtils::StringVec & outputvec, const char * str); +StringUtils::StringVec SplitStringEnvStyle(const std::string & str); // Join on ',' std::string JoinStringEnvStyle(const StringUtils::StringVec & outputvec); diff --git a/src/OpenColorIO/Processor.cpp b/src/OpenColorIO/Processor.cpp index 063f6b5eb1..95fcfb3aa5 100755 --- a/src/OpenColorIO/Processor.cpp +++ b/src/OpenColorIO/Processor.cpp @@ -228,7 +228,6 @@ ConstCPUProcessorRcPtr Processor::getOptimizedCPUProcessor(BitDepth inBitDepth, return getImpl()->getOptimizedCPUProcessor(inBitDepth, outBitDepth, oFlags); } - Processor::Impl::Impl(): m_metadata(ProcessorMetadata::Create()) { @@ -451,15 +450,19 @@ void Processor::Impl::setColorSpaceConversion(const Config & config, throw Exception("Internal error: Processor should be empty"); } - BuildColorSpaceOps(m_ops, config, context, srcColorSpace, dstColorSpace); + BuildColorSpaceOps(m_ops, config, context, srcColorSpace, dstColorSpace, false); + std::ostringstream desc; + desc << "Color space conversion from " << srcColorSpace->getName() + << " to " << dstColorSpace->getName(); + m_ops.getFormatMetadata().addAttribute(METADATA_DESCRIPTION, desc.str().c_str()); m_ops.finalize(OPTIMIZATION_NONE); m_ops.unifyDynamicProperties(); } void Processor::Impl::setTransform(const Config & config, const ConstContextRcPtr & context, - const ConstTransformRcPtr& transform, + const ConstTransformRcPtr & transform, TransformDirection direction) { if (!m_ops.empty()) diff --git a/src/OpenColorIO/TokensManager.h b/src/OpenColorIO/TokensManager.h new file mode 100644 index 0000000000..f1229eb41b --- /dev/null +++ b/src/OpenColorIO/TokensManager.h @@ -0,0 +1,102 @@ +// SPDX-License-Identifier: BSD-3-Clause +// Copyright Contributors to the OpenColorIO Project. + + +#ifndef INCLUDED_OCIO_TOKENS_MANAGER_H +#define INCLUDED_OCIO_TOKENS_MANAGER_H + +#include +#include + +#include + +#include "PrivateTypes.h" +#include "utils/StringUtils.h" + +namespace OCIO_NAMESPACE +{ + +class TokensManager +{ +public: + TokensManager() = default; + TokensManager(const TokensManager &) = delete; + virtual ~TokensManager() = default; + TokensManager & operator=(const TokensManager &) = default; + + typedef StringUtils::StringVec Tokens; + + Tokens::const_iterator findToken(const char * token) const + { + if (!token || !*token) return m_tokens.end(); + + // NB: Categories are not case-sensitive and whitespace is stripped. + const std::string ref(StringUtils::Trim(StringUtils::Lower(token))); + + for (auto itr = m_tokens.begin(); itr != m_tokens.end(); ++itr) + { + if (StringUtils::Trim(StringUtils::Lower(*itr)) == ref) + { + return itr; + } + } + + return m_tokens.end(); + } + + bool hasToken(const char * token) const + { + return findToken(token) != m_tokens.end(); + } + + void addToken(const char * token) + { + if (findToken(token) == m_tokens.end()) + { + m_tokens.push_back(StringUtils::Trim(token)); + } + } + + void removeToken(const char * token) + { + if (!token || !*token) return; + + // NB: Categories are not case-sensitive and whitespace is stripped. + const std::string ref(StringUtils::Trim(StringUtils::Lower(token))); + + for (auto itr = m_tokens.begin(); itr != m_tokens.end(); ++itr) + { + if (StringUtils::Trim(StringUtils::Lower(*itr)) == ref) + { + m_tokens.erase(itr); + return; + } + } + + return; + } + + int getNumTokens() const + { + return static_cast(m_tokens.size()); + } + + const char * getToken(int index) const + { + if (index<0 || index >= (int)m_tokens.size()) return nullptr; + + return m_tokens[index].c_str(); + } + + void clearTokens() + { + m_tokens.clear(); + } + +private: + Tokens m_tokens; +}; + +} // namespace OCIO_NAMESPACE + +#endif diff --git a/src/OpenColorIO/Transform.cpp b/src/OpenColorIO/Transform.cpp index 2419fd18ac..6bf5e6ceb0 100755 --- a/src/OpenColorIO/Transform.cpp +++ b/src/OpenColorIO/Transform.cpp @@ -66,10 +66,10 @@ void BuildOps(OpRcPtrVec & ops, { BuildColorSpaceOps(ops, config, context, *colorSpaceTransform, dir); } - else if(ConstDisplayTransformRcPtr displayTransform = \ - DynamicPtrCast(transform)) + else if(ConstDisplayViewTransformRcPtr displayViewTransform = \ + DynamicPtrCast(transform)) { - BuildDisplayOps(ops, config, context, *displayTransform, dir); + BuildDisplayOps(ops, config, context, *displayViewTransform, dir); } else if(ConstExponentTransformRcPtr exponentTransform = \ DynamicPtrCast(transform)) @@ -126,10 +126,10 @@ void BuildOps(OpRcPtrVec & ops, { BuildLut1DOp(ops, config, *lut1dTransform, dir); } - else if (ConstLut3DTransformRcPtr lut1dTransform = \ + else if (ConstLut3DTransformRcPtr lut3dTransform = \ DynamicPtrCast(transform)) { - BuildLut3DOp(ops, config, *lut1dTransform, dir); + BuildLut3DOp(ops, config, *lut3dTransform, dir); } else if(ConstMatrixTransformRcPtr matrixTransform = \ DynamicPtrCast(transform)) @@ -175,10 +175,10 @@ std::ostream& operator<< (std::ostream & os, const Transform & transform) { os << *colorSpaceTransform; } - else if(const DisplayTransform * displayTransform = \ - dynamic_cast(t)) + else if(const DisplayViewTransform * displayViewTransform = \ + dynamic_cast(t)) { - os << *displayTransform; + os << *displayViewTransform; } else if(const ExponentTransform * exponentTransform = \ dynamic_cast(t)) diff --git a/src/OpenColorIO/ViewTransform.cpp b/src/OpenColorIO/ViewTransform.cpp index 8c099252fb..efc6c7bf3e 100644 --- a/src/OpenColorIO/ViewTransform.cpp +++ b/src/OpenColorIO/ViewTransform.cpp @@ -5,12 +5,12 @@ #include -#include "Categories.h" +#include "TokensManager.h" namespace OCIO_NAMESPACE { -class ViewTransform::Impl : public CategoriesManager +class ViewTransform::Impl { public: std::string m_name; @@ -21,10 +21,11 @@ class ViewTransform::Impl : public CategoriesManager TransformRcPtr m_toRefTransform; TransformRcPtr m_fromRefTransform; + TokensManager m_categories; + Impl() = delete; explicit Impl(ReferenceSpaceType referenceSpace) - : CategoriesManager() - , m_referenceSpaceType(referenceSpace) + : m_referenceSpaceType(referenceSpace) { } @@ -35,9 +36,6 @@ class ViewTransform::Impl : public CategoriesManager { if (this != &rhs) { - *dynamic_cast(this) - = *dynamic_cast(&rhs); - m_name = rhs.m_name; m_family = rhs.m_family; m_description = rhs.m_description; @@ -50,6 +48,8 @@ class ViewTransform::Impl : public CategoriesManager m_fromRefTransform = rhs.m_fromRefTransform ? rhs.m_fromRefTransform->createEditableCopy() : rhs.m_fromRefTransform; + + m_categories = rhs.m_categories; } return *this; } @@ -116,31 +116,31 @@ void ViewTransform::setDescription(const char * description) bool ViewTransform::hasCategory(const char * category) const { - return getImpl()->hasCategory(category); + return getImpl()->m_categories.hasToken(category); } void ViewTransform::addCategory(const char * category) { - getImpl()->addCategory(category); + getImpl()->m_categories.addToken(category); } void ViewTransform::removeCategory(const char * category) { - getImpl()->removeCategory(category); + getImpl()->m_categories.removeToken(category); } int ViewTransform::getNumCategories() const { - return getImpl()->getNumCategories(); + return getImpl()->m_categories.getNumTokens(); } const char * ViewTransform::getCategory(int index) const { - return getImpl()->getCategory(index); + return getImpl()->m_categories.getToken(index); } void ViewTransform::clearCategories() { - getImpl()->clearCategories(); + getImpl()->m_categories.clearTokens(); } diff --git a/src/OpenColorIO/ViewingRules.cpp b/src/OpenColorIO/ViewingRules.cpp new file mode 100644 index 0000000000..e418f369d2 --- /dev/null +++ b/src/OpenColorIO/ViewingRules.cpp @@ -0,0 +1,482 @@ +// SPDX-License-Identifier: BSD-3-Clause +// Copyright Contributors to the OpenColorIO Project. + +#include + +#include + +#include "TokensManager.h" +#include "CustomKeys.h" +#include "Logging.h" +#include "ParseUtils.h" +#include "Platform.h" +#include "ViewingRules.h" + +namespace OCIO_NAMESPACE +{ + +namespace +{ +bool IsEncodingUsed(const ColorSpaceSetRcPtr & colorspaces, const char * encName) +{ + const std::string teststr = StringUtils::Lower(encName); + const int numCS = colorspaces->getNumColorSpaces(); + for (int cs = 0; cs < numCS; ++cs) + { + auto colorspace = colorspaces->getColorSpaceByIndex(cs); + const std::string csis{ colorspace->getEncoding() }; + if (StringUtils::Lower(csis) == teststr) + { + return true; + } + } + return false; +} +} + +class ViewingRule +{ +public: + + using CustomKeys = std::map; + + ViewingRule() = delete; + ViewingRule(const ViewingRule &) = delete; + ViewingRule & operator=(const ViewingRule &) = delete; + + explicit ViewingRule(const char * name) + : m_name(name) + { + } + + ViewingRuleRcPtr clone() const + { + ViewingRuleRcPtr rule = std::make_shared(m_name.c_str()); + + rule->m_colorSpaces = m_colorSpaces; + rule->m_encodings = m_encodings; + rule->m_customKeys = m_customKeys; + + return rule; + } + + const char * getName() const noexcept + { + return m_name.c_str(); + } + + void sanityCheck(std::function colorSpaceAccesssor, + const ColorSpaceSetRcPtr & colorspaces) const + { + const auto numCS = m_colorSpaces.getNumTokens(); + for (int csIdx = 0; csIdx < numCS; ++csIdx) + { + const char * csname = m_colorSpaces.getToken(csIdx); + // Can be a color space or a role (all color spaces). + ConstColorSpaceRcPtr cs = colorSpaceAccesssor(csname); + if (!cs) + { + std::ostringstream os; + os << "The rule '" << m_name << "' "; + os << "refers to color space '" << std::string(csname); + os << "' which is not defined."; + throw Exception(os.str().c_str()); + } + } + const int numEnc = m_encodings.getNumTokens(); + for (int encIdx = 0; encIdx < numEnc; ++encIdx) + { + const char * encName = m_encodings.getToken(encIdx); + if (!IsEncodingUsed(colorspaces, encName)) + { + std::ostringstream os; + os << "The rule '" << m_name << "' "; + os << "refers to encoding '" << std::string(encName); + os << "' that is not used by any of the color spaces."; + LogWarning(os.str()); + } + } + if (numCS + numEnc == 0) + { + std::ostringstream os; + os << "The rule '" << m_name << "' "; + os << "must have either a color space or an encoding."; + throw Exception(os.str().c_str()); + } + else if (numCS != 0 && numEnc != 0) + { + std::ostringstream os; + os << "The rule '" << m_name << "' "; + os << "cannot refer to both a color space and an encoding."; + throw Exception(os.str().c_str()); + } + } + + + CustomKeysContainer m_customKeys; + TokensManager m_colorSpaces; + TokensManager m_encodings; + +private: + + const std::string m_name; +}; + +ViewingRules::ViewingRules() + : m_impl(new ViewingRules::Impl()) +{ +} + +ViewingRules::~ViewingRules() +{ + delete m_impl; + m_impl = nullptr; +} + +ViewingRulesRcPtr ViewingRules::Create() +{ + return ViewingRulesRcPtr(new ViewingRules(), &deleter); +} + +void ViewingRules::deleter(ViewingRules * vr) +{ + delete vr; +} + +ViewingRulesRcPtr ViewingRules::createEditableCopy() const +{ + ViewingRulesRcPtr rules = Create(); + *rules->m_impl = *m_impl; // Deep copy. + return rules; +} + +ViewingRules::Impl & ViewingRules::Impl::operator=(const ViewingRules::Impl & rhs) +{ + if (this != &rhs) + { + m_rules.clear(); + + for (const auto & rule : rhs.m_rules) + { + m_rules.push_back(rule->clone()); + } + } + + return *this; +} + +void ViewingRules::Impl::validatePosition(size_t ruleIndex) const +{ + const auto numRules = m_rules.size(); + if (ruleIndex >= numRules) + { + std::ostringstream oss; + oss << "Viewing rules: rule index '" << ruleIndex << "' invalid." + << " There are only '" << numRules << "' rules."; + throw Exception(oss.str().c_str()); + } +} + +void ViewingRules::Impl::validateNewRule(const char * name) const +{ + if (!name || !*name) + { + throw Exception("Viewing rules: rule must have a non-empty name."); + } + auto existingRule = std::find_if(m_rules.begin(), m_rules.end(), + [name](const ViewingRuleRcPtr & rule) + { + return 0 == Platform::Strcasecmp(name, rule->getName()); + }); + if (existingRule != m_rules.end()) + { + std::ostringstream oss; + oss << "Viewing rules: A rule named '" << name << "' already exists."; + throw Exception(oss.str().c_str()); + } +} + +void ViewingRules::Impl::sanityCheck( + std::function colorSpaceAccessor, + const ColorSpaceSetRcPtr & colorspaces) const +{ + for (auto & rule : m_rules) + { + rule->sanityCheck(colorSpaceAccessor, colorspaces); + } +} + +size_t ViewingRules::getNumEntries() const noexcept +{ + return m_impl->m_rules.size(); +} + +size_t ViewingRules::getIndexForRule(const char * ruleName) const +{ + const size_t numRules = m_impl->m_rules.size(); + for (size_t idx = 0; idx < numRules; ++idx) + { + if (0 == Platform::Strcasecmp(ruleName, m_impl->m_rules[idx]->getName())) + { + return idx; + } + } + + std::ostringstream oss; + oss << "Viewing rules: rule name '" << ruleName << "' not found."; + throw Exception(oss.str().c_str()); +} + +const char * ViewingRules::getName(size_t ruleIndex) const +{ + m_impl->validatePosition(ruleIndex); + return m_impl->m_rules[ruleIndex]->getName(); +} + +size_t ViewingRules::getNumColorSpaces(size_t ruleIndex) const +{ + m_impl->validatePosition(ruleIndex); + return m_impl->m_rules[ruleIndex]->m_colorSpaces.getNumTokens(); +} + +const char * ViewingRules::getColorSpace(size_t ruleIndex, size_t colorSpaceIndex) const +{ + m_impl->validatePosition(ruleIndex); + const auto numCS = m_impl->m_rules[ruleIndex]->m_colorSpaces.getNumTokens(); + if (static_cast(colorSpaceIndex) >= numCS) + { + std::ostringstream oss; + oss << "Viewing rules: rule '" << std::string(m_impl->m_rules[ruleIndex]->getName()) + << "' at index '" << ruleIndex << "': colorspace index '" << colorSpaceIndex + << "' is invalid. There are only '" << numCS << "' colorspaces."; + throw Exception(oss.str().c_str()); + } + return m_impl->m_rules[ruleIndex]->m_colorSpaces.getToken(static_cast(colorSpaceIndex)); +} + +void ViewingRules::addColorSpace(size_t ruleIndex, const char * colorSpace) +{ + m_impl->validatePosition(ruleIndex); + if (!colorSpace || !*colorSpace) + { + std::ostringstream oss; + oss << "Viewing rules: rule '" << std::string(m_impl->m_rules[ruleIndex]->getName()) + << "' at index '" << ruleIndex << "': colorspace should have a non-empty name."; + throw Exception(oss.str().c_str()); + } + if (m_impl->m_rules[ruleIndex]->m_encodings.getNumTokens() != 0) + { + std::ostringstream oss; + oss << "Viewing rules: rule '" << std::string(m_impl->m_rules[ruleIndex]->getName()) + << "' at index '" << ruleIndex + << "': colorspace can't be added if there are encodings."; + throw Exception(oss.str().c_str()); + } + m_impl->m_rules[ruleIndex]->m_colorSpaces.addToken(colorSpace); +} + +void ViewingRules::removeColorSpace(size_t ruleIndex, size_t colorSpaceIndex) +{ + m_impl->m_rules[ruleIndex]->m_colorSpaces.removeToken(getColorSpace(ruleIndex, colorSpaceIndex)); +} + +size_t ViewingRules::getNumEncodings(size_t ruleIndex) const +{ + m_impl->validatePosition(ruleIndex); + return m_impl->m_rules[ruleIndex]->m_encodings.getNumTokens(); +} + +const char * ViewingRules::getEncoding(size_t ruleIndex, size_t encodingIndex) const +{ + m_impl->validatePosition(ruleIndex); + const auto numEnc = m_impl->m_rules[ruleIndex]->m_encodings.getNumTokens(); + if (static_cast(encodingIndex) >= numEnc) + { + std::ostringstream oss; + oss << "Viewing rules: rule '" << std::string(m_impl->m_rules[ruleIndex]->getName()) + << "' at index '" << ruleIndex << "': encoding index '" << encodingIndex + << "' is invalid. There are only '" << numEnc << "' encodings."; + throw Exception(oss.str().c_str()); + } + return m_impl->m_rules[ruleIndex]->m_encodings.getToken(static_cast(encodingIndex)); +} + +void ViewingRules::addEncoding(size_t ruleIndex, const char * encoding) +{ + m_impl->validatePosition(ruleIndex); + if (!encoding || !*encoding) + { + std::ostringstream oss; + oss << "Viewing rules: rule '" << std::string(m_impl->m_rules[ruleIndex]->getName()) + << "' at index '" << ruleIndex << "': encoding should have a non-empty name."; + throw Exception(oss.str().c_str()); + } + if (m_impl->m_rules[ruleIndex]->m_colorSpaces.getNumTokens() != 0) + { + std::ostringstream oss; + oss << "Viewing rules: rule '" << std::string(m_impl->m_rules[ruleIndex]->getName()) + << "' at index '" << ruleIndex + << "': encoding can't be added if there are colorspaces."; + throw Exception(oss.str().c_str()); + } + m_impl->m_rules[ruleIndex]->m_encodings.addToken(encoding); +} + +void ViewingRules::removeEncoding(size_t ruleIndex, size_t encodingIndex) +{ + m_impl->m_rules[ruleIndex]->m_encodings.removeToken(getEncoding(ruleIndex, encodingIndex)); +} + +size_t ViewingRules::getNumCustomKeys(size_t ruleIndex) const +{ + m_impl->validatePosition(ruleIndex); + return m_impl->m_rules[ruleIndex]->m_customKeys.getSize(); +} + +const char * ViewingRules::getCustomKeyName(size_t ruleIndex, size_t key) const +{ + m_impl->validatePosition(ruleIndex); + try + { + return m_impl->m_rules[ruleIndex]->m_customKeys.getName(key); + } + catch (Exception & e) + { + std::ostringstream oss; + oss << "Viewing rules: rule named '" << std::string(m_impl->m_rules[ruleIndex]->getName()) + << "' error: " << e.what(); + throw Exception(oss.str().c_str()); + } +} + +const char * ViewingRules::getCustomKeyValue(size_t ruleIndex, size_t key) const +{ + m_impl->validatePosition(ruleIndex); + try + { + return m_impl->m_rules[ruleIndex]->m_customKeys.getValue(key); + } + catch (Exception & e) + { + std::ostringstream oss; + oss << "Viewing rules: rule named '" << std::string(m_impl->m_rules[ruleIndex]->getName()) + << "' error: " << e.what(); + throw Exception(oss.str().c_str()); + } +} + +void ViewingRules::setCustomKey(size_t ruleIndex, const char * key, const char * value) +{ + m_impl->validatePosition(ruleIndex); + try + { + m_impl->m_rules[ruleIndex]->m_customKeys.set(key, value); + } + catch (Exception & e) + { + std::ostringstream oss; + oss << "Viewing rules: rule named '" << std::string(m_impl->m_rules[ruleIndex]->getName()) + << "' error: " << e.what(); + throw Exception(oss.str().c_str()); + } +} + +void ViewingRules::insertRule(size_t ruleIndex, const char * name) +{ + const std::string ruleName(StringUtils::Trim(name ? name : "")); + + m_impl->validateNewRule(ruleName.c_str()); + + auto newRule = std::make_shared(ruleName.c_str()); + if (ruleIndex == getNumEntries()) + { + m_impl->m_rules.push_back(newRule); + } + else + { + m_impl->validatePosition(ruleIndex); + m_impl->m_rules.insert(m_impl->m_rules.begin() + ruleIndex, newRule); + } +} + +void ViewingRules::removeRule(size_t ruleIndex) +{ + m_impl->validatePosition(ruleIndex); + m_impl->m_rules.erase(m_impl->m_rules.begin() + ruleIndex); +} + +std::ostream & operator<< (std::ostream & os, const ViewingRules & vr) +{ + const size_t numRules = vr.getNumEntries(); + for (size_t r = 0; r < numRules; ++r) + { + os << ""; + if (r + 1 != numRules) + { + os << "\n"; + } + } + return os; +} + +bool FindRule(ConstViewingRulesRcPtr vr, const std::string & name, size_t & ruleIndex) +{ + const auto numrules = vr->getNumEntries(); + for (size_t index = 0; index < numrules; ++index) + { + const std::string ruleName{ vr->getName(index) }; + if (StrEqualsCaseIgnore(ruleName, name)) + { + ruleIndex = index; + return true; + } + } + return false; +} + +} // namespace OCIO_NAMESPACE diff --git a/src/OpenColorIO/ViewingRules.h b/src/OpenColorIO/ViewingRules.h new file mode 100644 index 0000000000..c79026d5b4 --- /dev/null +++ b/src/OpenColorIO/ViewingRules.h @@ -0,0 +1,56 @@ +// SPDX-License-Identifier: BSD-3-Clause +// Copyright Contributors to the OpenColorIO Project. + + +#ifndef INCLUDED_OCIO_VIEWINGRULES_H +#define INCLUDED_OCIO_VIEWINGRULES_H + +#include +#include +#include + +#include + + +namespace OCIO_NAMESPACE +{ + +namespace ViewingRuleUtils +{ +constexpr char Name[] { "name" }; +constexpr char ColorSpaces[]{ "colorspaces" }; +constexpr char Encodings[] { "encodings" }; +constexpr char CustomKey[] { "custom" }; +} + +bool FindRule(ConstViewingRulesRcPtr vr, const std::string & name, size_t & ruleIndex); + +class ViewingRule; +using ViewingRuleRcPtr = OCIO_SHARED_PTR; + +class ViewingRules::Impl +{ +public: + + Impl() = default; + Impl(const Impl &) = delete; + Impl & operator=(const Impl & rhs); + ~Impl() = default; + + void validatePosition(size_t ruleIndex) const; + void validateNewRule(const char * name) const; + + void sanityCheck(std::function colorSpaceAccessor, + const ColorSpaceSetRcPtr & colorspaces) const; + +private: + + friend class ViewingRules; + + // All rules. + std::vector m_rules; +}; + +} // namespace OCIO_NAMESPACE + +#endif diff --git a/src/OpenColorIO/fileformats/FormatMetadata.cpp b/src/OpenColorIO/fileformats/FormatMetadata.cpp index 6a7150b03d..242b8d3cfb 100644 --- a/src/OpenColorIO/fileformats/FormatMetadata.cpp +++ b/src/OpenColorIO/fileformats/FormatMetadata.cpp @@ -44,7 +44,7 @@ FormatMetadataImpl::FormatMetadataImpl(const std::string & name, const std::stri { if (name.empty()) { - throw Exception("FormatMetadata has to have a non empty name."); + throw Exception("FormatMetadata has to have a non-empty name."); } } @@ -70,7 +70,7 @@ void FormatMetadataImpl::setName(const std::string & name) { if (name.empty()) { - throw Exception("FormatMetadata has to have a non empty name."); + throw Exception("FormatMetadata has to have a non-empty name."); } m_name = name; @@ -248,7 +248,7 @@ void FormatMetadataImpl::setName(const char * name) m_name = name; if (m_name.empty()) { - throw Exception("FormatMetadata has to have a non empty name."); + throw Exception("FormatMetadata has to have a non-empty name."); } } diff --git a/src/OpenColorIO/ops/fixedfunction/FixedFunctionOpData.cpp b/src/OpenColorIO/ops/fixedfunction/FixedFunctionOpData.cpp index fde56bf230..613eb99418 100644 --- a/src/OpenColorIO/ops/fixedfunction/FixedFunctionOpData.cpp +++ b/src/OpenColorIO/ops/fixedfunction/FixedFunctionOpData.cpp @@ -331,7 +331,9 @@ FixedFunctionOpData::~FixedFunctionOpData() FixedFunctionOpDataRcPtr FixedFunctionOpData::clone() const { - return std::make_shared(getParams(), getStyle()); + auto clone = std::make_shared(getParams(), getStyle()); + clone->getFormatMetadata() = getFormatMetadata(); + return clone; } void FixedFunctionOpData::validate() const diff --git a/src/OpenColorIO/ops/matrix/MatrixOpData.cpp b/src/OpenColorIO/ops/matrix/MatrixOpData.cpp index bd48692ef2..0237b8b240 100644 --- a/src/OpenColorIO/ops/matrix/MatrixOpData.cpp +++ b/src/OpenColorIO/ops/matrix/MatrixOpData.cpp @@ -77,8 +77,8 @@ template void MatrixOpData::Offsets::setRGBA(const double * v4); bool MatrixOpData::Offsets::isNotNull() const { - static constexpr double zero4[] { 0., 0., 0., 0. }; - return (memcmp(m_values, zero4, 4 * sizeof(double)) != 0); + return m_values[0] != 0. || m_values[1] != 0. || + m_values[2] != 0. || m_values[3] != 0.; } void MatrixOpData::Offsets::scale(double s) diff --git a/src/OpenColorIO/transforms/ColorSpaceTransform.cpp b/src/OpenColorIO/transforms/ColorSpaceTransform.cpp index f657bd0021..1eba2b0d1f 100755 --- a/src/OpenColorIO/transforms/ColorSpaceTransform.cpp +++ b/src/OpenColorIO/transforms/ColorSpaceTransform.cpp @@ -22,26 +22,24 @@ void ColorSpaceTransform::deleter(ColorSpaceTransform* t) class ColorSpaceTransform::Impl { public: - TransformDirection m_dir; + TransformDirection m_dir{ TRANSFORM_DIR_FORWARD }; std::string m_src; std::string m_dst; + bool m_dataBypass{ true }; - Impl() : - m_dir(TRANSFORM_DIR_FORWARD) - { } - + Impl() = default; Impl(const Impl &) = delete; - ~Impl() - { } + ~Impl() = default; Impl& operator= (const Impl & rhs) { if (this != &rhs) { - m_dir = rhs.m_dir; - m_src = rhs.m_src; - m_dst = rhs.m_dst; + m_dir = rhs.m_dir; + m_src = rhs.m_src; + m_dst = rhs.m_dst; + m_dataBypass = rhs.m_dataBypass; } return *this; } @@ -112,12 +110,27 @@ void ColorSpaceTransform::setDst(const char * dst) getImpl()->m_dst = dst; } +bool ColorSpaceTransform::getDataBypass() const noexcept +{ + return getImpl()->m_dataBypass; +} + +void ColorSpaceTransform::setDataBypass(bool bypass) noexcept +{ + getImpl()->m_dataBypass = bypass; +} + std::ostream& operator<< (std::ostream& os, const ColorSpaceTransform& t) { os << ""; return os; } @@ -175,7 +188,8 @@ void BuildColorSpaceOps(OpRcPtrVec & ops, } } - BuildColorSpaceOps(ops, config, context, src, dst); + BuildColorSpaceOps(ops, config, context, src, dst, + colorSpaceTransform.getDataBypass()); } namespace @@ -196,7 +210,8 @@ void BuildColorSpaceOps(OpRcPtrVec & ops, const Config & config, const ConstContextRcPtr & context, const ConstColorSpaceRcPtr & srcColorSpace, - const ConstColorSpaceRcPtr & dstColorSpace) + const ConstColorSpaceRcPtr & dstColorSpace, + bool dataBypass) { if(!srcColorSpace) throw Exception("BuildColorSpaceOps failed, null srcColorSpace."); @@ -205,7 +220,7 @@ void BuildColorSpaceOps(OpRcPtrVec & ops, if(AreColorSpacesInSameEqualityGroup(srcColorSpace, dstColorSpace)) return; - if(dstColorSpace->isData() || srcColorSpace->isData()) + if(dataBypass && (dstColorSpace->isData() || srcColorSpace->isData())) return; // Consider dt8 -> vd8? @@ -214,7 +229,7 @@ void BuildColorSpaceOps(OpRcPtrVec & ops, // ever encountered in transit, we'd want to short circuit the result. // Go from the srcColorSpace to the reference space. - BuildColorSpaceToReferenceOps(ops, config, context, srcColorSpace); + BuildColorSpaceToReferenceOps(ops, config, context, srcColorSpace, dataBypass); // There are two possible reference spaces, the main (scene-referred) one and the // display-referred one. If the src and dst use different reference spaces, use the @@ -224,18 +239,19 @@ void BuildColorSpaceOps(OpRcPtrVec & ops, dstColorSpace->getReferenceSpaceType()); // Go from the reference space to dstColorSpace. - BuildColorSpaceFromReferenceOps(ops, config, context, dstColorSpace); + BuildColorSpaceFromReferenceOps(ops, config, context, dstColorSpace, dataBypass); } void BuildColorSpaceToReferenceOps(OpRcPtrVec & ops, const Config & config, const ConstContextRcPtr & context, - const ConstColorSpaceRcPtr & srcColorSpace) + const ConstColorSpaceRcPtr & srcColorSpace, + bool dataBypass) { if (!srcColorSpace) throw Exception("BuildColorSpaceOps failed, null colorSpace."); - if (srcColorSpace->isData()) + if (dataBypass && srcColorSpace->isData()) return; AllocationData srcAllocation; @@ -267,12 +283,13 @@ void BuildColorSpaceToReferenceOps(OpRcPtrVec & ops, void BuildColorSpaceFromReferenceOps(OpRcPtrVec & ops, const Config & config, const ConstContextRcPtr & context, - const ConstColorSpaceRcPtr & dstColorSpace) + const ConstColorSpaceRcPtr & dstColorSpace, + bool dataBypass) { if (!dstColorSpace) throw Exception("BuildColorSpaceOps failed, null colorSpace."); - if (dstColorSpace->isData()) + if (dataBypass && dstColorSpace->isData()) return; // Go from the reference space, either by using: diff --git a/src/OpenColorIO/transforms/DisplayTransform.cpp b/src/OpenColorIO/transforms/DisplayTransform.cpp deleted file mode 100755 index 346aa806c5..0000000000 --- a/src/OpenColorIO/transforms/DisplayTransform.cpp +++ /dev/null @@ -1,488 +0,0 @@ -// SPDX-License-Identifier: BSD-3-Clause -// Copyright Contributors to the OpenColorIO Project. - - -#include - -#include "OpBuilders.h" - -#include - - -namespace OCIO_NAMESPACE -{ - -DisplayTransformRcPtr DisplayTransform::Create() -{ - return DisplayTransformRcPtr(new DisplayTransform(), &deleter); -} - -void DisplayTransform::deleter(DisplayTransform* t) -{ - delete t; -} - -class DisplayTransform::Impl -{ -public: - TransformDirection m_dir = TRANSFORM_DIR_FORWARD; - std::string m_inputColorSpaceName; - TransformRcPtr m_linearCC; - TransformRcPtr m_colorTimingCC; - TransformRcPtr m_channelView; - std::string m_display; - std::string m_view; - TransformRcPtr m_displayCC; - - std::string m_looksOverride; - bool m_looksOverrideEnabled = false; - - Impl() = default; - Impl(const Impl &) = delete; - ~Impl() = default; - - Impl& operator= (const Impl & rhs) - { - if (this != &rhs) - { - m_dir = rhs.m_dir; - m_inputColorSpaceName = rhs.m_inputColorSpaceName; - - m_linearCC = rhs.m_linearCC? - rhs.m_linearCC->createEditableCopy() : rhs.m_linearCC; - - m_colorTimingCC = rhs.m_colorTimingCC? - rhs.m_colorTimingCC->createEditableCopy() - : rhs.m_colorTimingCC; - - m_channelView = rhs.m_channelView? - rhs.m_channelView->createEditableCopy() : rhs.m_channelView; - - m_display = rhs.m_display; - m_view = rhs.m_view; - - m_displayCC = rhs.m_displayCC? - rhs.m_displayCC->createEditableCopy() : rhs.m_displayCC; - - m_looksOverride = rhs.m_looksOverride; - m_looksOverrideEnabled = rhs.m_looksOverrideEnabled; - } - return *this; - } -}; - -/////////////////////////////////////////////////////////////////////////// - -DisplayTransform::DisplayTransform() - : m_impl(new DisplayTransform::Impl) -{ -} - -TransformRcPtr DisplayTransform::createEditableCopy() const -{ - DisplayTransformRcPtr transform = DisplayTransform::Create(); - *(transform->m_impl) = *m_impl; // Perform a deep copy. - return transform; -} - -DisplayTransform::~DisplayTransform() -{ - delete m_impl; - m_impl = nullptr; -} - -TransformDirection DisplayTransform::getDirection() const noexcept -{ - return getImpl()->m_dir; -} - -void DisplayTransform::setDirection(TransformDirection dir) noexcept -{ - getImpl()->m_dir = dir; -} - -void DisplayTransform::validate() const -{ - Transform::validate(); - - if (getImpl()->m_inputColorSpaceName.empty()) - { - throw Exception("DisplayTransform: empty input color space name."); - } - - if (getImpl()->m_display.empty()) - { - throw Exception("DisplayTransform: empty display name."); - } - - if (getImpl()->m_view.empty()) - { - throw Exception("DisplayTransform: empty view name."); - } -} - -void DisplayTransform::setInputColorSpaceName(const char * name) -{ - getImpl()->m_inputColorSpaceName = name ? name : ""; -} - -const char * DisplayTransform::getInputColorSpaceName() const -{ - return getImpl()->m_inputColorSpaceName.c_str(); -} - -void DisplayTransform::setLinearCC(const ConstTransformRcPtr & cc) -{ - getImpl()->m_linearCC = cc->createEditableCopy(); -} - -ConstTransformRcPtr DisplayTransform::getLinearCC() const -{ - return getImpl()->m_linearCC; -} - -void DisplayTransform::setColorTimingCC(const ConstTransformRcPtr & cc) -{ - getImpl()->m_colorTimingCC = cc->createEditableCopy(); -} - -ConstTransformRcPtr DisplayTransform::getColorTimingCC() const -{ - return getImpl()->m_colorTimingCC; -} - -void DisplayTransform::setChannelView(const ConstTransformRcPtr & transform) -{ - getImpl()->m_channelView = transform->createEditableCopy(); -} - -ConstTransformRcPtr DisplayTransform::getChannelView() const -{ - return getImpl()->m_channelView; -} - -void DisplayTransform::setDisplay(const char * display) -{ - getImpl()->m_display = display ? display : ""; -} - -const char * DisplayTransform::getDisplay() const -{ - return getImpl()->m_display.c_str(); -} - -void DisplayTransform::setView(const char * view) -{ - getImpl()->m_view = view ? view : ""; -} - -const char * DisplayTransform::getView() const -{ - return getImpl()->m_view.c_str(); -} - -void DisplayTransform::setDisplayCC(const ConstTransformRcPtr & cc) -{ - getImpl()->m_displayCC = cc->createEditableCopy(); -} - -ConstTransformRcPtr DisplayTransform::getDisplayCC() const -{ - return getImpl()->m_displayCC; -} - -void DisplayTransform::setLooksOverride(const char * looks) -{ - getImpl()->m_looksOverride = looks; -} - -const char * DisplayTransform::getLooksOverride() const -{ - return getImpl()->m_looksOverride.c_str(); -} - -void DisplayTransform::setLooksOverrideEnabled(bool enabled) -{ - getImpl()->m_looksOverrideEnabled = enabled; -} - -bool DisplayTransform::getLooksOverrideEnabled() const -{ - return getImpl()->m_looksOverrideEnabled; -} - -std::ostream& operator<< (std::ostream& os, const DisplayTransform& t) -{ - os << ""; - return os; -} - -/////////////////////////////////////////////////////////////////////////// - -void BuildDisplayOps(OpRcPtrVec & ops, - const Config & config, - const ConstContextRcPtr & context, - const DisplayTransform & displayTransform, - TransformDirection dir) -{ - auto combinedDir = CombineTransformDirections(dir, displayTransform.getDirection()); - if (combinedDir == TRANSFORM_DIR_UNKNOWN) - { - std::ostringstream os; - os << "Cannot build display transform: unspecified transform direction."; - throw Exception(os.str().c_str()); - } - - const std::string inputColorSpaceName = displayTransform.getInputColorSpaceName(); - ConstColorSpaceRcPtr inputColorSpace = config.getColorSpace(inputColorSpaceName.c_str()); - if (!inputColorSpace) - { - std::ostringstream os; - os << "DisplayTransform error."; - if (inputColorSpaceName.empty()) - { - os << " InputColorSpaceName is unspecified."; - } - else - { - os << " Cannot find inputColorSpace, named '" << inputColorSpaceName << "'."; - } - throw Exception(os.str().c_str()); - } - - const std::string display = displayTransform.getDisplay(); - const std::string view = displayTransform.getView(); - - const std::string viewTransformName = config.getDisplayViewTransformName(display.c_str(), view.c_str()); - ConstViewTransformRcPtr viewTransform; - if (!viewTransformName.empty()) - { - viewTransform = config.getViewTransform(viewTransformName.c_str()); - } - - // NB: If the viewTranform is present, then displayColorSpace is a true display color space - // rather than a traditional color space. - const std::string displayColorSpaceName = config.getDisplayColorSpaceName(display.c_str(), view.c_str()); - ConstColorSpaceRcPtr displayColorSpace = config.getColorSpace(displayColorSpaceName.c_str()); - if (!displayColorSpace) - { - std::ostringstream os; - os << "DisplayTransform error."; - if (displayColorSpaceName.empty()) - { - os << " displayColorSpaceName is unspecified."; - } - else - { - os << " Cannot find display colorspace, '" << displayColorSpaceName << "'."; - } - throw Exception(os.str().c_str()); - } - - bool skipColorSpaceConversions = (inputColorSpace->isData() || displayColorSpace->isData()); - - // If we're viewing alpha, also skip all color space conversions. - // If the user does uses a different transform for the channel view, - // in place of a simple matrix, they run the risk that when viewing alpha - // the colorspace transforms will not be skipped. (I.e., filmlook will be applied - // to alpha.) If this ever becomes an issue, additional engineering will be - // added at that time. - - ConstMatrixTransformRcPtr typedChannelView = DynamicPtrCast( - displayTransform.getChannelView()); - if (typedChannelView) - { - double matrix44[16]; - typedChannelView->getMatrix(matrix44); - - if ((matrix44[3]>0.0) || (matrix44[7]>0.0) || (matrix44[11]>0.0)) - { - skipColorSpaceConversions = true; - } - } - - ConstColorSpaceRcPtr currentColorSpace = inputColorSpace; - - // Apply a transform in ROLE_SCENE_LINEAR. - ConstTransformRcPtr linearCC = displayTransform.getLinearCC(); - if (linearCC) - { - // Put the new ops into a temp array, to see if it's a no-op - // If it is a no-op, dont bother doing the colorspace conversion. - OpRcPtrVec tmpOps; - BuildOps(tmpOps, config, context, linearCC, TRANSFORM_DIR_FORWARD); - - if (!tmpOps.isNoOp()) - { - ConstColorSpaceRcPtr targetColorSpace = config.getColorSpace(ROLE_SCENE_LINEAR); - - if (!targetColorSpace) - { - std::ostringstream os; - os << "DisplayTransform error."; - os << " LinearCC requires '" << std::string(ROLE_SCENE_LINEAR); - os << "' role to be defined."; - throw Exception(os.str().c_str()); - } - - if (!skipColorSpaceConversions) - { - BuildColorSpaceOps(ops, config, context, currentColorSpace, targetColorSpace); - currentColorSpace = targetColorSpace; - } - - ops += tmpOps; - } - } - - // Apply a color correction, in ROLE_COLOR_TIMING. - ConstTransformRcPtr colorTimingCC = displayTransform.getColorTimingCC(); - if (colorTimingCC) - { - // Put the new ops into a temp array, to see if it's a no-op - // If it is a no-op, dont bother doing the colorspace conversion. - OpRcPtrVec tmpOps; - BuildOps(tmpOps, config, context, colorTimingCC, TRANSFORM_DIR_FORWARD); - - if (!tmpOps.isNoOp()) - { - ConstColorSpaceRcPtr targetColorSpace = config.getColorSpace(ROLE_COLOR_TIMING); - - if (!targetColorSpace) - { - std::ostringstream os; - os << "DisplayTransform error."; - os << " ColorTimingCC requires '" << std::string(ROLE_COLOR_TIMING); - os << "' role to be defined."; - throw Exception(os.str().c_str()); - } - - if(!skipColorSpaceConversions) - { - BuildColorSpaceOps(ops, config, context, currentColorSpace, targetColorSpace); - currentColorSpace = targetColorSpace; - } - - ops += tmpOps; - } - } - - // Apply a look, if specified. - LookParseResult looks; - if (displayTransform.getLooksOverrideEnabled()) - { - looks.parse(displayTransform.getLooksOverride()); - } - else if (!skipColorSpaceConversions) - { - looks.parse(config.getDisplayLooks(display.c_str(), view.c_str())); - } - - if (!looks.empty()) - { - BuildLookOps(ops, - currentColorSpace, - skipColorSpaceConversions, - config, - context, - looks); - } - - // Apply a channel view. - ConstTransformRcPtr channelView = displayTransform.getChannelView(); - if (channelView) - { - BuildOps(ops, config, context, channelView, TRANSFORM_DIR_FORWARD); - } - - // Apply the conversion to the display color space. - if (!skipColorSpaceConversions) - { - if (viewTransform) - { - // DisplayColorSpace is display-referred. - - // Convert the currentColorSpace to its reference space. - BuildColorSpaceToReferenceOps(ops, config, context, currentColorSpace); - - // If necessary, convert to the type of reference space used by the view transform. - const auto vtRef = viewTransform->getReferenceSpaceType(); - const auto curCSRef = currentColorSpace->getReferenceSpaceType(); - BuildReferenceConversionOps(ops, config, context, curCSRef, vtRef); - - // Apply view transform. - if (viewTransform->getTransform(VIEWTRANSFORM_DIR_FROM_REFERENCE)) - { - BuildOps(ops, config, context, - viewTransform->getTransform(VIEWTRANSFORM_DIR_FROM_REFERENCE), - TRANSFORM_DIR_FORWARD); - } - else if (viewTransform->getTransform(VIEWTRANSFORM_DIR_TO_REFERENCE)) - { - BuildOps(ops, config, context, - viewTransform->getTransform(VIEWTRANSFORM_DIR_TO_REFERENCE), - TRANSFORM_DIR_INVERSE); - } - - // Convert from the display-referred reference space to the displayColorSpace. - BuildColorSpaceFromReferenceOps(ops, config, context, displayColorSpace); - } - else - { - BuildColorSpaceOps(ops, config, context, currentColorSpace, displayColorSpace); - } - currentColorSpace = displayColorSpace; - } - - // Apply a display cc. - ConstTransformRcPtr displayCC = displayTransform.getDisplayCC(); - if (displayCC) - { - BuildOps(ops, config, context, displayCC, TRANSFORM_DIR_FORWARD); - } - - // TODO: Implement inverse direction. It is not simply inverting the result, because the - // from_reference or to_reference transform should be chosen from the direction (when they - // both exist). - - // TODO: The view transform & display color space pipeline for (display, view) pair requires - // some adjustements to the inverse computation as it's more accurate to use the - // ViewTransform inverse if available. - - // Invert the display transform, if requested. - if (combinedDir == TRANSFORM_DIR_INVERSE) - { - ops = ops.invert(); - } -} - -} // namespace OCIO_NAMESPACE diff --git a/src/OpenColorIO/transforms/DisplayViewTransform.cpp b/src/OpenColorIO/transforms/DisplayViewTransform.cpp new file mode 100644 index 0000000000..3c76d97d69 --- /dev/null +++ b/src/OpenColorIO/transforms/DisplayViewTransform.cpp @@ -0,0 +1,411 @@ +// SPDX-License-Identifier: BSD-3-Clause +// Copyright Contributors to the OpenColorIO Project. + + +#include + +#include + +#include "Display.h" +#include "OpBuilders.h" + +namespace OCIO_NAMESPACE +{ + +DisplayViewTransformRcPtr DisplayViewTransform::Create() +{ + return DisplayViewTransformRcPtr(new DisplayViewTransform(), &deleter); +} + +void DisplayViewTransform::deleter(DisplayViewTransform* t) +{ + delete t; +} + +class DisplayViewTransform::Impl +{ +public: + TransformDirection m_dir{ TRANSFORM_DIR_FORWARD }; + std::string m_src; + std::string m_display; + std::string m_view; + + bool m_looksBypass{ false }; + bool m_dataBypass{ true }; + + Impl() = default; + Impl(const Impl &) = delete; + ~Impl() = default; + Impl& operator= (const Impl & rhs) = default; +}; + +/////////////////////////////////////////////////////////////////////////// + +DisplayViewTransform::DisplayViewTransform() + : m_impl(new DisplayViewTransform::Impl) +{ +} + +TransformRcPtr DisplayViewTransform::createEditableCopy() const +{ + DisplayViewTransformRcPtr transform = DisplayViewTransform::Create(); + *(transform->m_impl) = *m_impl; // Perform a deep copy. + return transform; +} + +DisplayViewTransform::~DisplayViewTransform() +{ + delete m_impl; + m_impl = nullptr; +} + +TransformDirection DisplayViewTransform::getDirection() const noexcept +{ + return getImpl()->m_dir; +} + +void DisplayViewTransform::setDirection(TransformDirection dir) noexcept +{ + getImpl()->m_dir = dir; +} + +void DisplayViewTransform::validate() const +{ + Transform::validate(); + + if (getImpl()->m_src.empty()) + { + throw Exception("DisplayViewTransform: empty source color space name."); + } + + if (getImpl()->m_display.empty()) + { + throw Exception("DisplayViewTransform: empty display name."); + } + + if (getImpl()->m_view.empty()) + { + throw Exception("DisplayViewTransform: empty view name."); + } +} + +void DisplayViewTransform::setSrc(const char * name) +{ + getImpl()->m_src = name ? name : ""; +} + +const char * DisplayViewTransform::getSrc() const +{ + return getImpl()->m_src.c_str(); +} + +void DisplayViewTransform::setDisplay(const char * display) +{ + getImpl()->m_display = display ? display : ""; +} + +const char * DisplayViewTransform::getDisplay() const +{ + return getImpl()->m_display.c_str(); +} + +void DisplayViewTransform::setView(const char * view) +{ + getImpl()->m_view = view ? view : ""; +} + +const char * DisplayViewTransform::getView() const +{ + return getImpl()->m_view.c_str(); +} + +void DisplayViewTransform::setLooksBypass(bool bypass) +{ + getImpl()->m_looksBypass = bypass; +} + +bool DisplayViewTransform::getLooksBypass() const +{ + return getImpl()->m_looksBypass; +} + +void DisplayViewTransform::setDataBypass(bool bypass) noexcept +{ + getImpl()->m_dataBypass = bypass; +} + +bool DisplayViewTransform::getDataBypass() const noexcept +{ + return getImpl()->m_dataBypass; +} + +std::ostream& operator<< (std::ostream& os, const DisplayViewTransform& t) +{ + os << ""; + return os; +} + +/////////////////////////////////////////////////////////////////////////// + +// Helper function to build the list of ops to convert from the source color space to the display +// color space (using a view transform). This is used when building ops in the forward direction. +void BuildSourceToDisplay(OpRcPtrVec & ops, + const Config & config, + const ConstContextRcPtr & context, + const ConstColorSpaceRcPtr & sourceCS, + const ConstViewTransformRcPtr & viewTransform, + const ConstColorSpaceRcPtr & displayCS, + bool dataBypass) +{ + // DisplayCS is display-referred. + + // Convert the current color space to its reference space. + BuildColorSpaceToReferenceOps(ops, config, context, sourceCS, dataBypass); + + // If necessary, convert to the type of reference space used by the view transform. + const auto vtRef = viewTransform->getReferenceSpaceType(); + const auto curCSRef = sourceCS->getReferenceSpaceType(); + BuildReferenceConversionOps(ops, config, context, curCSRef, vtRef); + + // Apply view transform. + if (viewTransform->getTransform(VIEWTRANSFORM_DIR_FROM_REFERENCE)) + { + BuildOps(ops, config, context, + viewTransform->getTransform(VIEWTRANSFORM_DIR_FROM_REFERENCE), + TRANSFORM_DIR_FORWARD); + } + else if (viewTransform->getTransform(VIEWTRANSFORM_DIR_TO_REFERENCE)) + { + BuildOps(ops, config, context, + viewTransform->getTransform(VIEWTRANSFORM_DIR_TO_REFERENCE), + TRANSFORM_DIR_INVERSE); + } + else + { + std::ostringstream os; + os << "View transform named '" << viewTransform->getName(); + os << "' needs either a transform from or to reference."; + throw Exception(os.str().c_str()); + } + + // Convert from the display-referred reference space to the displayCS. + BuildColorSpaceFromReferenceOps(ops, config, context, displayCS, dataBypass); +} + +// Helper function to build the list of ops to convert from the display color space (using a view +// transform) to the source color space. This is used when building ops in the inverse direction. +void BuildDisplayToSource(OpRcPtrVec & ops, + const Config & config, + const ConstContextRcPtr & context, + const ConstColorSpaceRcPtr & displayCS, + const ConstViewTransformRcPtr & viewTransform, + const ConstColorSpaceRcPtr & sourceCS, + bool dataBypass) +{ + // Convert to the display-referred reference space from the displayColorSpace. + BuildColorSpaceToReferenceOps(ops, config, context, displayCS, dataBypass); + + // Apply view transform inverted. + if (viewTransform->getTransform(VIEWTRANSFORM_DIR_TO_REFERENCE)) + { + BuildOps(ops, config, context, + viewTransform->getTransform(VIEWTRANSFORM_DIR_TO_REFERENCE), + TRANSFORM_DIR_FORWARD); + } + else if (viewTransform->getTransform(VIEWTRANSFORM_DIR_FROM_REFERENCE)) + { + BuildOps(ops, config, context, + viewTransform->getTransform(VIEWTRANSFORM_DIR_FROM_REFERENCE), + TRANSFORM_DIR_INVERSE); + } + else + { + std::ostringstream os; + os << "View transform named '" << viewTransform->getName(); + os << "' needs either a transform from or to reference."; + throw Exception(os.str().c_str()); + } + + // If necessary, convert from the type of reference space used by the view transform to the + // reference space of the source color space. + const auto vtRef = viewTransform->getReferenceSpaceType(); + const auto inCSRef = sourceCS->getReferenceSpaceType(); + BuildReferenceConversionOps(ops, config, context, vtRef, inCSRef); + + // Convert from the reference space back to the source color space. + BuildColorSpaceFromReferenceOps(ops, config, context, sourceCS, dataBypass); + +} + +// Build ops for a display transform. +void BuildDisplayOps(OpRcPtrVec & ops, + const Config & config, + const ConstContextRcPtr & context, + const DisplayViewTransform & displayViewTransform, + TransformDirection dir) +{ + auto combinedDir = CombineTransformDirections(dir, displayViewTransform.getDirection()); + if (combinedDir == TRANSFORM_DIR_UNKNOWN) + { + std::ostringstream os; + os << "Cannot build display transform: unspecified transform direction."; + throw Exception(os.str().c_str()); + } + + // Validate src color space. + const std::string srcColorSpaceName = displayViewTransform.getSrc(); + ConstColorSpaceRcPtr srcColorSpace = config.getColorSpace(srcColorSpaceName.c_str()); + if (!srcColorSpace) + { + std::ostringstream os; + os << "DisplayViewTransform error."; + if (srcColorSpaceName.empty()) + { + os << " The source color space is unspecified."; + } + else + { + os << " Cannot find source color space, named '" << srcColorSpaceName << "'."; + } + throw Exception(os.str().c_str()); + } + + const std::string display = displayViewTransform.getDisplay(); + const std::string view = displayViewTransform.getView(); + + // Get the view transform if any. + const std::string viewTransformName = config.getDisplayViewTransformName(display.c_str(), view.c_str()); + ConstViewTransformRcPtr viewTransform; + if (!viewTransformName.empty()) + { + viewTransform = config.getViewTransform(viewTransformName.c_str()); + } + + // Get the color space associated to the (display, view) pair. + const char * csName = config.getDisplayViewColorSpaceName(display.c_str(), view.c_str()); + + // A shared view containing a view transform may set the color space to USE_DISPLAY_NAME, + // in which case we look for a display color space with the same name as the display. + const std::string displayColorSpaceName = View::UseDisplayName(csName) ? display : csName; + ConstColorSpaceRcPtr displayColorSpace = config.getColorSpace(displayColorSpaceName.c_str()); + if (!displayColorSpace) + { + std::ostringstream os; + os << "DisplayViewTransform error."; + if (displayColorSpaceName.empty()) + { + os << " Display color space name is unspecified."; + } + else + { + os << " Cannot find display color space, '" << displayColorSpaceName << "'."; + } + throw Exception(os.str().c_str()); + } + + // By default, data color spaces are not processed. + const bool dataBypass = displayViewTransform.getDataBypass(); + if (dataBypass && + (srcColorSpace->isData() || displayColorSpace->isData())) + { + return; + } + + // Get looks to be applied, if specified. + LookParseResult looks; + if (!displayViewTransform.getLooksBypass()) + { + looks.parse(config.getDisplayViewLooks(display.c_str(), view.c_str())); + } + + // Now that all the inputs are found and validated, the following code builds the list of ops + // for the forward or the inverse direction. + + if (combinedDir == TRANSFORM_DIR_FORWARD) + { + // Start from src color space. + ConstColorSpaceRcPtr currentCS = srcColorSpace; + + // Apply looks if needed. + if (!looks.empty()) + { + // Note that this updates the currentCS to be the process space of the last look + // applied. + BuildLookOps(ops, + currentCS, + false, + config, + context, + looks); + } + + // Apply the conversion from the current color space to the display color space. + if (viewTransform) + { + BuildSourceToDisplay(ops, config, context, currentCS, viewTransform, + displayColorSpace, dataBypass); + } + else + { + BuildColorSpaceOps(ops, config, context, currentCS, displayColorSpace, + dataBypass); + } + } + else // TRANSFORM_DIR_INVERSE + { + // The source color space of the view transform might need to be computed. In forward, + // looks (if present) are applied and will change the current color space that is used + // as the starting point of the view transform. Looks need to be used in order to find + // what color space to use for the view transform in the inverse direction. + ConstColorSpaceRcPtr vtSourceCS = srcColorSpace; + if (!looks.empty()) + { + // Get result color space of apply looks in forward direction to find-out the source + // color space of the view transform. + const char * csRes = LooksResultColorSpace(config, context, looks); + vtSourceCS = config.getColorSpace(csRes); + } + + // Apply the conversion from the display color space to the vtSourceCS. + if (viewTransform) + { + BuildDisplayToSource(ops, config, context, displayColorSpace, viewTransform, + vtSourceCS, dataBypass); + } + else + { + BuildColorSpaceOps(ops, config, context, displayColorSpace, vtSourceCS, + dataBypass); + } + + if (!looks.empty()) + { + // Apply looks in inverse direction. Note that vtSourceCS is updated. + looks.reverse(); + BuildLookOps(ops, + vtSourceCS, + false, + config, + context, + looks); + + // End in srcColorSpace. + BuildColorSpaceOps(ops, config, context, + vtSourceCS, srcColorSpace, dataBypass); + } + } +} +} // namespace OCIO_NAMESPACE diff --git a/src/OpenColorIO/transforms/LookTransform.cpp b/src/OpenColorIO/transforms/LookTransform.cpp index 5a500329b4..f4654e42b8 100755 --- a/src/OpenColorIO/transforms/LookTransform.cpp +++ b/src/OpenColorIO/transforms/LookTransform.cpp @@ -27,28 +27,25 @@ void LookTransform::deleter(LookTransform* t) class LookTransform::Impl { public: - TransformDirection m_dir; + TransformDirection m_dir{ TRANSFORM_DIR_FORWARD }; + bool m_skipColorSpaceConversion{ false }; std::string m_src; std::string m_dst; std::string m_looks; - Impl() : - m_dir(TRANSFORM_DIR_FORWARD) - { } - + Impl() = default; Impl(const Impl &) = delete; - - ~Impl() - { } + ~Impl() = default; Impl& operator= (const Impl & rhs) { if (this != &rhs) { - m_dir = rhs.m_dir; - m_src = rhs.m_src; - m_dst = rhs.m_dst; - m_looks = rhs.m_looks; + m_dir = rhs.m_dir; + m_src = rhs.m_src; + m_dst = rhs.m_dst; + m_looks = rhs.m_looks; + m_skipColorSpaceConversion = rhs.m_skipColorSpaceConversion; } return *this; } @@ -90,12 +87,12 @@ void LookTransform::validate() const if (getImpl()->m_src.empty()) { - throw Exception("LookTransform: empty source color space name"); + throw Exception("LookTransform: empty source color space name."); } if (getImpl()->m_dst.empty()) { - throw Exception("LookTransform: empty destination color space name"); + throw Exception("LookTransform: empty destination color space name."); } } @@ -106,7 +103,7 @@ const char * LookTransform::getSrc() const void LookTransform::setSrc(const char * src) { - getImpl()->m_src = src; + getImpl()->m_src = src ? src : ""; } const char * LookTransform::getDst() const @@ -116,12 +113,12 @@ const char * LookTransform::getDst() const void LookTransform::setDst(const char * dst) { - getImpl()->m_dst = dst; + getImpl()->m_dst = dst ? dst : ""; } void LookTransform::setLooks(const char * looks) { - getImpl()->m_looks = looks; + getImpl()->m_looks = looks ? looks : ""; } const char * LookTransform::getLooks() const @@ -129,12 +126,55 @@ const char * LookTransform::getLooks() const return getImpl()->m_looks.c_str(); } +void LookTransform::setSkipColorSpaceConversion(bool skip) +{ + getImpl()->m_skipColorSpaceConversion = skip; +} + +bool LookTransform::getSkipColorSpaceConversion() const +{ + return getImpl()->m_skipColorSpaceConversion; +} + +const char * LooksResultColorSpace(const Config & config, + const ConstContextRcPtr & context, + const LookParseResult & looks) +{ + if (!looks.empty()) + { + // Apply looks in forward direction to update the source space. + // Note that we cannot simply take the process space of the last look, since one of the + // look fall-backs may be used, so the look tokens need to be run. + ConstColorSpaceRcPtr currentColorSpace; + OpRcPtrVec tmp; + BuildLookOps(tmp, currentColorSpace, false, config, context, looks); + if (currentColorSpace) + { + return currentColorSpace->getName(); + } + } + return ""; +} + +const char * LookTransform::GetLooksResultColorSpace(const ConstConfigRcPtr & config, + const ConstContextRcPtr & context, + const char * looksStr) +{ + if (!looksStr || !*looksStr) return ""; + + LookParseResult looks; + looks.parse(looksStr); + + return LooksResultColorSpace(*config, context, looks); +} + std::ostream& operator<< (std::ostream& os, const LookTransform& t) { os << ""; return os; @@ -146,11 +186,11 @@ namespace { void RunLookTokens(OpRcPtrVec & ops, - ConstColorSpaceRcPtr & currentColorSpace, - bool skipColorSpaceConversions, - const Config& config, - const ConstContextRcPtr & context, - const LookParseResult::Tokens & lookTokens) + ConstColorSpaceRcPtr & currentColorSpace, + bool skipColorSpaceConversion, + const Config& config, + const ConstContextRcPtr & context, + const LookParseResult::Tokens & lookTokens) { if(lookTokens.empty()) return; @@ -169,7 +209,7 @@ void RunLookTokens(OpRcPtrVec & ops, os << "', cannot be found. "; if(config.getNumLooks() == 0) { - os << " (No looks defined in config)"; + os << " (No looks defined in config)."; } else { @@ -179,7 +219,7 @@ void RunLookTokens(OpRcPtrVec & ops, if(ii != 0) os << ", "; os << config.getLookNameByIndex(ii); } - os << ")"; + os << ")."; } throw Exception(os.str().c_str()); @@ -224,22 +264,26 @@ void RunLookTokens(OpRcPtrVec & ops, if (!tmpOps.isNoOp()) { - if(!skipColorSpaceConversions) + ConstColorSpaceRcPtr processColorSpace = config.getColorSpace(look->getProcessSpace()); + if(!processColorSpace) + { + std::ostringstream os; + os << "RunLookTokens error. "; + os << "The specified look, '" << lookTokens[i].name; + os << "', requires processing in the ColorSpace, '"; + os << look->getProcessSpace() << "' which is not defined."; + throw Exception(os.str().c_str()); + } + if (!currentColorSpace) + { + currentColorSpace = processColorSpace; + } + // If current color space is already the process space skip the conversion. + if (!skipColorSpaceConversion && + currentColorSpace.get() != processColorSpace.get()) { - ConstColorSpaceRcPtr processColorSpace = config.getColorSpace(look->getProcessSpace()); - if(!processColorSpace) - { - std::ostringstream os; - os << "RunLookTokens error. "; - os << "The specified look, '" << lookTokens[i].name; - os << "', requires processing in the ColorSpace, '"; - os << look->getProcessSpace() << "' which is not defined."; - throw Exception(os.str().c_str()); - } - BuildColorSpaceOps(ops, config, context, - currentColorSpace, - processColorSpace); + currentColorSpace, processColorSpace, false); currentColorSpace = processColorSpace; } @@ -253,10 +297,10 @@ void RunLookTokens(OpRcPtrVec & ops, //////////////////////////////////////////////////////////////////////////// void BuildLookOps(OpRcPtrVec & ops, - const Config& config, - const ConstContextRcPtr & context, - const LookTransform & lookTransform, - TransformDirection dir) + const Config & config, + const ConstContextRcPtr & context, + const LookTransform & lookTransform, + TransformDirection dir) { ConstColorSpaceRcPtr src, dst; src = config.getColorSpace( lookTransform.getSrc() ); @@ -296,25 +340,29 @@ void BuildLookOps(OpRcPtrVec & ops, throw Exception(os.str().c_str()); } + const bool skipColorSpaceConversion = lookTransform.getSkipColorSpaceConversion(); ConstColorSpaceRcPtr currentColorSpace = src; BuildLookOps(ops, - currentColorSpace, - false, - config, - context, - looks); - - BuildColorSpaceOps(ops, config, context, - currentColorSpace, - dst); + currentColorSpace, + skipColorSpaceConversion, + config, + context, + looks); + + // If current color space is already the dst space skip the conversion. + if (!skipColorSpaceConversion && currentColorSpace.get() != dst.get()) + { + BuildColorSpaceOps(ops, config, context, + currentColorSpace, dst, false); + } } void BuildLookOps(OpRcPtrVec & ops, - ConstColorSpaceRcPtr & currentColorSpace, - bool skipColorSpaceConversions, - const Config& config, - const ConstContextRcPtr & context, - const LookParseResult & looks) + ConstColorSpaceRcPtr & currentColorSpace, // in-out + bool skipColorSpaceConversion, + const Config & config, + const ConstContextRcPtr & context, + const LookParseResult & looks) { const LookParseResult::Options & options = looks.getOptions(); @@ -327,11 +375,11 @@ void BuildLookOps(OpRcPtrVec & ops, // As an optimization, if we only have a single look option, // just push back onto the final location RunLookTokens(ops, - currentColorSpace, - skipColorSpaceConversions, - config, - context, - options[0]); + currentColorSpace, + skipColorSpaceConversion, + config, + context, + options[0]); } else { @@ -353,11 +401,11 @@ void BuildLookOps(OpRcPtrVec & ops, try { RunLookTokens(tmpOps, - cs, - skipColorSpaceConversions, - config, - context, - options[i]); + cs, + skipColorSpaceConversion, + config, + context, + options[i]); success = true; break; } diff --git a/src/apps/ocioconvert/main.cpp b/src/apps/ocioconvert/main.cpp index f27fefc2be..0c52dffa69 100644 --- a/src/apps/ocioconvert/main.cpp +++ b/src/apps/ocioconvert/main.cpp @@ -464,8 +464,8 @@ int main(int argc, const char **argv) } else if (useDisplayView) { - OCIO::DisplayTransformRcPtr t = OCIO::DisplayTransform::Create(); - t->setInputColorSpaceName(inputcolorspace); + OCIO::DisplayViewTransformRcPtr t = OCIO::DisplayViewTransform::Create(); + t->setSrc(inputcolorspace); t->setDisplay(display); t->setView(view); processor = config->getProcessor(t); diff --git a/src/apps/ociodisplay/CMakeLists.txt b/src/apps/ociodisplay/CMakeLists.txt index d4af73ff7d..8048460641 100755 --- a/src/apps/ociodisplay/CMakeLists.txt +++ b/src/apps/ociodisplay/CMakeLists.txt @@ -31,6 +31,7 @@ target_include_directories(ociodisplay ) target_link_libraries(ociodisplay PRIVATE + apphelpers ${GLEW_LIBRARIES} ${GLUT_LIBRARIES} oglapphelpers diff --git a/src/apps/ociodisplay/main.cpp b/src/apps/ociodisplay/main.cpp index 4fd3866eae..6b4e6d2860 100644 --- a/src/apps/ociodisplay/main.cpp +++ b/src/apps/ociodisplay/main.cpp @@ -34,6 +34,7 @@ namespace OCIO = OCIO_NAMESPACE; #include "glsl.h" #include "oglapp.h" +#include "ViewingPipeline.h" bool g_verbose = false; bool g_gpulegacy = false; @@ -177,7 +178,7 @@ void InitOCIO(const char * filename) OCIO::ConstConfigRcPtr config = OCIO::GetCurrentConfig(); g_display = config->getDefaultDisplay(); g_transformName = config->getDefaultView(g_display.c_str()); - g_look = config->getDisplayLooks(g_display.c_str(), g_transformName.c_str()); + g_look = config->getDisplayViewLooks(g_display.c_str(), g_transformName.c_str()); g_inputColorSpace = OCIO::ROLE_SCENE_LINEAR; if(filename && *filename) @@ -324,11 +325,15 @@ void UpdateOCIOGLState() // Step 0: Get the processor using any of the pipelines mentioned above. OCIO::ConstConfigRcPtr config = OCIO::GetCurrentConfig(); - OCIO::DisplayTransformRcPtr transform = OCIO::DisplayTransform::Create(); - transform->setInputColorSpaceName( g_inputColorSpace.c_str() ); + OCIO::DisplayViewTransformRcPtr transform = OCIO::DisplayViewTransform::Create(); + transform->setSrc( g_inputColorSpace.c_str() ); transform->setDisplay( g_display.c_str() ); transform->setView( g_transformName.c_str() ); - transform->setLooksOverride( g_look.c_str() ); + + OCIO::ViewingPipeline vpt; + vpt.setDisplayViewTransform(transform); + vpt.setLooksOverrideEnabled(true); + vpt.setLooksOverride(g_look); if(g_verbose) { @@ -368,7 +373,7 @@ void UpdateOCIOGLState() OCIO::MatrixTransformRcPtr mtx = OCIO::MatrixTransform::Create(); mtx->setMatrix(m44); mtx->setOffset(offset4); - transform->setLinearCC(mtx); + vpt.setLinearCC(mtx); } // Channel swizzling @@ -381,7 +386,7 @@ void UpdateOCIOGLState() OCIO::MatrixTransformRcPtr swizzle = OCIO::MatrixTransform::Create(); swizzle->setMatrix(m44); swizzle->setOffset(offset); - transform->setChannelView(swizzle); + vpt.setChannelView(swizzle); } // Post-display transform gamma @@ -390,13 +395,13 @@ void UpdateOCIOGLState() const double exponent4f[4] = { exponent, exponent, exponent, exponent }; OCIO::ExponentTransformRcPtr expTransform = OCIO::ExponentTransform::Create(); expTransform->setValue(exponent4f); - transform->setDisplayCC(expTransform); + vpt.setDisplayCC(expTransform); } OCIO::ConstProcessorRcPtr processor; try { - processor = config->getProcessor(transform); + processor = vpt.getProcessor(config, config->getCurrentContext()); } catch(OCIO::Exception & e) { @@ -450,13 +455,13 @@ void displayDevice_CB(int id) g_display = display; - const char * csname = config->getDisplayColorSpaceName(g_display.c_str(), g_transformName.c_str()); - if(!csname) + const char * csname = config->getDisplayViewColorSpaceName(g_display.c_str(), g_transformName.c_str()); + if (!csname || !*csname) { g_transformName = config->getDefaultView(g_display.c_str()); } - g_look = config->getDisplayLooks(g_display.c_str(), g_transformName.c_str()); + g_look = config->getDisplayViewLooks(g_display.c_str(), g_transformName.c_str()); UpdateOCIOGLState(); glutPostRedisplay(); @@ -471,7 +476,7 @@ void transform_CB(int id) g_transformName = transform; - g_look = config->getDisplayLooks(g_display.c_str(), g_transformName.c_str()); + g_look = config->getDisplayViewLooks(g_display.c_str(), g_transformName.c_str()); UpdateOCIOGLState(); glutPostRedisplay(); diff --git a/src/bindings/python/CMakeLists.txt b/src/bindings/python/CMakeLists.txt index d530bbf38f..8f6986b1fa 100644 --- a/src/bindings/python/CMakeLists.txt +++ b/src/bindings/python/CMakeLists.txt @@ -31,7 +31,7 @@ set(SOURCES PyBuiltinTransformRegistry.cpp PyCDLTransform.cpp PyColorSpaceTransform.cpp - PyDisplayTransform.cpp + PyDisplayViewTransform.cpp PyExponentTransform.cpp PyExponentWithLinearTransform.cpp PyExposureContrastTransform.cpp @@ -63,6 +63,7 @@ set(SOURCES PyGpuShaderCreator.cpp PyGpuShaderDesc.cpp PyContext.cpp + PyViewingRules.cpp ) add_library(PyOpenColorIO MODULE ${SOURCES} ${PYDOC_OUTPUT}) diff --git a/src/bindings/python/PyColorSpace.cpp b/src/bindings/python/PyColorSpace.cpp index f12a47ba34..cc20c0d191 100644 --- a/src/bindings/python/PyColorSpace.cpp +++ b/src/bindings/python/PyColorSpace.cpp @@ -49,6 +49,7 @@ void bindPyColorSpace(py::module & m) .def(py::init([](ReferenceSpaceType referenceSpace, const std::string & name, const std::string & family, + const std::string & encoding, const std::string & equalityGroup, const std::string & description, BitDepth bitDepth, @@ -62,6 +63,7 @@ void bindPyColorSpace(py::module & m) ColorSpaceRcPtr p = ColorSpace::Create(referenceSpace); if (!name.empty()) { p->setName(name.c_str()); } if (!family.empty()) { p->setFamily(family.c_str()); } + if (!encoding.empty()) { p->setEncoding(encoding.c_str()); } if (!equalityGroup.empty()) { p->setEqualityGroup(equalityGroup.c_str()); } if (!description.empty()) { p->setDescription(description.c_str()); } p->setBitDepth(bitDepth); @@ -96,6 +98,7 @@ void bindPyColorSpace(py::module & m) "referenceSpace"_a = DEFAULT->getReferenceSpaceType(), "name"_a = DEFAULT->getName(), "family"_a = DEFAULT->getFamily(), + "encoding"_a = DEFAULT->getEncoding(), "equalityGroup"_a = DEFAULT->getEqualityGroup(), "description"_a = DEFAULT->getDescription(), "bitDepth"_a = DEFAULT->getBitDepth(), @@ -104,12 +107,14 @@ void bindPyColorSpace(py::module & m) "allocationVars"_a = getAllocationVarsStdVec(DEFAULT), "toReference"_a = DEFAULT->getTransform(COLORSPACE_DIR_TO_REFERENCE), "fromReference"_a = DEFAULT->getTransform(COLORSPACE_DIR_FROM_REFERENCE), - "categories"_a = getCategoriesStdVec(DEFAULT)) + "categories"_a = getCategoriesStdVec(DEFAULT)) .def("getName", &ColorSpace::getName) .def("setName", &ColorSpace::setName, "name"_a) .def("getFamily", &ColorSpace::getFamily) .def("setFamily", &ColorSpace::setFamily, "family"_a) + .def("getEncoding", &ColorSpace::getEncoding) + .def("setEncoding", &ColorSpace::setEncoding, "encoding"_a) .def("getEqualityGroup", &ColorSpace::getEqualityGroup) .def("setEqualityGroup", &ColorSpace::setEqualityGroup, "equalityGroup"_a) .def("getDescription", &ColorSpace::getDescription) diff --git a/src/bindings/python/PyColorSpaceTransform.cpp b/src/bindings/python/PyColorSpaceTransform.cpp index 3e6dce8003..9dfd81e201 100644 --- a/src/bindings/python/PyColorSpaceTransform.cpp +++ b/src/bindings/python/PyColorSpaceTransform.cpp @@ -10,29 +10,34 @@ void bindPyColorSpaceTransform(py::module & m) { ColorSpaceTransformRcPtr DEFAULT = ColorSpaceTransform::Create(); - py::class_(m, "ColorSpaceTransform") .def(py::init(&ColorSpaceTransform::Create)) - .def(py::init([](const std::string & src, - const std::string & dst, - TransformDirection dir) + .def(py::init([](const std::string & src, + const std::string & dst, + TransformDirection dir, + bool dataBypass) { ColorSpaceTransformRcPtr p = ColorSpaceTransform::Create(); if (!src.empty()) { p->setSrc(src.c_str()); } if (!dst.empty()) { p->setDst(dst.c_str()); } p->setDirection(dir); + p->setDataBypass(dataBypass); p->validate(); return p; }), - "src"_a = DEFAULT->getSrc(), - "dst"_a = DEFAULT->getDst(), - "dir"_a = DEFAULT->getDirection()) + "src"_a = DEFAULT->getSrc(), + "dst"_a = DEFAULT->getDst(), + "dir"_a = DEFAULT->getDirection(), + "dataBypass"_a = DEFAULT->getDataBypass()) - .def("getSrc", &ColorSpaceTransform::getSrc) - .def("setSrc", &ColorSpaceTransform::setSrc, "src"_a) - .def("getDst", &ColorSpaceTransform::getDst) - .def("setDst", &ColorSpaceTransform::setDst, "dst"_a); + .def("getSrc", &ColorSpaceTransform::getSrc) + .def("setSrc", &ColorSpaceTransform::setSrc, "src"_a) + .def("getDst", &ColorSpaceTransform::getDst) + .def("setDst", &ColorSpaceTransform::setDst, "dst"_a) + .def("getDataBypass", &ColorSpaceTransform::getDataBypass) + .def("setDataBypass", &ColorSpaceTransform::setDataBypass, "dataBypass"_a); } } // namespace OCIO_NAMESPACE diff --git a/src/bindings/python/PyConfig.cpp b/src/bindings/python/PyConfig.cpp index 50e44de0f0..c64ba1f017 100644 --- a/src/bindings/python/PyConfig.cpp +++ b/src/bindings/python/PyConfig.cpp @@ -23,7 +23,9 @@ enum ConfigIterator IT_ROLE_NAME, IT_ROLE_COLOR_SPACE, IT_DISPLAY, - IT_VIEW, + IT_SHARED_VIEW, + IT_DISPLAY_VIEW, + IT_DISPLAY_VIEW_COLORSPACE, IT_LOOK_NAME, IT_LOOK, IT_VIEW_TRANSFORM_NAME, @@ -45,7 +47,10 @@ using ActiveColorSpaceIterator = PyIterator; using RoleColorSpaceIterator = PyIterator; using DisplayIterator = PyIterator; -using ViewIterator = PyIterator; +using SharedViewIterator = PyIterator; +using ViewIterator = PyIterator; +using ViewForColorSpaceIterator = PyIterator; using LookNameIterator = PyIterator; using LookIterator = PyIterator; using ViewTransformNameIterator = PyIterator; @@ -157,31 +162,53 @@ void bindPyConfig(py::module & m) .def("getRoles", [](ConfigRcPtr & self) { return RoleColorSpaceIterator(self); }) // Display/View Registration + .def("addSharedView", + (void (Config::*)(const char *, + const char *, + const char *, + const char *, + const char *, + const char *)) &Config::addSharedView, + "view"_a, "viewTransformName"_a, "colorSpaceName"_a, "looks"_a, + "ruleName"_a, "description"_a) + .def("removeSharedView", &Config::removeSharedView, "view"_a) + .def("getSharedViews", [](ConfigRcPtr & self) { return SharedViewIterator(self); }) .def("getDefaultDisplay", &Config::getDefaultDisplay) .def("getDisplays", [](ConfigRcPtr & self) { return DisplayIterator(self); }) .def("getDefaultView", &Config::getDefaultView, "display"_a) .def("getViews", [](ConfigRcPtr & self, const std::string & display) - { - return ViewIterator(self, display.c_str()); - }, + { + return ViewIterator(self, display); + }, "display"_a) + .def("getViews", + [](ConfigRcPtr & self, const std::string & display, const std::string & colorSpaceName) + { + return ViewForColorSpaceIterator(self, display, colorSpaceName); + }, + "display"_a, "colorSpaceName"_a) .def("getDisplayViewTransformName", &Config::getDisplayViewTransformName, "display"_a, "view"_a) - .def("getDisplayColorSpaceName", &Config::getDisplayColorSpaceName, "display"_a, "view"_a) - .def("getDisplayLooks", &Config::getDisplayLooks, "display"_a, "view"_a) - .def("addDisplay", + .def("getDisplayViewColorSpaceName", &Config::getDisplayViewColorSpaceName, "display"_a, "view"_a) + .def("getDisplayViewLooks", &Config::getDisplayViewLooks, "display"_a, "view"_a) + .def("getDisplayViewRule", &Config::getDisplayViewRule, "display"_a, "view"_a) + .def("getDisplayViewDescription", &Config::getDisplayViewDescription, "display"_a, "view"_a) + .def("addDisplayView", (void (Config::*)(const char *, const char *, const char *, const char *)) - &Config::addDisplay, + &Config::addDisplayView, "display"_a, "view"_a, "colorSpaceName"_a, "looks"_a) - .def("addDisplay", + .def("addDisplayView", (void (Config::*)(const char *, const char *, const char *, const char *, - const char *)) - &Config::addDisplay, - "display"_a, "view"_a, "viewTransform"_a, "displayColorSpaceName"_a, "looks"_a) - .def("removeDisplay", &Config::removeDisplay, "display"_a, "view"_a) + const char *, + const char *, + const char *)) &Config::addDisplayView, + "display"_a, "view"_a, "viewTransform"_a, "displayColorSpaceName"_a, "looks"_a, + "ruleName"_a, "description"_a) + .def("addDisplaySharedView", &Config::addDisplaySharedView, "display"_a, "view"_a) + .def("removeDisplayView", &Config::removeDisplayView, "display"_a, "view"_a) .def("clearDisplays", &Config::clearDisplays) .def("setActiveDisplays", &Config::setActiveDisplays, "displays"_a) .def("getActiveDisplays", &Config::getActiveDisplays) @@ -223,6 +250,10 @@ void bindPyConfig(py::module & m) &Config::getDefaultSceneToDisplayViewTransform) .def("clearViewTransforms", &Config::clearViewTransforms) + // Viewing Rules + .def("getViewingRules", &Config::getViewingRules) + .def("setViewingRules", &Config::setViewingRules, "ViewingRules"_a) + // File Rules .def("getFileRules", &Config::getFileRules) .def("setFileRules", &Config::setFileRules, "fileRules"_a) @@ -251,24 +282,24 @@ void bindPyConfig(py::module & m) .def("getProcessor", (ConstProcessorRcPtr (Config::*)(const char *, const char *) const) &Config::getProcessor, - "srcName"_a, "dstName"_a) + "srcColorSpaceName"_a, "dstColorSpaceName"_a) .def("getProcessor", (ConstProcessorRcPtr (Config::*)(const ConstContextRcPtr &, const char *, const char *) const) &Config::getProcessor, - "context"_a, "srcName"_a, "dstName"_a) + "context"_a, "srcColorSpaceName"_a, "dstColorSpaceName"_a) .def("getProcessor", (ConstProcessorRcPtr (Config::*)(const char *, const char *, const char *) const) &Config::getProcessor, - "inputColorSpaceName"_a, "display"_a, "view"_a) + "srcColorSpaceName"_a, "display"_a, "view"_a) .def("getProcessor", (ConstProcessorRcPtr (Config::*)(const ConstContextRcPtr &, const char *, const char *, const char *) const) &Config::getProcessor, - "context"_a, "inputColorSpaceName"_a, "display"_a, "view"_a) + "context"_a, "srcColorSpaceName"_a, "display"_a, "view"_a) .def("getProcessor", (ConstProcessorRcPtr (Config::*)(const ConstTransformRcPtr &) const) &Config::getProcessor, @@ -286,51 +317,52 @@ void bindPyConfig(py::module & m) "context"_a, "transform"_a, "direction"_a) .def_static("GetProcessor", [](const ConstConfigRcPtr & srcConfig, - const char * srcName, + const char * srcColorSpaceName, const ConstConfigRcPtr & dstConfig, - const char * dstName) + const char * dstColorSpaceName) { - return Config::GetProcessor(srcConfig, srcName, dstConfig, dstName); + return Config::GetProcessor(srcConfig, srcColorSpaceName, + dstConfig, dstColorSpaceName); }, - "srcConfig"_a, "srcName"_a, "dstConfig"_a, "dstName"_a) + "srcConfig"_a, "srcColorSpaceName"_a, "dstConfig"_a, "dstColorSpaceName"_a) .def_static("GetProcessor", [](const ConstContextRcPtr & srcContext, const ConstConfigRcPtr & srcConfig, - const char * srcName, + const char * srcColorSpaceName, const ConstContextRcPtr & dstContext, const ConstConfigRcPtr & dstConfig, - const char * dstName) + const char * dstColorSpaceName) { - return Config::GetProcessor(srcContext, srcConfig, srcName, - dstContext, dstConfig, dstName); + return Config::GetProcessor(srcContext, srcConfig, srcColorSpaceName, + dstContext, dstConfig, dstColorSpaceName); }, - "srcContext"_a, "srcConfig"_a, "srcName"_a, - "dstContext"_a, "dstConfig"_a, "dstName"_a) + "srcContext"_a, "srcConfig"_a, "srcColorSpaceName"_a, + "dstContext"_a, "dstConfig"_a, "dstColorSpaceName"_a) .def_static("GetProcessor", [](const ConstConfigRcPtr & srcConfig, - const char * srcName, + const char * srcColorSpaceName, const char * srcInterchangeName, const ConstConfigRcPtr & dstConfig, - const char * dstName, + const char * dstColorSpaceName, const char * dstInterchangeName) { - return Config::GetProcessor(srcConfig, srcName, srcInterchangeName, - dstConfig, dstName, dstInterchangeName); + return Config::GetProcessor(srcConfig, srcColorSpaceName, srcInterchangeName, + dstConfig, dstColorSpaceName, dstInterchangeName); }, - "srcConfig"_a, "srcName"_a, "srcInterchangeName"_a, - "dstConfig"_a, "dstName"_a, "dstInterchangeName"_a) + "srcConfig"_a, "srcColorSpaceName"_a, "srcInterchangeName"_a, + "dstConfig"_a, "dstColorSpaceName"_a, "dstInterchangeName"_a) .def_static("GetProcessor", [](const ConstContextRcPtr & srcContext, const ConstConfigRcPtr & srcConfig, - const char * srcName, + const char * srcColorSpaceName, const char * srcInterchangeName, const ConstContextRcPtr & dstContext, const ConstConfigRcPtr & dstConfig, - const char * dstName, + const char * dstColorSpaceName, const char * dstInterchangeName) { - return Config::GetProcessor(srcContext, srcConfig, srcName, srcInterchangeName, - dstContext, dstConfig, dstName, dstInterchangeName); + return Config::GetProcessor(srcContext, srcConfig, srcColorSpaceName, srcInterchangeName, + dstContext, dstConfig, dstColorSpaceName, dstInterchangeName); }, - "srcContext"_a, "srcConfig"_a, "srcName"_a, "srcInterchangeName"_a, - "dstContext"_a, "dstConfig"_a, "dstName"_a, "dstInterchangeName"_a); + "srcContext"_a, "srcConfig"_a, "srcColorSpaceName"_a, "srcInterchangeName"_a, + "dstContext"_a, "dstConfig"_a, "dstColorSpaceName"_a, "dstInterchangeName"_a); defStr(cls); @@ -511,18 +543,54 @@ void bindPyConfig(py::module & m) return it.m_obj->getDisplay(i); }); + py::class_(cls, "SharedViewIterator") + .def("__len__", [](SharedViewIterator & it) { return it.m_obj->getNumViews(VIEW_SHARED, + nullptr); }) + .def("__getitem__", [](SharedViewIterator & it, int i) + { + it.checkIndex(i, it.m_obj->getNumViews(VIEW_SHARED, nullptr)); + return it.m_obj->getView(VIEW_SHARED, nullptr, i); + }) + .def("__iter__", [](SharedViewIterator & it) -> SharedViewIterator & { return it; }) + .def("__next__", [](SharedViewIterator & it) + { + int i = it.nextIndex(it.m_obj->getNumViews(VIEW_SHARED, nullptr)); + return it.m_obj->getView(VIEW_SHARED, nullptr, i); + }); + py::class_(cls, "ViewIterator") - .def("__len__", [](ViewIterator & it) { return it.m_obj->getNumViews(std::get<0>(it.m_args)); }) - .def("__getitem__", [](ViewIterator & it, int i) + .def("__len__", [](ViewIterator & it) + { return it.m_obj->getNumViews(std::get<0>(it.m_args).c_str()); }) + .def("__getitem__", [](ViewIterator & it, int i) { - it.checkIndex(i, it.m_obj->getNumViews(std::get<0>(it.m_args))); - return it.m_obj->getView(std::get<0>(it.m_args), i); + it.checkIndex(i, it.m_obj->getNumViews(std::get<0>(it.m_args).c_str())); + return it.m_obj->getView(std::get<0>(it.m_args).c_str(), i); }) .def("__iter__", [](ViewIterator & it) -> ViewIterator & { return it; }) .def("__next__", [](ViewIterator & it) { - int i = it.nextIndex(it.m_obj->getNumViews(std::get<0>(it.m_args))); - return it.m_obj->getView(std::get<0>(it.m_args), i); + int i = it.nextIndex(it.m_obj->getNumViews(std::get<0>(it.m_args).c_str())); + return it.m_obj->getView(std::get<0>(it.m_args).c_str(), i); + }); + + py::class_(cls, "ViewForColorSpaceIterator") + .def("__len__", [](ViewForColorSpaceIterator & it) + { return it.m_obj->getNumViews(std::get<0>(it.m_args).c_str(), + std::get<1>(it.m_args).c_str()); }) + .def("__getitem__", [](ViewForColorSpaceIterator & it, int i) + { + it.checkIndex(i, it.m_obj->getNumViews(std::get<0>(it.m_args).c_str(), + std::get<1>(it.m_args).c_str())); + return it.m_obj->getView(std::get<0>(it.m_args).c_str(), + std::get<1>(it.m_args).c_str(), i); + }) + .def("__iter__", [](ViewForColorSpaceIterator & it) -> ViewForColorSpaceIterator & { return it; }) + .def("__next__", [](ViewForColorSpaceIterator & it) + { + int i = it.nextIndex(it.m_obj->getNumViews(std::get<0>(it.m_args).c_str(), + std::get<1>(it.m_args).c_str())); + return it.m_obj->getView(std::get<0>(it.m_args).c_str(), + std::get<1>(it.m_args).c_str(), i); }); py::class_(cls, "LookNameIterator") diff --git a/src/bindings/python/PyDisplayTransform.cpp b/src/bindings/python/PyDisplayTransform.cpp deleted file mode 100644 index 5b9532e521..0000000000 --- a/src/bindings/python/PyDisplayTransform.cpp +++ /dev/null @@ -1,76 +0,0 @@ -// SPDX-License-Identifier: BSD-3-Clause -// Copyright Contributors to the OpenColorIO Project. - -#include "PyTransform.h" - -namespace OCIO_NAMESPACE -{ - -void bindPyDisplayTransform(py::module & m) -{ - DisplayTransformRcPtr DEFAULT = DisplayTransform::Create(); - - py::class_(m, "DisplayTransform") - .def(py::init(&DisplayTransform::Create)) - .def(py::init([](const std::string & inputColorSpaceName, - TransformRcPtr linearCC, - TransformRcPtr colorTimingCC, - TransformRcPtr channelView, - const std::string & display, - const std::string & view, - TransformRcPtr displayCC, - const std::string & looksOverride, - bool looksOverrideEnabled, - TransformDirection dir) - { - DisplayTransformRcPtr p = DisplayTransform::Create(); - if (!inputColorSpaceName.empty()) - { - p->setInputColorSpaceName(inputColorSpaceName.c_str()); - } - if (linearCC) { p->setLinearCC(linearCC); } - if (colorTimingCC) { p->setColorTimingCC(colorTimingCC); } - if (channelView) { p->setChannelView(channelView); } - if (!display.empty()) { p->setDisplay(display.c_str()); } - if (!view.empty()) { p->setView(view.c_str()); } - if (displayCC) { p->setDisplayCC(displayCC); } - if (!looksOverride.empty()) { p->setLooksOverride(looksOverride.c_str()); } - p->setLooksOverrideEnabled(looksOverrideEnabled); - p->setDirection(dir); - p->validate(); - return p; - }), - "inputColorSpaceName"_a = DEFAULT->getInputColorSpaceName(), - "linearCC"_a = DEFAULT->getLinearCC(), - "colorTimingCC"_a = DEFAULT->getColorTimingCC(), - "channelView"_a = DEFAULT->getChannelView(), - "display"_a = DEFAULT->getDisplay(), - "view"_a = DEFAULT->getView(), - "displayCC"_a = DEFAULT->getDisplayCC(), - "looksOvveride"_a = DEFAULT->getLooksOverride(), - "looksOverrideEnabled"_a = DEFAULT->getLooksOverrideEnabled(), - "dir"_a = DEFAULT->getDirection()) - - .def("getInputColorSpaceName", &DisplayTransform::getInputColorSpaceName) - .def("setInputColorSpaceName", &DisplayTransform::setInputColorSpaceName, "name"_a) - .def("getLinearCC", &DisplayTransform::getLinearCC) - .def("setLinearCC", &DisplayTransform::setLinearCC, "cc"_a) - .def("getColorTimingCC", &DisplayTransform::getColorTimingCC) - .def("setColorTimingCC", &DisplayTransform::setColorTimingCC, "cc"_a) - .def("getChannelView", &DisplayTransform::getChannelView) - .def("setChannelView", &DisplayTransform::setChannelView, "transform"_a) - .def("getDisplay", &DisplayTransform::getDisplay) - .def("setDisplay", &DisplayTransform::setDisplay, "display"_a) - .def("getView", &DisplayTransform::getView) - .def("setView", &DisplayTransform::setView, "view"_a) - .def("getDisplayCC", &DisplayTransform::getDisplayCC) - .def("setDisplayCC", &DisplayTransform::setDisplayCC, "cc"_a) - .def("getLooksOverride", &DisplayTransform::getLooksOverride) - .def("setLooksOverride", &DisplayTransform::setLooksOverride, "looks"_a) - .def("getLooksOverrideEnabled", &DisplayTransform::getLooksOverrideEnabled) - .def("setLooksOverrideEnabled", &DisplayTransform::setLooksOverrideEnabled, "enabled"_a); -} - -} // namespace OCIO_NAMESPACE diff --git a/src/bindings/python/PyDisplayViewTransform.cpp b/src/bindings/python/PyDisplayViewTransform.cpp new file mode 100644 index 0000000000..c75021c459 --- /dev/null +++ b/src/bindings/python/PyDisplayViewTransform.cpp @@ -0,0 +1,53 @@ +// SPDX-License-Identifier: BSD-3-Clause +// Copyright Contributors to the OpenColorIO Project. + +#include "PyTransform.h" + +namespace OCIO_NAMESPACE +{ + +void bindPyDisplayViewTransform(py::module & m) +{ + DisplayViewTransformRcPtr DEFAULT = DisplayViewTransform::Create(); + + py::class_(m, "DisplayViewTransform") + .def(py::init(&DisplayViewTransform::Create)) + .def(py::init([](const std::string & src, + const std::string & display, + const std::string & view, + bool looksBypass, + bool dataBypass, + TransformDirection dir) + { + DisplayViewTransformRcPtr p = DisplayViewTransform::Create(); + if (!src.empty()) { p->setSrc(src.c_str()); } + if (!display.empty()) { p->setDisplay(display.c_str()); } + if (!view.empty()) { p->setView(view.c_str()); } + p->setLooksBypass(looksBypass); + p->setDataBypass(dataBypass); + p->setDirection(dir); + p->validate(); + return p; + }), + "src"_a = DEFAULT->getSrc(), + "display"_a = DEFAULT->getDisplay(), + "view"_a = DEFAULT->getView(), + "looksBypass"_a = DEFAULT->getLooksBypass(), + "dataBypass"_a = DEFAULT->getDataBypass(), + "dir"_a = DEFAULT->getDirection()) + + .def("getSrc", &DisplayViewTransform::getSrc) + .def("setSrc", &DisplayViewTransform::setSrc, "src"_a) + .def("getDisplay", &DisplayViewTransform::getDisplay) + .def("setDisplay", &DisplayViewTransform::setDisplay, "display"_a) + .def("getView", &DisplayViewTransform::getView) + .def("setView", &DisplayViewTransform::setView, "view"_a) + .def("getLooksBypass", &DisplayViewTransform::getLooksBypass) + .def("setLooksBypass", &DisplayViewTransform::setLooksBypass, "looksBypass"_a) + .def("getDataBypass", &DisplayViewTransform::getDataBypass) + .def("setDataBypass", &DisplayViewTransform::setDataBypass, "dataBypass"_a); +} + +} // namespace OCIO_NAMESPACE diff --git a/src/bindings/python/PyLookTransform.cpp b/src/bindings/python/PyLookTransform.cpp index 482cbd16c0..275a322e49 100644 --- a/src/bindings/python/PyLookTransform.cpp +++ b/src/bindings/python/PyLookTransform.cpp @@ -14,30 +14,36 @@ void bindPyLookTransform(py::module & m) LookTransformRcPtr /* holder */, Transform /* base */>(m, "LookTransform") .def(py::init(&LookTransform::Create)) - .def(py::init([](const std::string & src, - const std::string & dst, - const std::string & looks, - TransformDirection dir) + .def(py::init([](const std::string & src, + const std::string & dst, + const std::string & looks, + TransformDirection dir, + bool skipColorSpaceConversion) { LookTransformRcPtr p = LookTransform::Create(); if (!src.empty()) { p->setSrc(src.c_str()); } if (!dst.empty()) { p->setDst(dst.c_str()); } if (!looks.empty()) { p->setLooks(looks.c_str()); } p->setDirection(dir); + p->setSkipColorSpaceConversion(skipColorSpaceConversion); p->validate(); return p; }), - "src"_a = DEFAULT->getSrc(), - "dst"_a = DEFAULT->getDst(), + "src"_a = DEFAULT->getSrc(), + "dst"_a = DEFAULT->getDst(), "looks"_a = DEFAULT->getLooks(), - "dir"_a = DEFAULT->getDirection()) + "dir"_a = DEFAULT->getDirection(), + "skipColorSpaceConversion"_a = DEFAULT->getSkipColorSpaceConversion()) .def("getSrc", &LookTransform::getSrc) .def("setSrc", &LookTransform::setSrc, "src"_a) .def("getDst", &LookTransform::getDst) .def("setDst", &LookTransform::setDst, "dst"_a) .def("getLooks", &LookTransform::getLooks) - .def("setLooks", &LookTransform::setLooks, "looks"_a); + .def("setLooks", &LookTransform::setLooks, "looks"_a) + .def("getSkipColorSpaceConversion", &LookTransform::getSkipColorSpaceConversion) + .def("setSkipColorSpaceConversion", &LookTransform::setSkipColorSpaceConversion, + "skipColorSpaceConversion"_a); } } // namespace OCIO_NAMESPACE diff --git a/src/bindings/python/PyOpenColorIO.cpp b/src/bindings/python/PyOpenColorIO.cpp index 12cd9be12b..427e325790 100644 --- a/src/bindings/python/PyOpenColorIO.cpp +++ b/src/bindings/python/PyOpenColorIO.cpp @@ -40,6 +40,7 @@ PYBIND11_MODULE(PyOpenColorIO, m) bindPyImageDesc(m); bindPyGpuShaderCreator(m); bindPyContext(m); + bindPyViewingRules(m); } } // namespace OCIO_NAMESPACE diff --git a/src/bindings/python/PyOpenColorIO.h b/src/bindings/python/PyOpenColorIO.h index 58b2b8c4bd..c1a4a254eb 100644 --- a/src/bindings/python/PyOpenColorIO.h +++ b/src/bindings/python/PyOpenColorIO.h @@ -35,6 +35,7 @@ void bindPyBaker(py::module & m); void bindPyImageDesc(py::module & m); void bindPyGpuShaderCreator(py::module & m); void bindPyContext(py::module & m); +void bindPyViewingRules(py::module & m); } // namespace OCIO_NAMESPACE @@ -65,9 +66,9 @@ struct polymorphic_type_hook { { type = &typeid(OCIO::ColorSpaceTransform); } - else if(dynamic_cast(src)) + else if(dynamic_cast(src)) { - type = &typeid(OCIO::DisplayTransform); + type = &typeid(OCIO::DisplayViewTransform); } else if(dynamic_cast(src)) { diff --git a/src/bindings/python/PyTransform.cpp b/src/bindings/python/PyTransform.cpp index f5b206c614..09b2244295 100644 --- a/src/bindings/python/PyTransform.cpp +++ b/src/bindings/python/PyTransform.cpp @@ -24,7 +24,7 @@ void bindPyTransform(py::module & m) bindPyBuiltinTransform(m); bindPyCDLTransform(m); bindPyColorSpaceTransform(m); - bindPyDisplayTransform(m); + bindPyDisplayViewTransform(m); bindPyExponentTransform(m); bindPyExponentWithLinearTransform(m); bindPyExposureContrastTransform(m); diff --git a/src/bindings/python/PyTransform.h b/src/bindings/python/PyTransform.h index e11b348e2e..4353fe066f 100644 --- a/src/bindings/python/PyTransform.h +++ b/src/bindings/python/PyTransform.h @@ -21,7 +21,7 @@ void bindPyAllocationTransform(py::module & m); void bindPyBuiltinTransform(py::module & m); void bindPyCDLTransform(py::module & m); void bindPyColorSpaceTransform(py::module & m); -void bindPyDisplayTransform(py::module & m); +void bindPyDisplayViewTransform(py::module & m); void bindPyExponentTransform(py::module & m); void bindPyExponentWithLinearTransform(py::module & m); void bindPyExposureContrastTransform(py::module & m); diff --git a/src/bindings/python/PyViewingRules.cpp b/src/bindings/python/PyViewingRules.cpp new file mode 100644 index 0000000000..9c110fee2b --- /dev/null +++ b/src/bindings/python/PyViewingRules.cpp @@ -0,0 +1,83 @@ +// SPDX-License-Identifier: BSD-3-Clause +// Copyright Contributors to the OpenColorIO Project. + +#include "PyOpenColorIO.h" +#include "PyUtils.h" + +namespace OCIO_NAMESPACE +{ + +enum ViewingRuleIterator +{ + IT_VIEWING_RULE_COLOR_SPACE = 0, + IT_VIEWING_RULE_ENCODING +}; + +using ViewingRuleColorSpaceIterator = PyIterator; +using ViewingRuleEncodingIterator = PyIterator; + +void bindPyViewingRules(py::module & m) +{ + auto cls = py::class_(m, "ViewingRules") + .def(py::init(&ViewingRules::Create)) + + .def("getNumEntries", &ViewingRules::getNumEntries) + .def("getIndexForRule", &ViewingRules::getIndexForRule, "ruleName"_a) + .def("getName", &ViewingRules::getName, "ruleIndex"_a) + .def("getColorSpaces", + [](ViewingRulesRcPtr & self, size_t ruleIndex) + { + return ViewingRuleColorSpaceIterator(self, ruleIndex); + }, + "ruleIndex"_a) + .def("addColorSpace", &ViewingRules::addColorSpace, "ruleIndex"_a, "colorSpaceName"_a) + .def("removeColorSpace", &ViewingRules::removeColorSpace, "ruleIndex"_a, "colorSpaceIndex"_a) + .def("getEncodings", + [](ViewingRulesRcPtr & self, size_t ruleIndex) + { + return ViewingRuleEncodingIterator(self, ruleIndex); + }, + "ruleIndex"_a) + .def("addEncoding", &ViewingRules::addEncoding, "ruleIndex"_a, "encodingName"_a) + .def("removeEncoding", &ViewingRules::removeEncoding, "ruleIndex"_a, "encodingIndex"_a) + .def("getNumCustomKeys", &ViewingRules::getNumCustomKeys, "ruleIndex"_a) + .def("getCustomKeyName", &ViewingRules::getCustomKeyName, "ruleIndex"_a, "key"_a) + .def("getCustomKeyValue", &ViewingRules::getCustomKeyValue, "ruleIndex"_a, "key"_a) + .def("setCustomKey", &ViewingRules::setCustomKey, "ruleIndex"_a, "key"_a, "value"_a) + .def("insertRule", + (void (ViewingRules::*)(size_t, const char *)) &ViewingRules::insertRule, + "ruleIndex"_a, "name"_a) + .def("removeRule", &ViewingRules::removeRule, "ruleIndex"_a); + + py::class_(cls, "ViewingRuleColorSpaceIterator") + .def("__len__", [](ViewingRuleColorSpaceIterator & it) { return it.m_obj->getNumColorSpaces(std::get<0>(it.m_args)); }) + .def("__getitem__", [](ViewingRuleColorSpaceIterator & it, size_t i) + { + it.checkIndex(static_cast(i), + static_cast(it.m_obj->getNumColorSpaces(std::get<0>(it.m_args)))); + return it.m_obj->getColorSpace(std::get<0>(it.m_args), i); + }) + .def("__iter__", [](ViewingRuleColorSpaceIterator & it) -> ViewingRuleColorSpaceIterator & { return it; }) + .def("__next__", [](ViewingRuleColorSpaceIterator & it) + { + int i = it.nextIndex(static_cast(it.m_obj->getNumColorSpaces(std::get<0>(it.m_args)))); + return it.m_obj->getColorSpace(std::get<0>(it.m_args), i); + }); + + py::class_(cls, "ViewingRuleEncodingIterator") + .def("__len__", [](ViewingRuleEncodingIterator & it) { return it.m_obj->getNumEncodings(std::get<0>(it.m_args)); }) + .def("__getitem__", [](ViewingRuleEncodingIterator & it, size_t i) + { + it.checkIndex(static_cast(i), + static_cast(it.m_obj->getNumEncodings(std::get<0>(it.m_args)))); + return it.m_obj->getEncoding(std::get<0>(it.m_args), i); + }) + .def("__iter__", [](ViewingRuleEncodingIterator & it) -> ViewingRuleEncodingIterator & { return it; }) + .def("__next__", [](ViewingRuleEncodingIterator & it) + { + int i = it.nextIndex(static_cast(it.m_obj->getNumEncodings(std::get<0>(it.m_args)))); + return it.m_obj->getEncoding(std::get<0>(it.m_args), i); + }); +} + +} // namespace OCIO_NAMESPACE diff --git a/src/libutils/apphelpers/CMakeLists.txt b/src/libutils/apphelpers/CMakeLists.txt index ee97fe1b23..5df1f72f38 100644 --- a/src/libutils/apphelpers/CMakeLists.txt +++ b/src/libutils/apphelpers/CMakeLists.txt @@ -6,6 +6,7 @@ set(SOURCES ColorSpaceHelpers.cpp DisplayViewHelpers.cpp MixingHelpers.cpp + ViewingPipeline.cpp ) set(INCLUDES @@ -13,6 +14,7 @@ set(INCLUDES ColorSpaceHelpers.h DisplayViewHelpers.h MixingHelpers.h + ViewingPipeline.h ) # Some include files are private to the library. diff --git a/src/libutils/apphelpers/DisplayViewHelpers.cpp b/src/libutils/apphelpers/DisplayViewHelpers.cpp index c4a161cbd8..42561b480b 100644 --- a/src/libutils/apphelpers/DisplayViewHelpers.cpp +++ b/src/libutils/apphelpers/DisplayViewHelpers.cpp @@ -15,6 +15,7 @@ #include "ColorSpaceHelpers.h" #include "DisplayViewHelpers.h" #include "utils/StringUtils.h" +#include "ViewingPipeline.h" namespace OCIO_NAMESPACE @@ -27,13 +28,14 @@ ConstProcessorRcPtr GetProcessor(const ConstConfigRcPtr & config, const char * workingName, const char * displayName, const char * viewName, + const ConstMatrixTransformRcPtr & channelView, TransformDirection direction) { ColorSpaceMenuHelperRcPtr menuHelper = ColorSpaceMenuHelper::Create(config, nullptr, nullptr); - DisplayTransformRcPtr displayTransform = DisplayTransform::Create(); + DisplayViewTransformRcPtr displayTransform = DisplayViewTransform::Create(); displayTransform->setDirection(direction); - displayTransform->setInputColorSpaceName(menuHelper->getNameFromUIName(workingName)); + displayTransform->setSrc(menuHelper->getNameFromUIName(workingName)); displayTransform->setDisplay(displayName); displayTransform->setView(viewName); @@ -64,9 +66,13 @@ ConstProcessorRcPtr GetProcessor(const ConstConfigRcPtr & config, } } - // Note: Reuse the DisplayTransform instance to benefit from any improvement - // made to the (display, view) color transformation i.e. - // ViewTransform + DisplayColorSpace and inverse computation. + if (!needExposure && !needGamma && !channelView) + { + return processor; + } + + ViewingPipeline pipeline; + pipeline.setDisplayViewTransform(displayTransform); // TODO: Need to update to allow for apps that are viewing non-scene-linear images. if (needExposure) @@ -79,7 +85,7 @@ ConstProcessorRcPtr GetProcessor(const ConstConfigRcPtr & config, ex->makeExposureDynamic(); ex->makeContrastDynamic(); - displayTransform->setLinearCC(ex); + pipeline.setLinearCC(ex); } if (needGamma) @@ -90,10 +96,16 @@ ConstProcessorRcPtr GetProcessor(const ConstConfigRcPtr & config, ex->makeGammaDynamic(); - displayTransform->setDisplayCC(ex); + pipeline.setDisplayCC(ex); + } + + if (channelView) + { + pipeline.setChannelView(channelView); } - return config->getProcessor(displayTransform); + ConstContextRcPtr context = config->getCurrentContext(); + return pipeline.getProcessor(config, context); } @@ -393,7 +405,7 @@ void AddDisplayView(ConfigRcPtr & config, // Step 4 - Add a new active (display, view) pair. - config->addDisplay(displayName, viewName, colorSpace->getName(), lookDefinition); + config->addDisplayView(displayName, viewName, colorSpace->getName(), lookDefinition); } void AddDisplayView(ConfigRcPtr & config, @@ -445,7 +457,8 @@ void AddDisplayView(ConfigRcPtr & config, void RemoveDisplayView(ConfigRcPtr & config, const char * displayName, const char * viewName) { - const std::string csName{ config->getDisplayColorSpaceName(displayName, viewName) }; + const std::string name{ config->getDisplayViewColorSpaceName(displayName, viewName) }; + const std::string csName{ name.empty() ? displayName : name }; if (csName.empty()) { std::string errMsg = "Missing color space for '"; @@ -458,7 +471,7 @@ void RemoveDisplayView(ConfigRcPtr & config, const char * displayName, const cha // Step 1 - Remove the (display, view) pair. - config->removeDisplay(displayName, viewName); + config->removeDisplayView(displayName, viewName); // Setp 2 - Remove the (display, view) pair from active lists if possible. diff --git a/src/libutils/apphelpers/DisplayViewHelpers.h b/src/libutils/apphelpers/DisplayViewHelpers.h index ed1ab0a5be..8e9d73da2c 100644 --- a/src/libutils/apphelpers/DisplayViewHelpers.h +++ b/src/libutils/apphelpers/DisplayViewHelpers.h @@ -22,6 +22,7 @@ ConstProcessorRcPtr GetProcessor(const ConstConfigRcPtr & config, const char * workingName, const char * displayName, const char * viewName, + const ConstMatrixTransformRcPtr & channelView, // Can be null. TransformDirection direction); // Add a new (display, view) pair and the new color space to a configuration instance. diff --git a/src/libutils/apphelpers/MixingHelpers.cpp b/src/libutils/apphelpers/MixingHelpers.cpp index 350d2d9721..be1094a92f 100644 --- a/src/libutils/apphelpers/MixingHelpers.cpp +++ b/src/libutils/apphelpers/MixingHelpers.cpp @@ -375,8 +375,11 @@ ConstProcessorRcPtr MixingColorSpaceManagerImpl::getProcessorWithoutEncoding(con if (getSelectedMixingSpaceIdx()>0) { // Mix colors in the selected (display, view) space. - return DisplayViewHelpers::GetProcessor(m_config, workingName, displayName, viewName, - TRANSFORM_DIR_FORWARD); + auto dt = DisplayViewTransform::Create(); + dt->setDisplay(displayName); + dt->setView(viewName); + dt->setSrc(workingName); + return m_config->getProcessor(dt); } else { diff --git a/src/libutils/apphelpers/ViewingPipeline.cpp b/src/libutils/apphelpers/ViewingPipeline.cpp new file mode 100644 index 0000000000..12e5813782 --- /dev/null +++ b/src/libutils/apphelpers/ViewingPipeline.cpp @@ -0,0 +1,372 @@ +// SPDX-License-Identifier: BSD-3-Clause +// Copyright Contributors to the OpenColorIO Project. + +#include +#include +#include + +#include + +#include "utils/StringUtils.h" +#include "ViewingPipeline.h" + +namespace OCIO_NAMESPACE +{ + +ConstDisplayViewTransformRcPtr ViewingPipeline::getDisplayViewTransform() const noexcept +{ + return m_displayViewTransform; +} + +void ViewingPipeline::setDisplayViewTransform(const ConstDisplayViewTransformRcPtr & dt) noexcept +{ + if (dt) + { + TransformRcPtr tr = dt->createEditableCopy(); + m_displayViewTransform = OCIO_DYNAMIC_POINTER_CAST(tr); + m_dtOriginalLooksBypass = m_displayViewTransform->getLooksBypass(); + m_displayViewTransform->setLooksBypass(true); + } + else + { + m_displayViewTransform = DisplayViewTransformRcPtr(); + } +} + +ConstTransformRcPtr ViewingPipeline::getLinearCC() const noexcept +{ + return m_linearCC; +} + +void ViewingPipeline::setLinearCC(const ConstTransformRcPtr & cc) noexcept +{ + if (cc) + { + m_linearCC = cc->createEditableCopy(); + } + else + { + m_linearCC = TransformRcPtr(); + } +} + +ConstTransformRcPtr ViewingPipeline::getColorTimingCC() const noexcept +{ + return m_colorTimingCC; +} + +void ViewingPipeline::setColorTimingCC(const ConstTransformRcPtr & cc) noexcept +{ + if (cc) + { + m_colorTimingCC = cc->createEditableCopy(); + } + else + { + m_colorTimingCC = TransformRcPtr(); + } +} + +ConstTransformRcPtr ViewingPipeline::getChannelView() const noexcept +{ + return m_channelView; +} + +void ViewingPipeline::setChannelView(const ConstTransformRcPtr & transform) noexcept +{ + if (transform) + { + m_channelView = transform->createEditableCopy(); + } + else + { + m_channelView = TransformRcPtr(); + } +} + +ConstTransformRcPtr ViewingPipeline::getDisplayCC() const noexcept +{ + return m_displayCC; +} + +void ViewingPipeline::setDisplayCC(const ConstTransformRcPtr & cc) noexcept +{ + if (cc) + { + m_displayCC = cc->createEditableCopy(); + } + else + { + m_displayCC = TransformRcPtr(); + } +} + + +void ViewingPipeline::setLooksOverrideEnabled(bool enable) +{ + m_looksOverrideEnabled = enable; +} + +bool ViewingPipeline::getLooksOverrideEnabled() const +{ + return m_looksOverrideEnabled; +} + +void ViewingPipeline::setLooksOverride(const std::string & looks) +{ + m_looksOverride = looks; +} + +const std::string & ViewingPipeline::getLooksOverride() const +{ + return m_looksOverride; +} + +void ViewingPipeline::validate() const +{ + if (!m_displayViewTransform) + { + throw Exception("ViewingPipeline: can't create a processor without " + "a display transform."); + } + + try + { + m_displayViewTransform->validate(); + + if (m_linearCC) + { + m_linearCC->validate(); + } + if (m_colorTimingCC) + { + m_colorTimingCC->validate(); + } + if (m_channelView) + { + m_channelView->validate(); + } + if (m_displayCC) + { + m_displayCC->validate(); + } + } + catch (Exception & e) + { + std::ostringstream oss; + oss << "ViewingPipeline is not valid: " + << e.what(); + throw Exception(oss.str().c_str()); + } +} + +ConstProcessorRcPtr ViewingPipeline::getProcessor(const ConstConfigRcPtr & configIn, + const ConstContextRcPtr & context) const +{ + validate(); + + // Get direction from display transform. + TransformDirection dir = m_displayViewTransform->getDirection(); + + ConstConfigRcPtr config = configIn; + + const std::string inputColorSpaceName = m_displayViewTransform->getSrc(); + ConstColorSpaceRcPtr inputColorSpace = config->getColorSpace(inputColorSpaceName.c_str()); + + if (!inputColorSpace) + { + std::ostringstream os; + os << "ViewingPipeline error: "; + if (inputColorSpaceName.empty()) + { + os << "InputColorSpaceName is unspecified."; + } + else + { + os << "Cannot find inputColorSpace, named '" << inputColorSpaceName << "'."; + } + throw Exception(os.str().c_str()); + } + + const std::string display = m_displayViewTransform->getDisplay(); + const std::string view = m_displayViewTransform->getView(); + + const std::string viewTransformName = config->getDisplayViewTransformName(display.c_str(), + view.c_str()); + ConstViewTransformRcPtr viewTransform; + if (!viewTransformName.empty()) + { + viewTransform = config->getViewTransform(viewTransformName.c_str()); + } + + // NB: If the viewTranform is present, then displayColorSpace is a true display color space + // rather than a traditional color space. + const std::string name{ config->getDisplayViewColorSpaceName(display.c_str(), view.c_str()) }; + // A shared view containing a view transform may set the color space to USE_DISPLAY_NAME, + // in which case we look for a display color space with the same name as the display. + const bool nameFromDisplay = (0 == strcmp(name.c_str(), OCIO_VIEW_USE_DISPLAY_NAME)); + const std::string displayColorSpaceName{ nameFromDisplay ? display : name }; + ConstColorSpaceRcPtr displayColorSpace = config->getColorSpace(displayColorSpaceName.c_str()); + if (!displayColorSpace) + { + std::ostringstream os; + os << "DisplayViewTransform error: "; + if (displayColorSpaceName.empty()) + { + os << "DisplayColorSpaceName is unspecified."; + } + else + { + os << "Cannot find display colorspace, '" << displayColorSpaceName << "'."; + } + throw Exception(os.str().c_str()); + } + + const bool dataBypass = m_displayViewTransform->getDataBypass(); + bool skipColorSpaceConversions = dataBypass && + (inputColorSpace->isData() || displayColorSpace->isData()); + + if (dataBypass) + { + // If we're viewing alpha, also skip all color space conversions. + // If the user does uses a different transform for the channel view, + // in place of a simple matrix, they run the risk that when viewing alpha + // the colorspace transforms will not be skipped. (I.e., filmlook will be applied + // to alpha.) If this ever becomes an issue, additional engineering will be + // added at that time. + + auto typedChannelView = DynamicPtrCast(m_channelView); + if (typedChannelView) + { + double matrix44[16]; + typedChannelView->getMatrix(matrix44); + + if ((matrix44[3]>0.0) || (matrix44[7]>0.0) || (matrix44[11]>0.0)) + { + skipColorSpaceConversions = true; + } + } + } + + std::string currentCSName{ inputColorSpaceName }; + ConstColorSpaceRcPtr dtInputColorSpace = inputColorSpace; + + GroupTransformRcPtr group = GroupTransform::Create(); + + if (m_linearCC) + { + auto linearCC = config->getProcessor(context, m_linearCC, dir); + // If it is a no-op, dont bother doing the colorspace conversion. + if (!linearCC->isNoOp()) + { + auto sceneLinearCS = config->getColorSpace(ROLE_SCENE_LINEAR); + dtInputColorSpace = sceneLinearCS; + if (!dtInputColorSpace) + { + std::ostringstream os; + os << "DisplayViewTransform error:"; + os << " LinearCC requires '" << std::string(ROLE_SCENE_LINEAR); + os << "' role to be defined."; + throw Exception(os.str().c_str()); + } + + if (!skipColorSpaceConversions) + { + auto cst = ColorSpaceTransform::Create(); + cst->setSrc(currentCSName.c_str()); + cst->setDst(ROLE_SCENE_LINEAR); + currentCSName = ROLE_SCENE_LINEAR; + group->appendTransform(cst); + } + + group->appendTransform(m_linearCC); + } + } + + if (m_colorTimingCC) + { + auto colorTimingCC = config->getProcessor(context, m_colorTimingCC, dir); + // If it is a no-op, dont bother doing the colorspace conversion. + if (!colorTimingCC->isNoOp()) + { + auto colorTimingCS = config->getColorSpace(ROLE_COLOR_TIMING); + dtInputColorSpace = colorTimingCS; + if (!dtInputColorSpace) + { + std::ostringstream os; + os << "DisplayViewTransform error:"; + os << " ColorTimingCC requires '" << std::string(ROLE_COLOR_TIMING); + os << "' role to be defined."; + throw Exception(os.str().c_str()); + } + + if (!skipColorSpaceConversions) + { + auto cst = ColorSpaceTransform::Create(); + cst->setSrc(currentCSName.c_str()); + cst->setDst(ROLE_COLOR_TIMING); + currentCSName = ROLE_COLOR_TIMING; + group->appendTransform(cst); + } + group->appendTransform(m_colorTimingCC); + } + } + + TransformRcPtr trans = m_displayViewTransform->createEditableCopy(); + DisplayViewTransformRcPtr dt = OCIO_DYNAMIC_POINTER_CAST(trans); + dt->setDirection(TRANSFORM_DIR_FORWARD); + + // Adjust display transform input color space. + dt->setSrc(currentCSName.c_str()); + + // NB: If looksOverrideEnabled is true, always apply the look, even to data color spaces. + // In other cases, follow what the DisplayViewTransform would do, except skip color space conversions + // to the process space for Look transforms for data spaces (DisplayViewTransform never skips). + std::string looks; + if (m_looksOverrideEnabled) + { + looks = m_looksOverride; + } + else if (!m_dtOriginalLooksBypass && !skipColorSpaceConversions) + { + looks = config->getDisplayViewLooks(display.c_str(), view.c_str()); + } + + if (!looks.empty()) + { + const char * inCS = dtInputColorSpace->getName(); + const char * outCS = skipColorSpaceConversions ? inCS : + LookTransform::GetLooksResultColorSpace(configIn, context, + looks.c_str()); + auto lt = LookTransform::Create(); + lt->setSrc(inCS); + lt->setDst(outCS); + lt->setLooks(looks.c_str()); + lt->setSkipColorSpaceConversion(skipColorSpaceConversions); + + group->appendTransform(lt); + + // Adjust display transform input color space. + dt->setSrc(outCS); + } + + if (m_channelView) + { + group->appendTransform(m_channelView); + } + + if (!skipColorSpaceConversions) + { + group->appendTransform(dt); + } + + if (m_displayCC) + { + group->appendTransform(m_displayCC); + } + + return config->getProcessor(context, group, dir); +} + +} // namespace OCIO_NAMESPACE + diff --git a/src/libutils/apphelpers/ViewingPipeline.h b/src/libutils/apphelpers/ViewingPipeline.h new file mode 100644 index 0000000000..cdd06e9990 --- /dev/null +++ b/src/libutils/apphelpers/ViewingPipeline.h @@ -0,0 +1,106 @@ +// SPDX-License-Identifier: BSD-3-Clause +// Copyright Contributors to the OpenColorIO Project. + + +#ifndef INCLUDED_OCIO_VIEWINGPIPELINE_H +#define INCLUDED_OCIO_VIEWINGPIPELINE_H + + +#include + +#include + + +namespace OCIO_NAMESPACE +{ + +// Whereas the DisplayViewTransform in OCIO core simply applies a specific view from an OCIO +// display, the ViewingPipeline provides an example of a complete viewing pipeline of the sort +// that could be used to implement a viewport in a typical application. It therefore adds, around +// the DisplayViewTransform, various optional color correction steps and RGBA channel view +// swizzling. The direction of the DisplayViewTranform is used as the direction of the pipeline. +// Note: The ViewingPipeline class provides the same functionality as the OCIO v1 DisplayTransform. +// +// Viewing pipeline: +// * Start in display transform input color space. +// * If linearCC is provided: +// * Go to scene_linear colorspace. +// * Apply linearCC transform. +// * If colorTimingCC is provided: +// * Go to color_timing colorspace. +// * Apply colorTimingCC transform. +// * Apply looks (from display transform or from looks override). +// * Go to first look color space. +// * Apply first look transform. +// * Iterate for all looks. +// * Apply channelView transform. +// * Apply display transform (without looks). +// * Apply displayCC. +// Note that looks are applied even if the display transform involves data color spaces. + +class ViewingPipeline +{ +public: + ViewingPipeline() = default; + ~ViewingPipeline() = default; + + ViewingPipeline(const ViewingPipeline &) = delete; + ViewingPipeline & operator=(const ViewingPipeline &) = delete; + + ConstDisplayViewTransformRcPtr getDisplayViewTransform() const noexcept; + void setDisplayViewTransform(const ConstDisplayViewTransformRcPtr & dt) noexcept; + + ConstTransformRcPtr getLinearCC() const noexcept; + void setLinearCC(const ConstTransformRcPtr & cc) noexcept; + + ConstTransformRcPtr getColorTimingCC() const noexcept; + void setColorTimingCC(const ConstTransformRcPtr & cc) noexcept; + + ConstTransformRcPtr getChannelView() const noexcept; + void setChannelView(const ConstTransformRcPtr & transform) noexcept; + + ConstTransformRcPtr getDisplayCC() const noexcept; + void setDisplayCC(const ConstTransformRcPtr & cc) noexcept; + + // Specify whether the lookOverride should be used, or not. This is a separate flag, as + // it's often useful to override "looks" to an empty string. + void setLooksOverrideEnabled(bool enable); + bool getLooksOverrideEnabled() const; + + // A user can optionally override the looks that are, by default, used with the expected + // display / view combination. A common use case for this functionality is in an image + // viewing app, where per-shot looks are supported. If for some reason a per-shot look is + // not defined for the current Context, the Config::getProcessor fcn will not succeed by + // default. Thus, with this mechanism the viewing app could override to looks = "", and + // this will allow image display to continue (though hopefully) the interface would reflect + // this fallback option.) + // + // Looks is a potentially comma (or colon) delimited list of lookNames, Where +/- prefixes + // are optionally allowed to denote forward/inverse look specification. (And forward is + // assumed in the absence of either) + void setLooksOverride(const std::string & looks); + const std::string & getLooksOverride() const; + + ConstProcessorRcPtr getProcessor(const ConstConfigRcPtr & config, + const ConstContextRcPtr & context) const; + +protected: + void validate() const; + +private: + TransformRcPtr m_linearCC; + TransformRcPtr m_colorTimingCC; + TransformRcPtr m_channelView; + TransformRcPtr m_displayCC; + DisplayViewTransformRcPtr m_displayViewTransform; + // Looks from DisplayViewTransform are applied separately. + bool m_dtOriginalLooksBypass{ false }; + + bool m_looksOverrideEnabled{ false }; + std::string m_looksOverride; +}; + +} // namespace OCIO_NAMESPACE + + +#endif // INCLUDED_OCIO_VIEWINGPIPELINETRANSFORM_H diff --git a/tests/apphelpers/CMakeLists.txt b/tests/apphelpers/CMakeLists.txt index 202ec70b20..62fbd7ce96 100644 --- a/tests/apphelpers/CMakeLists.txt +++ b/tests/apphelpers/CMakeLists.txt @@ -8,6 +8,7 @@ set(SOURCES DisplayViewHelpers_tests.cpp MixingHelpers_tests.cpp UnitTestMain.cpp + ViewingPipeline_tests.cpp ) add_executable(test_apphelpers_exec ${SOURCES}) diff --git a/tests/apphelpers/DisplayViewHelpers_tests.cpp b/tests/apphelpers/DisplayViewHelpers_tests.cpp index 5782fdb31d..8f544e0059 100644 --- a/tests/apphelpers/DisplayViewHelpers_tests.cpp +++ b/tests/apphelpers/DisplayViewHelpers_tests.cpp @@ -86,7 +86,7 @@ OCIO_ADD_TEST(DisplayViewHelpers, basic) userTransform->setSrc(filePath.c_str()); OCIO_CHECK_NO_THROW( - OCIO::DisplayViewHelpers::AddDisplayView(config, + OCIO::DisplayViewHelpers::AddDisplayView(config, "DISP_1", "VIEW_5", "look_3", *csInfo, userTransform, "cat1, cat2", "lut_input_1")); @@ -101,10 +101,10 @@ OCIO_ADD_TEST(DisplayViewHelpers, basic) OCIO_CHECK_NO_THROW(val = config->getView("DISP_1", 3)); OCIO_CHECK_EQUAL(std::string(val), "VIEW_5"); - OCIO_CHECK_NO_THROW(val = config->getDisplayColorSpaceName("DISP_1", "VIEW_5")); + OCIO_CHECK_NO_THROW(val = config->getDisplayViewColorSpaceName("DISP_1", "VIEW_5")); OCIO_CHECK_EQUAL(std::string(val), "view_5"); - OCIO_CHECK_NO_THROW(val = config->getDisplayLooks("DISP_1", "VIEW_5")); + OCIO_CHECK_NO_THROW(val = config->getDisplayViewLooks("DISP_1", "VIEW_5")); OCIO_CHECK_EQUAL(std::string(val), "look_3"); // @@ -126,8 +126,9 @@ OCIO_ADD_TEST(DisplayViewHelpers, basic) // OCIO::ConstProcessorRcPtr processor; OCIO_CHECK_NO_THROW( - processor = OCIO::DisplayViewHelpers::GetProcessor(cfg, + processor = OCIO::DisplayViewHelpers::GetProcessor(cfg, "lin_1", "DISP_1", "VIEW_5", + OCIO::ConstMatrixTransformRcPtr(), OCIO::TRANSFORM_DIR_FORWARD)); OCIO::GroupTransformRcPtr groupTransform; @@ -182,7 +183,7 @@ OCIO_ADD_TEST(DisplayViewHelpers, basic) OCIO_CHECK_EQUAL(cdl->getDirection(), OCIO::TRANSFORM_DIR_FORWARD); - double rgb[3] = { -1 }; + double rgb[3] = { -1. }; OCIO_CHECK_NO_THROW(cdl->getSlope(rgb)); OCIO_CHECK_EQUAL(rgb[0], 1.); OCIO_CHECK_EQUAL(rgb[1], 2.); @@ -223,7 +224,7 @@ OCIO_ADD_TEST(DisplayViewHelpers, basic) OCIO_CHECK_EQUAL(exp->getDirection(), OCIO::TRANSFORM_DIR_INVERSE); - double values[4] = { -1 }; + double values[4] = { -1. }; exp->getValue(values); OCIO_CHECK_EQUAL(values[0], 2.6); @@ -362,6 +363,7 @@ OCIO_ADD_TEST(DisplayViewHelpers, display_view_without_look) OCIO_CHECK_NO_THROW( processor = OCIO::DisplayViewHelpers::GetProcessor(cfg, "lin_1", "DISP_1", "VIEW_1", + OCIO::ConstMatrixTransformRcPtr(), OCIO::TRANSFORM_DIR_FORWARD)); OCIO_CHECK_NO_THROW(groupTransform = processor->createGroupTransform()); @@ -378,6 +380,7 @@ OCIO_ADD_TEST(DisplayViewHelpers, display_view_without_look) OCIO_CHECK_NO_THROW( processor = OCIO::DisplayViewHelpers::GetProcessor(cfg, "lin_1", "DISP_1", "VIEW_1", + OCIO::ConstMatrixTransformRcPtr(), OCIO::TRANSFORM_DIR_INVERSE)); OCIO_CHECK_NO_THROW(groupTransform = processor->createGroupTransform()); @@ -388,6 +391,36 @@ OCIO_ADD_TEST(DisplayViewHelpers, display_view_without_look) exp = OCIO::DynamicPtrCast(tr); OCIO_REQUIRE_ASSERT(exp); OCIO_CHECK_EQUAL(exp->getDirection(), OCIO::TRANSFORM_DIR_FORWARD); + + // Forward with a channel view matrix. + + auto cv = OCIO::MatrixTransform::Create(); + double mat[] = { 1.0, 0.0, 0.0, 0.0, + 0.0, 0.0, 0.0, 0.0, + 0.0, 0.0, 0.0, 0.0, + 0.0, 0.0, 0.0, 0.0 }; + cv->setMatrix(mat); + + OCIO_CHECK_NO_THROW( + processor = OCIO::DisplayViewHelpers::GetProcessor(cfg, + "lin_1", "DISP_1", "VIEW_1", + cv, + OCIO::TRANSFORM_DIR_FORWARD)); + + OCIO_CHECK_NO_THROW(groupTransform = processor->createGroupTransform()); + OCIO_CHECK_NO_THROW(groupTransform->validate()); + OCIO_REQUIRE_EQUAL(groupTransform->getNumTransforms(), 4); + + OCIO_CHECK_NO_THROW(tr = groupTransform->getTransform(1)); + auto mt = OCIO::DynamicPtrCast(tr); + OCIO_REQUIRE_ASSERT(mt); + OCIO_CHECK_EQUAL(mt->getDirection(), OCIO::TRANSFORM_DIR_FORWARD); + mt->getMatrix(mat); + OCIO_CHECK_EQUAL(mat[0], 1.); + OCIO_CHECK_EQUAL(mat[5], 0.); + + // Inverse test with a channel view matrix can't be done because channel view matrix + // is singular and inversion will fail. } namespace @@ -451,7 +484,7 @@ OCIO_ADD_TEST(DisplayViewHelpers, active_display_view) userTransform->setSrc(filePath.c_str()); OCIO_CHECK_NO_THROW( - OCIO::DisplayViewHelpers::AddDisplayView(cfg, + OCIO::DisplayViewHelpers::AddDisplayView(cfg, "DISP_1", "VIEW_5", nullptr, *csInfo, userTransform, "cat1, cat2", "lut_input_1")); @@ -514,7 +547,7 @@ OCIO_ADD_TEST(DisplayViewHelpers, active_display_view) OCIO_CHECK_EQUAL(cfg->getView("DISP_1", 2), std::string("VIEW_3")); OCIO_CHECK_THROW_WHAT( - OCIO::DisplayViewHelpers::AddDisplayView(cfg, + OCIO::DisplayViewHelpers::AddDisplayView(cfg, "DISP_5", "VIEW_5", nullptr, *csInfo, userTransform, "cat1, cat2", "lut_input_1"), @@ -540,7 +573,7 @@ OCIO_ADD_TEST(DisplayViewHelpers, active_display_view) OCIO_CHECK_EQUAL(cfg->getView("DISP_1", 1), std::string("VIEW_2")); OCIO_CHECK_THROW_WHAT( - OCIO::DisplayViewHelpers::AddDisplayView(cfg, + OCIO::DisplayViewHelpers::AddDisplayView(cfg, "DISP_1", "VIEW_5", nullptr, *csInfo, userTransform, "cat1, cat2", "lut_input_1"), diff --git a/tests/apphelpers/MixingHelpers_tests.cpp b/tests/apphelpers/MixingHelpers_tests.cpp index 35946f8d1c..3a7b48f851 100644 --- a/tests/apphelpers/MixingHelpers_tests.cpp +++ b/tests/apphelpers/MixingHelpers_tests.cpp @@ -105,26 +105,13 @@ OCIO_ADD_TEST(MixingColorSpaceManager, basic) OCIO::GroupTransformRcPtr groupTransform; OCIO_CHECK_NO_THROW(groupTransform = processor->createGroupTransform()); OCIO_CHECK_NO_THROW(groupTransform->validate()); - OCIO_REQUIRE_EQUAL(groupTransform->getNumTransforms(), 4); + OCIO_REQUIRE_EQUAL(groupTransform->getNumTransforms(), 2); OCIO::ConstTransformRcPtr tr; { OCIO_CHECK_NO_THROW(tr = groupTransform->getTransform(0)); - OCIO::ConstExposureContrastTransformRcPtr ec - = OCIO::DynamicPtrCast(tr); - OCIO_REQUIRE_ASSERT(ec); - - OCIO_CHECK_EQUAL(ec->getStyle(), OCIO::EXPOSURE_CONTRAST_LINEAR); - OCIO_CHECK_ASSERT(ec->isExposureDynamic()); - OCIO_CHECK_ASSERT(ec->isContrastDynamic()); - OCIO_CHECK_ASSERT(!ec->isGammaDynamic()); - } - - { - OCIO_CHECK_NO_THROW(tr = groupTransform->getTransform(1)); - OCIO::ConstExponentTransformRcPtr exp = OCIO::DynamicPtrCast(tr); OCIO_REQUIRE_ASSERT(exp); @@ -141,20 +128,7 @@ OCIO_ADD_TEST(MixingColorSpaceManager, basic) } { - OCIO_CHECK_NO_THROW(tr = groupTransform->getTransform(2)); - - OCIO::ConstExposureContrastTransformRcPtr ec - = OCIO::DynamicPtrCast(tr); - OCIO_REQUIRE_ASSERT(ec); - - OCIO_CHECK_EQUAL(ec->getStyle(), OCIO::EXPOSURE_CONTRAST_VIDEO); - OCIO_CHECK_ASSERT(!ec->isExposureDynamic()); - OCIO_CHECK_ASSERT(!ec->isContrastDynamic()); - OCIO_CHECK_ASSERT(ec->isGammaDynamic()); - } - - { - OCIO_CHECK_NO_THROW(tr = groupTransform->getTransform(3)); + OCIO_CHECK_NO_THROW(tr = groupTransform->getTransform(1)); OCIO::ConstFixedFunctionTransformRcPtr ff = OCIO::DynamicPtrCast(tr); diff --git a/tests/apphelpers/ViewingPipeline_tests.cpp b/tests/apphelpers/ViewingPipeline_tests.cpp new file mode 100644 index 0000000000..8403462e61 --- /dev/null +++ b/tests/apphelpers/ViewingPipeline_tests.cpp @@ -0,0 +1,846 @@ +// SPDX-License-Identifier: BSD-3-Clause +// Copyright Contributors to the OpenColorIO Project. + + +#include + +#include + +#include "testutils/UnitTest.h" +#include "UnitTestLogUtils.h" +#include "ViewingPipeline.h" + + +namespace OCIO = OCIO_NAMESPACE; + + +#ifndef OCIO_UNIT_TEST_FILES_DIR +#error Expecting OCIO_UNIT_TEST_FILES_DIR to be defined for tests. Check relevant CMakeLists.txt +#endif + +#define STR(x) FIELD_STR(x) + +static const std::string ocioTestFilesDir(STR(OCIO_UNIT_TEST_FILES_DIR)); + + +// The configuration file used by the unit tests. +#include "configs.data" + + +OCIO_ADD_TEST(ViewingPipeline, basic) +{ + // Validate default values. + OCIO::ViewingPipeline vp; + auto dt = vp.getDisplayViewTransform(); + OCIO_CHECK_ASSERT(!dt); + auto cv = vp.getChannelView(); + OCIO_CHECK_ASSERT(!cv); + auto ctcc = vp.getColorTimingCC(); + OCIO_CHECK_ASSERT(!ctcc); + auto dcc = vp.getDisplayCC(); + OCIO_CHECK_ASSERT(!dcc); + auto lcc = vp.getLinearCC(); + OCIO_CHECK_ASSERT(!lcc); + OCIO_CHECK_ASSERT(!vp.getLooksOverrideEnabled()); + OCIO_CHECK_EQUAL(vp.getLooksOverride(), ""); + + // An empty viewing pipeline transform is not valid. + OCIO::ConfigRcPtr config = OCIO::Config::CreateRaw()->createEditableCopy(); + OCIO_CHECK_THROW_WHAT(vp.getProcessor(config, config->getCurrentContext()), + OCIO::Exception, + "can't create a processor without a display transform"); + + // Validate setters. + + OCIO::DisplayViewTransformRcPtr dte = OCIO::DisplayViewTransform::Create(); + vp.setDisplayViewTransform(dte); + dt = vp.getDisplayViewTransform(); + OCIO_CHECK_ASSERT(dt); + + // Display transform member has to be valid. + OCIO_CHECK_THROW_WHAT(vp.getProcessor(config, config->getCurrentContext()), + OCIO::Exception, + "ViewingPipeline is not valid: " + "DisplayViewTransform: empty source color space name"); + + dte->setSrc("colorspace1"); + vp.setDisplayViewTransform(dte); + + // Display transform still invalid: missing display/view. + OCIO_CHECK_THROW_WHAT(vp.getProcessor(config, config->getCurrentContext()), + OCIO::Exception, + "ViewingPipeline is not valid: " + "DisplayViewTransform: empty display name"); + + dte->setDisplay("sRGB"); + dte->setView("view1"); + vp.setDisplayViewTransform(dte); + + // Validation is fine but missing elements in config. + OCIO_CHECK_THROW_WHAT(vp.getProcessor(config, config->getCurrentContext()), + OCIO::Exception, + "ViewingPipeline error: Cannot find inputColorSpace, " + "named 'colorspace1'"); + + auto cs = OCIO::ColorSpace::Create(); + cs->setName("colorspace1"); + cs->setTransform(OCIO::FixedFunctionTransform::Create(), OCIO::COLORSPACE_DIR_FROM_REFERENCE); + config->addColorSpace(cs); + + config->addDisplayView("sRGB", "view1", "colorspace1", ""); + + OCIO::ConstProcessorRcPtr proc; + OCIO_CHECK_NO_THROW(proc = vp.getProcessor(config, config->getCurrentContext())); + OCIO_CHECK_ASSERT(proc); + + OCIO::TransformRcPtr empty; + auto ff = OCIO::FixedFunctionTransform::Create(); + vp.setChannelView(ff); + cv = vp.getChannelView(); + OCIO_CHECK_ASSERT(cv); + OCIO_CHECK_NO_THROW(proc = vp.getProcessor(config, config->getCurrentContext())); + OCIO_CHECK_ASSERT(proc); + vp.setChannelView(empty); + cv = vp.getChannelView(); + OCIO_CHECK_ASSERT(!cv); + + vp.setColorTimingCC(ff); + ctcc = vp.getColorTimingCC(); + OCIO_CHECK_ASSERT(ctcc); + // Missing element: color_timing role. + OCIO_CHECK_THROW_WHAT(vp.getProcessor(config, config->getCurrentContext()), + OCIO::Exception, + "ColorTimingCC requires 'color_timing' role to be defined"); + vp.setColorTimingCC(empty); + ctcc = vp.getColorTimingCC(); + OCIO_CHECK_ASSERT(!ctcc); + + vp.setLinearCC(ff); + lcc = vp.getLinearCC(); + OCIO_CHECK_ASSERT(lcc); + // Missing element: scene_linear role. + OCIO_CHECK_THROW_WHAT(vp.getProcessor(config, config->getCurrentContext()), + OCIO::Exception, + "LinearCC requires 'scene_linear' role to be defined"); + vp.setLinearCC(empty); + lcc = vp.getLinearCC(); + OCIO_CHECK_ASSERT(!lcc); + + vp.setDisplayCC(ff); + dcc = vp.getDisplayCC(); + OCIO_CHECK_ASSERT(dcc); + OCIO_CHECK_NO_THROW(proc = vp.getProcessor(config, config->getCurrentContext())); + OCIO_CHECK_ASSERT(proc); + vp.setDisplayCC(empty); + dcc = vp.getDisplayCC(); + OCIO_CHECK_ASSERT(!dcc); + + vp.setLooksOverride("missingLook"); + OCIO_CHECK_EQUAL(vp.getLooksOverride(), "missingLook"); + + // Look is missing but looks override is not enabled. + OCIO_CHECK_NO_THROW(proc = vp.getProcessor(config, config->getCurrentContext())); + OCIO_CHECK_ASSERT(proc); + + vp.setLooksOverrideEnabled(true); + OCIO_CHECK_ASSERT(vp.getLooksOverrideEnabled()); + + // Missing look error. + OCIO_CHECK_THROW_WHAT(vp.getProcessor(config, config->getCurrentContext()), + OCIO::Exception, + "The specified look, 'missingLook', cannot be found"); +} + +OCIO_ADD_TEST(ViewingPipeline, processorWithLooks) +{ + std::istringstream is(category_test_config); + + OCIO::ConstConfigRcPtr cfg; + OCIO_CHECK_NO_THROW(cfg = OCIO::Config::CreateFromStream(is)); + OCIO_CHECK_NO_THROW(cfg->sanityCheck()); + + OCIO::DisplayViewTransformRcPtr dt = OCIO::DisplayViewTransform::Create(); + dt->setDisplay("DISP_2"); + dt->setView("VIEW_2"); + dt->setSrc("in_1"); + OCIO::ViewingPipeline vp; + vp.setDisplayViewTransform(dt); + + auto mat = OCIO::MatrixTransform::Create(); + double m[16] = { 1.1, 0., 0., 0., + 0., 1.2, 0., 0., + 0., 0., 1.1, 0., + 0., 0., 0., 1. }; + mat->setMatrix(m); + vp.setChannelView(mat); + + auto ff = OCIO::FixedFunctionTransform::Create(); + vp.setLinearCC(ff); + + // Processor in forward direction. + + OCIO::ConstProcessorRcPtr proc; + OCIO_CHECK_NO_THROW(proc = vp.getProcessor(cfg, cfg->getCurrentContext())); + OCIO_REQUIRE_ASSERT(proc); + + OCIO::GroupTransformRcPtr groupTransform; + OCIO_CHECK_NO_THROW(groupTransform = proc->createGroupTransform()); + + OCIO_REQUIRE_ASSERT(groupTransform); + OCIO_CHECK_NO_THROW(groupTransform->validate()); + OCIO_REQUIRE_EQUAL(groupTransform->getNumTransforms(), 8); + // LinearCC creates a color space conversion and a transform. + { + // Color space conversion from in_1 to scene_linear role (lin_1 color space). + OCIO::ConstTransformRcPtr tr; + OCIO_CHECK_NO_THROW(tr = groupTransform->getTransform(0)); + + OCIO::ConstExponentTransformRcPtr exp + = OCIO::DynamicPtrCast(tr); + OCIO_REQUIRE_ASSERT(exp); + + OCIO_CHECK_EQUAL(exp->getDirection(), OCIO::TRANSFORM_DIR_FORWARD); + + double values[4] = { -1. }; + exp->getValue(values); + + OCIO_CHECK_EQUAL(values[0], 2.6); + OCIO_CHECK_EQUAL(values[1], 2.6); + OCIO_CHECK_EQUAL(values[2], 2.6); + OCIO_CHECK_EQUAL(values[3], 1.); + + // LinearCC transform. + OCIO_CHECK_NO_THROW(tr = groupTransform->getTransform(1)); + + OCIO::ConstFixedFunctionTransformRcPtr fft + = OCIO::DynamicPtrCast(tr); + OCIO_REQUIRE_ASSERT(fft); + + OCIO_CHECK_EQUAL(fft->getDirection(), OCIO::TRANSFORM_DIR_FORWARD); + } + // Apply the looks, channel view, and view transform. + { + OCIO::ConstTransformRcPtr tr; + // Lin_1 to look3 process space (log_1). + OCIO_CHECK_NO_THROW(tr = groupTransform->getTransform(2)); + OCIO::ConstLogTransformRcPtr log = OCIO::DynamicPtrCast(tr); + OCIO_REQUIRE_ASSERT(log); + OCIO_CHECK_EQUAL(log->getDirection(), OCIO::TRANSFORM_DIR_FORWARD); + OCIO_CHECK_EQUAL(log->getBase(), 2.); + + // Look_3 transform. + OCIO_CHECK_NO_THROW(tr = groupTransform->getTransform(3)); + OCIO::ConstCDLTransformRcPtr cdl = OCIO::DynamicPtrCast(tr); + OCIO_REQUIRE_ASSERT(cdl); + OCIO_CHECK_EQUAL(cdl->getDirection(), OCIO::TRANSFORM_DIR_FORWARD); + double rgb[3] = { -1. }; + OCIO_CHECK_NO_THROW(cdl->getSlope(rgb)); + OCIO_CHECK_EQUAL(rgb[0], 1.); + OCIO_CHECK_EQUAL(rgb[1], 2.); + OCIO_CHECK_EQUAL(rgb[2], 1.); + + // Look_3 & look_4 have the same process space, no color space conversion. + + // Look_4 transform. + OCIO_CHECK_NO_THROW(tr = groupTransform->getTransform(4)); + cdl = OCIO::DynamicPtrCast(tr); + OCIO_REQUIRE_ASSERT(cdl); + OCIO_CHECK_EQUAL(cdl->getDirection(), OCIO::TRANSFORM_DIR_INVERSE); + OCIO_CHECK_NO_THROW(cdl->getSlope(rgb)); + OCIO_CHECK_EQUAL(rgb[0], 1.2); + OCIO_CHECK_EQUAL(rgb[1], 2.2); + OCIO_CHECK_EQUAL(rgb[2], 1.2); + + // Channel View transform (no color space conversion). + OCIO_CHECK_NO_THROW(tr = groupTransform->getTransform(5)); + OCIO::ConstMatrixTransformRcPtr mattr = OCIO::DynamicPtrCast(tr); + OCIO_REQUIRE_ASSERT(mattr); + OCIO_CHECK_EQUAL(mattr->getDirection(), OCIO::TRANSFORM_DIR_FORWARD); + mattr->getMatrix(m); + OCIO_CHECK_EQUAL(m[0], 1.1); + OCIO_CHECK_EQUAL(m[1], 0); + OCIO_CHECK_EQUAL(m[2], 0); + OCIO_CHECK_EQUAL(m[3], 0); + OCIO_CHECK_EQUAL(m[5], 1.2); + OCIO_CHECK_EQUAL(m[10], 1.1); + + // Look_4 process color space (log_1) to reference. + OCIO_CHECK_NO_THROW(tr = groupTransform->getTransform(6)); + log = OCIO::DynamicPtrCast(tr); + OCIO_REQUIRE_ASSERT(log); + OCIO_CHECK_EQUAL(log->getDirection(), OCIO::TRANSFORM_DIR_INVERSE); + OCIO_CHECK_EQUAL(log->getBase(), 2.); + + // Reference to view_2 color space. + OCIO_CHECK_NO_THROW(tr = groupTransform->getTransform(7)); + OCIO::ConstExponentTransformRcPtr exp + = OCIO::DynamicPtrCast(tr); + OCIO_REQUIRE_ASSERT(exp); + + OCIO_CHECK_EQUAL(exp->getDirection(), OCIO::TRANSFORM_DIR_INVERSE); + + double values[4] = { -1. }; + exp->getValue(values); + + OCIO_CHECK_EQUAL(values[0], 2.4); + OCIO_CHECK_EQUAL(values[1], 2.4); + OCIO_CHECK_EQUAL(values[2], 2.4); + OCIO_CHECK_EQUAL(values[3], 1.); + } + + // Repeat in inverse direction. + + dt->setDirection(OCIO::TRANSFORM_DIR_INVERSE); + vp.setDisplayViewTransform(dt); + OCIO_CHECK_NO_THROW(proc = vp.getProcessor(cfg, cfg->getCurrentContext())); + OCIO_REQUIRE_ASSERT(proc); + + OCIO_CHECK_NO_THROW(groupTransform = proc->createGroupTransform()); + + OCIO_REQUIRE_ASSERT(groupTransform); + OCIO_CHECK_NO_THROW(groupTransform->validate()); + OCIO_REQUIRE_EQUAL(groupTransform->getNumTransforms(), 8); + + // Apply the inverse view transform, channel view, and looks. + { + OCIO::ConstTransformRcPtr tr; + + // View_2 to reference. + OCIO_CHECK_NO_THROW(tr = groupTransform->getTransform(0)); + auto exp = OCIO::DynamicPtrCast(tr); + OCIO_REQUIRE_ASSERT(exp); + + OCIO_CHECK_EQUAL(exp->getDirection(), OCIO::TRANSFORM_DIR_FORWARD); + + double values[4] = { -1. }; + exp->getValue(values); + + OCIO_CHECK_EQUAL(values[0], 2.4); + OCIO_CHECK_EQUAL(values[1], 2.4); + OCIO_CHECK_EQUAL(values[2], 2.4); + OCIO_CHECK_EQUAL(values[3], 1.); + + // Reference to look_4 process color space (log_1). + OCIO_CHECK_NO_THROW(tr = groupTransform->getTransform(1)); + auto log = OCIO::DynamicPtrCast(tr); + OCIO_REQUIRE_ASSERT(log); + OCIO_CHECK_EQUAL(log->getDirection(), OCIO::TRANSFORM_DIR_FORWARD); + OCIO_CHECK_EQUAL(log->getBase(), 2.); + + // Channel View transform. + OCIO_CHECK_NO_THROW(tr = groupTransform->getTransform(2)); + auto mattr = OCIO::DynamicPtrCast(tr); + OCIO_REQUIRE_ASSERT(mattr); + OCIO_CHECK_EQUAL(mattr->getDirection(), OCIO::TRANSFORM_DIR_FORWARD); + mattr->getMatrix(m); + OCIO_CHECK_EQUAL(m[0], 1 / 1.1); + OCIO_CHECK_EQUAL(m[5], 1 / 1.2); + OCIO_CHECK_EQUAL(m[10], 1 / 1.1); + + // Look_4 transform. + OCIO_CHECK_NO_THROW(tr = groupTransform->getTransform(3)); + auto cdl = OCIO::DynamicPtrCast(tr); + OCIO_REQUIRE_ASSERT(cdl); + OCIO_CHECK_EQUAL(cdl->getDirection(), OCIO::TRANSFORM_DIR_FORWARD); + double rgb[3] = { -1. }; + OCIO_CHECK_NO_THROW(cdl->getSlope(rgb)); + OCIO_CHECK_EQUAL(rgb[0], 1.2); + OCIO_CHECK_EQUAL(rgb[1], 2.2); + OCIO_CHECK_EQUAL(rgb[2], 1.2); + + // Look_3 transform. + OCIO_CHECK_NO_THROW(tr = groupTransform->getTransform(4)); + cdl = OCIO::DynamicPtrCast(tr); + OCIO_REQUIRE_ASSERT(cdl); + OCIO_CHECK_EQUAL(cdl->getDirection(), OCIO::TRANSFORM_DIR_INVERSE); + OCIO_CHECK_NO_THROW(cdl->getSlope(rgb)); + OCIO_CHECK_EQUAL(rgb[0], 1.); + OCIO_CHECK_EQUAL(rgb[1], 2.); + OCIO_CHECK_EQUAL(rgb[2], 1.); + + // Look_3 process color space (log_1) to lin_1. + OCIO_CHECK_NO_THROW(tr = groupTransform->getTransform(5)); + log = OCIO::DynamicPtrCast(tr); + OCIO_REQUIRE_ASSERT(log); + OCIO_CHECK_EQUAL(log->getDirection(), OCIO::TRANSFORM_DIR_INVERSE); + OCIO_CHECK_EQUAL(log->getBase(), 2.); + } + // LinearCC color space conversion and transform. + { + // LinearCC transform. + OCIO::ConstTransformRcPtr tr; + OCIO_CHECK_NO_THROW(tr = groupTransform->getTransform(6)); + + OCIO::ConstFixedFunctionTransformRcPtr fft + = OCIO::DynamicPtrCast(tr); + OCIO_REQUIRE_ASSERT(fft); + + OCIO_CHECK_EQUAL(fft->getDirection(), OCIO::TRANSFORM_DIR_INVERSE); + + // LnearCC color space conversion. + OCIO_CHECK_NO_THROW(tr = groupTransform->getTransform(7)); + + OCIO::ConstExponentTransformRcPtr exp + = OCIO::DynamicPtrCast(tr); + OCIO_REQUIRE_ASSERT(exp); + + OCIO_CHECK_EQUAL(exp->getDirection(), OCIO::TRANSFORM_DIR_INVERSE); + + double values[4] = { -1. }; + exp->getValue(values); + + OCIO_CHECK_EQUAL(values[0], 2.6); + OCIO_CHECK_EQUAL(values[1], 2.6); + OCIO_CHECK_EQUAL(values[2], 2.6); + OCIO_CHECK_EQUAL(values[3], 1.); + } + + // Channel view with alpha will cause color space conversions to be skipped if + // data bypass is enabled (looks are also bypassed). + + m[3] = 0.1; + mat->setMatrix(m); + vp.setChannelView(mat); + OCIO_CHECK_NO_THROW(proc = vp.getProcessor(cfg, cfg->getCurrentContext())); + OCIO_CHECK_ASSERT(proc); + + OCIO_CHECK_NO_THROW(groupTransform = proc->createGroupTransform()); + + OCIO_CHECK_ASSERT(groupTransform); + OCIO_CHECK_NO_THROW(groupTransform->validate()); + OCIO_REQUIRE_EQUAL(groupTransform->getNumTransforms(), 2); + + { + OCIO::ConstTransformRcPtr tr; + + // Channel view. + OCIO_CHECK_NO_THROW(tr = groupTransform->getTransform(0)); + auto mattr = OCIO::DynamicPtrCast(tr); + OCIO_REQUIRE_ASSERT(mattr); + + // LinearCC transform. + OCIO_CHECK_NO_THROW(tr = groupTransform->getTransform(1)); + auto fft = OCIO::DynamicPtrCast(tr); + OCIO_REQUIRE_ASSERT(fft); + } + + // Looks are still applied if looks override is used. + + vp.setLooksOverrideEnabled(true); + vp.setLooksOverride(cfg->getDisplayViewLooks("DISP_2", "VIEW_2")); + + OCIO_CHECK_NO_THROW(proc = vp.getProcessor(cfg, cfg->getCurrentContext())); + OCIO_CHECK_ASSERT(proc); + + OCIO_CHECK_NO_THROW(groupTransform = proc->createGroupTransform()); + + OCIO_CHECK_ASSERT(groupTransform); + OCIO_CHECK_NO_THROW(groupTransform->validate()); + OCIO_REQUIRE_EQUAL(groupTransform->getNumTransforms(), 4); + + { + OCIO::ConstTransformRcPtr tr; + + // Channel view. + OCIO_CHECK_NO_THROW(tr = groupTransform->getTransform(0)); + auto mattr = OCIO::DynamicPtrCast(tr); + OCIO_REQUIRE_ASSERT(mattr); + + // Look_4 transform. + OCIO_CHECK_NO_THROW(tr = groupTransform->getTransform(1)); + auto cdl = OCIO::DynamicPtrCast(tr); + OCIO_REQUIRE_ASSERT(cdl); + + // Look_3 transform. + OCIO_CHECK_NO_THROW(tr = groupTransform->getTransform(2)); + cdl = OCIO::DynamicPtrCast(tr); + OCIO_REQUIRE_ASSERT(cdl); + + // LinearCC transform. + OCIO_CHECK_NO_THROW(tr = groupTransform->getTransform(3)); + auto fft = OCIO::DynamicPtrCast(tr); + OCIO_REQUIRE_ASSERT(fft); + } + + dt->setDataBypass(false); + vp.setDisplayViewTransform(dt); + OCIO_CHECK_NO_THROW(proc = vp.getProcessor(cfg, cfg->getCurrentContext())); + OCIO_CHECK_ASSERT(proc); + + OCIO_CHECK_NO_THROW(groupTransform = proc->createGroupTransform()); + + OCIO_CHECK_ASSERT(groupTransform); + OCIO_CHECK_NO_THROW(groupTransform->validate()); + OCIO_REQUIRE_EQUAL(groupTransform->getNumTransforms(), 8); +} + +OCIO_ADD_TEST(ViewingPipeline, fullPipelineNoLook) +{ + // + // Validate BuildDisplayOps where the display/view is a simple color space + // (i.e., no ViewTransform). + // + + const std::string src{ "source" }; + const std::string dst{ "destination" }; + const std::string linearCS{ "linear_cs" }; + const std::string timingCS{ "color_timing_cs" }; + + OCIO::ConfigRcPtr cfg = OCIO::Config::CreateRaw()->createEditableCopy(); + auto csSource = OCIO::ColorSpace::Create(); + csSource->setName(src.c_str()); + auto mat = OCIO::MatrixTransform::Create(); + constexpr double offsetSrc[4] = { 0., 0.1, 0.2, 0. }; + mat->setOffset(offsetSrc); + csSource->setTransform(mat, OCIO::COLORSPACE_DIR_TO_REFERENCE); + cfg->addColorSpace(csSource); + + auto cs = OCIO::ColorSpace::Create(); + cs->setName(dst.c_str()); + auto ff = OCIO::FixedFunctionTransform::Create(); + ff->setStyle(OCIO::FIXED_FUNCTION_ACES_GLOW_03); + cs->setTransform(ff, OCIO::COLORSPACE_DIR_FROM_REFERENCE); + cfg->addColorSpace(cs); + + cs = OCIO::ColorSpace::Create(); + cs->setName(linearCS.c_str()); + ff = OCIO::FixedFunctionTransform::Create(); + ff->setStyle(OCIO::FIXED_FUNCTION_ACES_GLOW_10); + cs->setTransform(ff, OCIO::COLORSPACE_DIR_FROM_REFERENCE); + ff = OCIO::FixedFunctionTransform::Create(); + ff->setStyle(OCIO::FIXED_FUNCTION_ACES_RED_MOD_10); + cs->setTransform(ff, OCIO::COLORSPACE_DIR_TO_REFERENCE); + cfg->addColorSpace(cs); + cfg->setRole(OCIO::ROLE_SCENE_LINEAR, linearCS.c_str()); + + cs = OCIO::ColorSpace::Create(); + cs->setName(timingCS.c_str()); + ff = OCIO::FixedFunctionTransform::Create(); + ff->setStyle(OCIO::FIXED_FUNCTION_RGB_TO_HSV); + cs->setTransform(ff, OCIO::COLORSPACE_DIR_FROM_REFERENCE); + ff = OCIO::FixedFunctionTransform::Create(); + ff->setStyle(OCIO::FIXED_FUNCTION_ACES_DARK_TO_DIM_10); + cs->setTransform(ff, OCIO::COLORSPACE_DIR_TO_REFERENCE); + cfg->addColorSpace(cs); + cfg->setRole(OCIO::ROLE_COLOR_TIMING, timingCS.c_str()); + + const std::string display{ "display" }; + const std::string view{ "view" }; + OCIO_CHECK_NO_THROW(cfg->addDisplayView(display.c_str(), view.c_str(), dst.c_str(), "")); + + OCIO_CHECK_NO_THROW(cfg->sanityCheck()); + + auto dt = OCIO::DisplayViewTransform::Create(); + dt->setSrc(src.c_str()); + + dt->setDisplay(display.c_str()); + dt->setView(view.c_str()); + + OCIO::ViewingPipeline vp; + vp.setDisplayViewTransform(dt); + + auto linearCC = OCIO::MatrixTransform::Create(); + constexpr double offsetLinearCC[4] = { 0.2, 0.3, 0.4, 0. }; + linearCC->setOffset(offsetLinearCC); + vp.setLinearCC(linearCC); + auto timimgCC = OCIO::ExponentTransform::Create(); + constexpr double valueTimingCC[4] = { 2.2, 2.3, 2.4, 1. }; + timimgCC->setValue(valueTimingCC); + vp.setColorTimingCC(timimgCC); + constexpr double offsetCV[4] = { 0.2, 0.1, 0.1, 0. }; + auto cvTrans = OCIO::MatrixTransform::Create(); + cvTrans->setOffset(offsetCV); + vp.setChannelView(cvTrans); + auto displayCC = OCIO::ExposureContrastTransform::Create(); + vp.setDisplayCC(displayCC); + + { + OCIO::ConstProcessorRcPtr proc; + OCIO_CHECK_NO_THROW(proc = vp.getProcessor(cfg, cfg->getCurrentContext())); + OCIO_REQUIRE_ASSERT(proc); + + OCIO::GroupTransformRcPtr groupTransform; + OCIO_CHECK_NO_THROW(groupTransform = proc->createGroupTransform()); + + OCIO_REQUIRE_ASSERT(groupTransform); + OCIO_CHECK_NO_THROW(groupTransform->validate()); + OCIO_REQUIRE_EQUAL(groupTransform->getNumTransforms(), 10); + + // 0-1. InputCS -> scene linear role: + // 0. Input to reference. + // 1. Scene linear role from reference. + // 2. LinearCC. + // 3-4. Scene linear -> color timing role: + // 4. Scene linear role to reference. + // 5. ColorTiming from reference. + // 5. ColorTimingCC. + // * No look. + // 6. ChannelView. + // 7-8. Color timing role -> display/view color space: + // 7. ColorTiming to reference. + // 8. DisplayCS from reference. + // 9. DisplayCC. + + // 0. Input to reference. + OCIO::ConstTransformRcPtr tr; + OCIO_CHECK_NO_THROW(tr = groupTransform->getTransform(0)); + auto mat = OCIO::DynamicPtrCast(tr); + OCIO_REQUIRE_ASSERT(mat); + OCIO_CHECK_EQUAL(mat->getDirection(), OCIO::TRANSFORM_DIR_FORWARD); + double offset[4]{ 0. }; + mat->getOffset(offset); + OCIO_CHECK_EQUAL(offset[0], offsetSrc[0]); + OCIO_CHECK_EQUAL(offset[1], offsetSrc[1]); + OCIO_CHECK_EQUAL(offset[2], offsetSrc[2]); + OCIO_CHECK_EQUAL(offset[3], offsetSrc[3]); + + // 1. Scene linear role from reference. + OCIO_CHECK_NO_THROW(tr = groupTransform->getTransform(1)); + auto ff = OCIO::DynamicPtrCast(tr); + OCIO_REQUIRE_ASSERT(ff); + OCIO_CHECK_EQUAL(ff->getDirection(), OCIO::TRANSFORM_DIR_FORWARD); + OCIO_CHECK_EQUAL(ff->getStyle(), OCIO::FIXED_FUNCTION_ACES_GLOW_10); + + // 2. LinearCC. + OCIO_CHECK_NO_THROW(tr = groupTransform->getTransform(2)); + mat = OCIO::DynamicPtrCast(tr); + OCIO_REQUIRE_ASSERT(mat); + OCIO_CHECK_EQUAL(mat->getDirection(), OCIO::TRANSFORM_DIR_FORWARD); + mat->getOffset(offset); + OCIO_CHECK_EQUAL(offset[0], offsetLinearCC[0]); + OCIO_CHECK_EQUAL(offset[1], offsetLinearCC[1]); + OCIO_CHECK_EQUAL(offset[2], offsetLinearCC[2]); + OCIO_CHECK_EQUAL(offset[3], offsetLinearCC[3]); + + // 3. Scene linear role to reference. + OCIO_CHECK_NO_THROW(tr = groupTransform->getTransform(3)); + ff = OCIO::DynamicPtrCast(tr); + OCIO_REQUIRE_ASSERT(ff); + OCIO_CHECK_EQUAL(ff->getDirection(), OCIO::TRANSFORM_DIR_FORWARD); + OCIO_CHECK_EQUAL(ff->getStyle(), OCIO::FIXED_FUNCTION_ACES_RED_MOD_10); + + // 4. ColorTiming from reference. + OCIO_CHECK_NO_THROW(tr = groupTransform->getTransform(4)); + ff = OCIO::DynamicPtrCast(tr); + OCIO_REQUIRE_ASSERT(ff); + OCIO_CHECK_EQUAL(ff->getDirection(), OCIO::TRANSFORM_DIR_FORWARD); + OCIO_CHECK_EQUAL(ff->getStyle(), OCIO::FIXED_FUNCTION_RGB_TO_HSV); + + // 5. ColorTimingCC. + OCIO_CHECK_NO_THROW(tr = groupTransform->getTransform(5)); + auto exp = OCIO::DynamicPtrCast(tr); + OCIO_REQUIRE_ASSERT(exp); + OCIO_CHECK_EQUAL(exp->getDirection(), OCIO::TRANSFORM_DIR_FORWARD); + + double expVals[4]{ 0. }; + exp->getValue(expVals); + OCIO_CHECK_EQUAL(expVals[0], valueTimingCC[0]); + OCIO_CHECK_EQUAL(expVals[1], valueTimingCC[1]); + OCIO_CHECK_EQUAL(expVals[2], valueTimingCC[2]); + OCIO_CHECK_EQUAL(expVals[3], valueTimingCC[3]); + + // 6. ChannelView. + OCIO_CHECK_NO_THROW(tr = groupTransform->getTransform(6)); + mat = OCIO::DynamicPtrCast(tr); + OCIO_REQUIRE_ASSERT(mat); + OCIO_CHECK_EQUAL(mat->getDirection(), OCIO::TRANSFORM_DIR_FORWARD); + mat->getOffset(offset); + OCIO_CHECK_EQUAL(offset[0], offsetCV[0]); + OCIO_CHECK_EQUAL(offset[1], offsetCV[1]); + OCIO_CHECK_EQUAL(offset[2], offsetCV[2]); + OCIO_CHECK_EQUAL(offset[3], offsetCV[3]); + + // 7. ColorTiming to reference. + OCIO_CHECK_NO_THROW(tr = groupTransform->getTransform(7)); + ff = OCIO::DynamicPtrCast(tr); + OCIO_REQUIRE_ASSERT(ff); + OCIO_CHECK_EQUAL(ff->getDirection(), OCIO::TRANSFORM_DIR_FORWARD); + OCIO_CHECK_EQUAL(ff->getStyle(), OCIO::FIXED_FUNCTION_ACES_DARK_TO_DIM_10); + + // 8. DisplayCS from reference. + OCIO_CHECK_NO_THROW(tr = groupTransform->getTransform(8)); + ff = OCIO::DynamicPtrCast(tr); + OCIO_REQUIRE_ASSERT(ff); + OCIO_CHECK_EQUAL(ff->getDirection(), OCIO::TRANSFORM_DIR_FORWARD); + OCIO_CHECK_EQUAL(ff->getStyle(), OCIO::FIXED_FUNCTION_ACES_GLOW_03); + + // 9. DisplayCC. + OCIO_CHECK_NO_THROW(tr = groupTransform->getTransform(9)); + auto ec = OCIO::DynamicPtrCast(tr); + OCIO_REQUIRE_ASSERT(ec); + } + + // + // Using a scene-referred ViewTransform. + // + + const std::string dsp{ "display" }; + cs = OCIO::ColorSpace::Create(OCIO::REFERENCE_SPACE_DISPLAY); + cs->setName(dsp.c_str()); + auto ec = OCIO::ExposureContrastTransform::Create(); + cs->setTransform(ec, OCIO::COLORSPACE_DIR_FROM_REFERENCE); + cfg->addColorSpace(cs); + + const std::string scenevt{ "scene_vt" }; + auto vt = OCIO::ViewTransform::Create(OCIO::REFERENCE_SPACE_SCENE); + vt->setName(scenevt.c_str()); + auto log = OCIO::LogTransform::Create(); + log->setBase(4.2); + vt->setTransform(log, OCIO::VIEWTRANSFORM_DIR_FROM_REFERENCE); + cfg->addViewTransform(vt); + + const std::string viewt{ "viewt" }; + OCIO_CHECK_NO_THROW(cfg->addDisplayView(display.c_str(), viewt.c_str(), scenevt.c_str(), + dsp.c_str(), "", "", "")); + OCIO_CHECK_NO_THROW(cfg->sanityCheck()); + + dt->setView(viewt.c_str()); + vp.setDisplayViewTransform(dt); + + { + OCIO::ConstProcessorRcPtr proc; + OCIO_CHECK_NO_THROW(proc = vp.getProcessor(cfg, cfg->getCurrentContext())); + OCIO_REQUIRE_ASSERT(proc); + + OCIO::GroupTransformRcPtr groupTransform; + OCIO_CHECK_NO_THROW(groupTransform = proc->createGroupTransform()); + + OCIO_REQUIRE_ASSERT(groupTransform); + OCIO_CHECK_NO_THROW(groupTransform->validate()); + // Getting an additional op for the reference space change. + OCIO_REQUIRE_EQUAL(groupTransform->getNumTransforms(), 11); + + // Same as previous up to colorTiming to reference. + // 0. Input to reference. + // 1. Scene linear role from reference. + // 2. LinearCC. + // 3. Scene linear role to reference. + // 4. ColorTiming from reference. + // 5. ColorTimingCC. + // 6. ChannelView. + // 7. ColorTiming to reference. + + // 8. Changing from scene-referred space to display-referred space done + // with the specified view transform. + OCIO::ConstTransformRcPtr tr; + OCIO_CHECK_NO_THROW(tr = groupTransform->getTransform(8)); + auto log = OCIO::DynamicPtrCast(tr); + OCIO_REQUIRE_ASSERT(log); + OCIO_CHECK_EQUAL(log->getDirection(), OCIO::TRANSFORM_DIR_FORWARD); + OCIO_CHECK_EQUAL(log->getBase(), 4.2); + + // 9. DisplayCS from reference. + OCIO_CHECK_NO_THROW(tr = groupTransform->getTransform(9)); + auto ec = OCIO::DynamicPtrCast(tr); + OCIO_REQUIRE_ASSERT(ec); + + // 10. DisplayCC. + OCIO_CHECK_NO_THROW(tr = groupTransform->getTransform(10)); + ec = OCIO::DynamicPtrCast(tr); + OCIO_REQUIRE_ASSERT(ec); + } + + // + // Adding a display-referred ViewTransform. + // + + const std::string displayvt{ "display_vt" }; + vt = OCIO::ViewTransform::Create(OCIO::REFERENCE_SPACE_DISPLAY); + vt->setName(displayvt.c_str()); + log = OCIO::LogTransform::Create(); + log->setBase(2.1); + vt->setTransform(log, OCIO::VIEWTRANSFORM_DIR_FROM_REFERENCE); + cfg->addViewTransform(vt); + + // Replace view display. + OCIO_CHECK_NO_THROW(cfg->addDisplayView(display.c_str(), viewt.c_str(), displayvt.c_str(), + dsp.c_str(), "", "", "")); + OCIO_CHECK_NO_THROW(cfg->sanityCheck()); + + { + OCIO::ConstProcessorRcPtr proc; + OCIO_CHECK_NO_THROW(proc = vp.getProcessor(cfg, cfg->getCurrentContext())); + OCIO_REQUIRE_ASSERT(proc); + + OCIO::GroupTransformRcPtr groupTransform; + OCIO_CHECK_NO_THROW(groupTransform = proc->createGroupTransform()); + + OCIO_REQUIRE_ASSERT(groupTransform); + OCIO_CHECK_NO_THROW(groupTransform->validate()); + // Getting an additional op for the display to display view transform. + OCIO_REQUIRE_EQUAL(groupTransform->getNumTransforms(), 12); + + // Same as previous up to scene-referred to display referred. + // 0. Input to reference. + // 1. Scene linear role from reference. + // 2. LinearCC. + // 3. Scene linear role to reference. + // 4. ColorTiming from reference. + // 5. ColorTimingCC. + // 6. ChannelView. + // 7. ColorTiming to reference. + // 8. Changing from scene-referred space to display-referred space using the + // default view transform. + + // 9. Display-referred reference to display-referred reference using the specified view transform. + OCIO::ConstTransformRcPtr tr; + OCIO_CHECK_NO_THROW(tr = groupTransform->getTransform(9)); + auto log = OCIO::DynamicPtrCast(tr); + OCIO_REQUIRE_ASSERT(log); + OCIO_CHECK_EQUAL(log->getDirection(), OCIO::TRANSFORM_DIR_FORWARD); + OCIO_CHECK_EQUAL(log->getBase(), 2.1); + + // 10. DisplayCS from reference. + OCIO_CHECK_NO_THROW(tr = groupTransform->getTransform(10)); + auto ec = OCIO::DynamicPtrCast(tr); + OCIO_REQUIRE_ASSERT(ec); + + // 11. DisplayCC. + OCIO_CHECK_NO_THROW(tr = groupTransform->getTransform(11)); + ec = OCIO::DynamicPtrCast(tr); + OCIO_REQUIRE_ASSERT(ec); + } + + csSource->setIsData(true); + cfg->addColorSpace(csSource); + OCIO_CHECK_NO_THROW(cfg->sanityCheck()); + + { + OCIO::ConstProcessorRcPtr proc; + OCIO_CHECK_NO_THROW(proc = vp.getProcessor(cfg, cfg->getCurrentContext())); + OCIO_REQUIRE_ASSERT(proc); + + OCIO::GroupTransformRcPtr groupTransform; + OCIO_CHECK_NO_THROW(groupTransform = proc->createGroupTransform()); + + OCIO_REQUIRE_ASSERT(groupTransform); + OCIO_CHECK_NO_THROW(groupTransform->validate()); + // Color space conversion is skipped. + OCIO_REQUIRE_EQUAL(groupTransform->getNumTransforms(), 4); + + // With isData true, the view/display transform is not applied. The CC and channelView + // are applied, but without converting to their usual process spaces. + // 0. LinearCC. + // 1. ColorTimingCC. + // 2. ChannelView. + // 3. DisplayCC. + + OCIO::ConstTransformRcPtr tr; + OCIO_CHECK_NO_THROW(tr = groupTransform->getTransform(0)); + auto mat = OCIO::DynamicPtrCast(tr); + OCIO_REQUIRE_ASSERT(mat); + + OCIO_CHECK_NO_THROW(tr = groupTransform->getTransform(1)); + auto exp = OCIO::DynamicPtrCast(tr); + OCIO_REQUIRE_ASSERT(exp); + + OCIO_CHECK_NO_THROW(tr = groupTransform->getTransform(2)); + mat = OCIO::DynamicPtrCast(tr); + OCIO_REQUIRE_ASSERT(mat); + + OCIO_CHECK_NO_THROW(tr = groupTransform->getTransform(3)); + auto ec = OCIO::DynamicPtrCast(tr); + OCIO_REQUIRE_ASSERT(ec); + } +} + diff --git a/tests/cpu/CMakeLists.txt b/tests/cpu/CMakeLists.txt index bb2c535b17..4736879ef2 100755 --- a/tests/cpu/CMakeLists.txt +++ b/tests/cpu/CMakeLists.txt @@ -64,7 +64,6 @@ endfunction(add_ocio_test) # OpenColorIO target set(SOURCES Caching.cpp - Display.cpp fileformats/cdl/CDLParser.cpp fileformats/cdl/CDLReaderHelper.cpp fileformats/ctf/CTFReaderHelper.cpp @@ -94,7 +93,6 @@ set(SOURCES transforms/builtins/ACES.cpp transforms/builtins/ColorMatrixHelpers.cpp transforms/builtins/OpHelpers.cpp - transforms/LookTransform.cpp ) if(OCIO_ADD_EXTRA_BUILTINS) @@ -117,6 +115,7 @@ set(TESTS Config_tests.cpp Context_tests.cpp CPUProcessor_tests.cpp + Display_tests.cpp DynamicProperty_tests.cpp Exception_tests.cpp fileformats/ctf/CTFTransform_tests.cpp @@ -196,7 +195,7 @@ set(TESTS transforms/AllocationTransform_tests.cpp transforms/CDLTransform_tests.cpp transforms/ColorSpaceTransform_tests.cpp - transforms/DisplayTransform_tests.cpp + transforms/DisplayViewTransform_tests.cpp transforms/ExponentTransform_tests.cpp transforms/ExponentWithLinearTransform_tests.cpp transforms/ExposureContrastTransform_tests.cpp @@ -205,6 +204,7 @@ set(TESTS transforms/LogAffineTransform_tests.cpp transforms/LogCameraTransform_tests.cpp transforms/LogTransform_tests.cpp + transforms/LookTransform_tests.cpp transforms/Lut1DTransform_tests.cpp transforms/Lut3DTransform_tests.cpp transforms/MatrixTransform_tests.cpp @@ -212,6 +212,7 @@ set(TESTS UnitTestMain.cpp UnitTestOptimFlags.cpp UnitTestUtils.cpp + ViewingRules_tests.cpp ViewTransform_tests.cpp ) diff --git a/tests/cpu/ColorSpace_tests.cpp b/tests/cpu/ColorSpace_tests.cpp index 2bb5ed71eb..7340e54c85 100644 --- a/tests/cpu/ColorSpace_tests.cpp +++ b/tests/cpu/ColorSpace_tests.cpp @@ -29,6 +29,7 @@ OCIO_ADD_TEST(ColorSpace, basic) OCIO_CHECK_EQUAL(std::string(""), cs->getFamily()); OCIO_CHECK_EQUAL(std::string(""), cs->getDescription()); OCIO_CHECK_EQUAL(std::string(""), cs->getEqualityGroup()); + OCIO_CHECK_EQUAL(std::string(""), cs->getEncoding()); OCIO_CHECK_EQUAL(OCIO::BIT_DEPTH_UNKNOWN, cs->getBitDepth()); OCIO_CHECK_ASSERT(!cs->isData()); OCIO_CHECK_EQUAL(OCIO::ALLOCATION_UNIFORM, cs->getAllocation()); @@ -42,6 +43,8 @@ OCIO_ADD_TEST(ColorSpace, basic) OCIO_CHECK_EQUAL(std::string("description"), cs->getDescription()); cs->setEqualityGroup("equalitygroup"); OCIO_CHECK_EQUAL(std::string("equalitygroup"), cs->getEqualityGroup()); + cs->setEncoding("encoding"); + OCIO_CHECK_EQUAL(std::string("encoding"), cs->getEncoding()); cs->setBitDepth(OCIO::BIT_DEPTH_F16); OCIO_CHECK_EQUAL(OCIO::BIT_DEPTH_F16, cs->getBitDepth()); cs->setIsData(true); @@ -58,7 +61,7 @@ OCIO_ADD_TEST(ColorSpace, basic) std::ostringstream oss; oss << *cs; - OCIO_CHECK_EQUAL(oss.str().size(), 149); + OCIO_CHECK_EQUAL(oss.str().size(), 168); } OCIO_ADD_TEST(ColorSpace, category) @@ -98,4 +101,3 @@ OCIO_ADD_TEST(ColorSpace, category) OCIO_CHECK_NO_THROW(cs->clearCategories()); OCIO_CHECK_EQUAL(cs->getNumCategories(), 0); } - diff --git a/tests/cpu/Config_tests.cpp b/tests/cpu/Config_tests.cpp index 41f428d98a..248ff05f30 100644 --- a/tests/cpu/Config_tests.cpp +++ b/tests/cpu/Config_tests.cpp @@ -1649,6 +1649,7 @@ OCIO_ADD_TEST(Config, categories) " bitdepth: unknown\n" " isdata: false\n" " categories: [rendering, linear]\n" + " encoding: scene-linear\n" " allocation: uniform\n" " allocationvars: [-0.125, 1.125]\n" "\n" @@ -1659,6 +1660,7 @@ OCIO_ADD_TEST(Config, categories) " bitdepth: unknown\n" " isdata: false\n" " categories: [rendering]\n" + " encoding: data\n" " allocation: uniform\n" " allocationvars: [-0.125, 1.125]\n"; @@ -1701,8 +1703,10 @@ OCIO_ADD_TEST(Config, categories) OCIO_CHECK_EQUAL(config->getIndexForColorSpace("raw2"), 1); cs = config->getColorSpace("raw1"); OCIO_CHECK_EQUAL(std::string(cs->getName()), std::string("raw1")); + OCIO_CHECK_EQUAL(std::string(cs->getEncoding()), std::string("scene-linear")); cs = config->getColorSpace("raw2"); OCIO_CHECK_EQUAL(std::string(cs->getName()), std::string("raw2")); + OCIO_CHECK_EQUAL(std::string(cs->getEncoding()), std::string("data")); } OCIO_ADD_TEST(Config, display) @@ -1811,6 +1815,13 @@ OCIO_ADD_TEST(Config, display) OCIO_REQUIRE_EQUAL(config->getNumDisplays(), 1); OCIO_CHECK_EQUAL(std::string(config->getDisplay(0)), std::string("sRGB_1")); OCIO_CHECK_EQUAL(std::string(config->getDefaultDisplay()), "sRGB_1"); + + OCIO_REQUIRE_EQUAL(config->getNumDisplaysAll(), 6); + + // Test that all displays are saved. + std::stringstream ss; + ss << *config.get(); + OCIO_CHECK_EQUAL(ss.str(), myProfile); } { @@ -2071,6 +2082,9 @@ OCIO_ADD_TEST(Config, view) OCIO_REQUIRE_EQUAL(config->getNumViews("sRGB_1"), 2); OCIO_CHECK_EQUAL(std::string(config->getView("sRGB_1", 0)), "View_1"); OCIO_CHECK_EQUAL(std::string(config->getView("sRGB_1", 1)), "View_2"); + // Invalid index. + OCIO_CHECK_EQUAL(std::string(config->getView("sRGB_1", 42)), ""); + OCIO_CHECK_EQUAL(std::string(config->getDefaultView("sRGB_2")), "View_2"); OCIO_REQUIRE_EQUAL(config->getNumViews("sRGB_2"), 2); OCIO_CHECK_EQUAL(std::string(config->getView("sRGB_2", 0)), "View_2"); @@ -2079,6 +2093,10 @@ OCIO_ADD_TEST(Config, view) OCIO_REQUIRE_EQUAL(config->getNumViews("sRGB_3"), 2); OCIO_CHECK_EQUAL(std::string(config->getView("sRGB_3", 0)), "View_3"); OCIO_CHECK_EQUAL(std::string(config->getView("sRGB_3", 1)), "View_1"); + + std::stringstream ss; + ss << *config.get(); + OCIO_CHECK_EQUAL(ss.str(), myProfile); } { @@ -2102,6 +2120,15 @@ OCIO_ADD_TEST(Config, view) OCIO_CHECK_EQUAL(std::string(config->getDefaultView("sRGB_3")), "View_3"); OCIO_REQUIRE_EQUAL(config->getNumViews("sRGB_3"), 1); OCIO_CHECK_EQUAL(std::string(config->getView("sRGB_3", 0)), "View_3"); + + OCIO_REQUIRE_EQUAL(config->getNumViews(OCIO::VIEW_DISPLAY_DEFINED, "sRGB_1"), 2); + OCIO_REQUIRE_EQUAL(config->getNumViews(OCIO::VIEW_DISPLAY_DEFINED, "sRGB_2"), 2); + OCIO_REQUIRE_EQUAL(config->getNumViews(OCIO::VIEW_DISPLAY_DEFINED, "sRGB_3"), 2); + + // Test that all views are saved. + std::stringstream ss; + ss << *config.get(); + OCIO_CHECK_EQUAL(ss.str(), myProfile); } { @@ -3327,7 +3354,7 @@ OCIO_ADD_TEST(Config, inactive_color_space) lookTransform->setLooks("beauty"); // Process space (i.e. lnh) inactive. lookTransform->setSrc("raw"); - const char * csName = config->getDisplayColorSpaceName("sRGB", "Lnh"); + const char * csName = config->getDisplayViewColorSpaceName("sRGB", "Lnh"); lookTransform->setDst(csName); // Color space inactive (i.e. lnh). OCIO_CHECK_NO_THROW(config->getProcessor(lookTransform, OCIO::TRANSFORM_DIR_FORWARD)); @@ -3981,7 +4008,7 @@ OCIO_ADD_TEST(Config, view_transforms) const std::string vtDisplay{ "display" }; vt->setName(vtDisplay.c_str()); OCIO_CHECK_THROW_WHAT(configEdit->addViewTransform(vt), OCIO::Exception, - "Cannot add view transform with no transform"); + "Cannot add view transform 'display' with no transform"); OCIO_CHECK_NO_THROW(vt->setTransform(OCIO::MatrixTransform::Create(), OCIO::VIEWTRANSFORM_DIR_FROM_REFERENCE)); OCIO_CHECK_NO_THROW(configEdit->addViewTransform(vt)); @@ -4039,7 +4066,11 @@ OCIO_ADD_TEST(Config, view_transforms) OCIO_ADD_TEST(Config, display_view) { + // Create a config with a display that has 2 kinds of views. + OCIO::ConfigRcPtr config = OCIO::Config::Create(); + config->upgradeToLatestVersion(); + auto cs = OCIO::ColorSpace::Create(OCIO::REFERENCE_SPACE_SCENE); cs->setName("scs"); config->addColorSpace(cs); @@ -4060,17 +4091,82 @@ OCIO_ADD_TEST(Config, display_view) OCIO_CHECK_NO_THROW(config->addViewTransform(vt)); const std::string display{ "display" }; - OCIO_CHECK_NO_THROW(config->addDisplay(display.c_str(), "view1", "scs", "")); + OCIO_CHECK_NO_THROW(config->addDisplayView(display.c_str(), "view1", "scs", "")); OCIO_CHECK_NO_THROW(config->sanityCheck()); - OCIO_CHECK_NO_THROW(config->addDisplay(display.c_str(), "view2", "view_transform", "scs", "")); + OCIO_CHECK_NO_THROW(config->addDisplayView(display.c_str(), "view2", "view_transform", "scs", + "", "", "")); OCIO_CHECK_THROW_WHAT(config->sanityCheck(), OCIO::Exception, "color space, 'scs', that is not a display-referred"); - OCIO_CHECK_NO_THROW(config->addDisplay(display.c_str(), "view2", "view_transform", "dcs", "")); + OCIO_CHECK_NO_THROW(config->addDisplayView(display.c_str(), "view2", "view_transform", "dcs", + "", "", "")); OCIO_CHECK_NO_THROW(config->sanityCheck()); + // Validate how the config is serialized. + + std::stringstream os; + os << *config.get(); + constexpr char expected[]{ R"(ocio_profile_version: 2 + +search_path: "" +strictparsing: true +luma: [0.2126, 0.7152, 0.0722] + +roles: + {} + +file_rules: + - ! {name: Default, colorspace: added_default_rule_colorspace} + +displays: + display: + - ! {name: view1, colorspace: scs} + - ! {name: view2, view_transform: view_transform, display_colorspace: dcs} + +active_displays: [] +active_views: [] +inactive_colorspaces: [added_default_rule_colorspace] + +view_transforms: + - ! + name: display + from_display_reference: ! {} + + - ! + name: view_transform + from_reference: ! {} + +display_colorspaces: + - ! + name: dcs + family: "" + equalitygroup: "" + bitdepth: unknown + isdata: false + allocation: uniform + +colorspaces: + - ! + name: added_default_rule_colorspace + family: "" + equalitygroup: "" + bitdepth: unknown + isdata: true + allocation: uniform + + - ! + name: scs + family: "" + equalitygroup: "" + bitdepth: unknown + isdata: false + allocation: uniform +)" }; + + OCIO_CHECK_EQUAL(os.str(), expected); + OCIO_CHECK_EQUAL(config->getNumDisplays(), 1); OCIO_CHECK_EQUAL(config->getNumViews(display.c_str()), 2); @@ -4087,30 +4183,37 @@ OCIO_ADD_TEST(Config, display_view) const std::string v1{ configRead->getView("display", 0) }; OCIO_CHECK_EQUAL(v1, "view1"); OCIO_CHECK_EQUAL(std::string("scs"), - configRead->getDisplayColorSpaceName("display", v1.c_str())); + configRead->getDisplayViewColorSpaceName("display", v1.c_str())); OCIO_CHECK_EQUAL(std::string(""), configRead->getDisplayViewTransformName("display", v1.c_str())); const std::string v2{ configRead->getView("display", 1) }; OCIO_CHECK_EQUAL(v2, "view2"); OCIO_CHECK_EQUAL(std::string("dcs"), - configRead->getDisplayColorSpaceName("display", v2.c_str())); + configRead->getDisplayViewColorSpaceName("display", v2.c_str())); OCIO_CHECK_EQUAL(std::string("view_transform"), configRead->getDisplayViewTransformName("display", v2.c_str())); - // Using nullptr for any parameter does nothing. - OCIO_CHECK_NO_THROW(config->addDisplay(nullptr, "view1", "scs", "")); - OCIO_CHECK_NO_THROW(config->addDisplay(display.c_str(), nullptr, "scs", "")); - OCIO_CHECK_NO_THROW(config->addDisplay(display.c_str(), "view3", nullptr, "")); - OCIO_CHECK_NO_THROW(config->addDisplay(display.c_str(), "view4", "view_transform", nullptr, "")); - OCIO_CHECK_EQUAL(config->getNumDisplays(), 1); - OCIO_CHECK_EQUAL(config->getNumViews(display.c_str()), 2); - - OCIO_CHECK_THROW_WHAT(config->addDisplay("", "view1", "scs", ""), OCIO::Exception, - "Can't add a (display, view) pair with empty display name"); - OCIO_CHECK_THROW_WHAT(config->addDisplay(display.c_str(), "", "scs", ""), OCIO::Exception, - "Can't add a (display, view) pair with empty view name"); - OCIO_CHECK_THROW_WHAT(config->addDisplay(display.c_str(), "view1", "", ""), OCIO::Exception, - "Can't add a (display, view) pair with empty color space name"); + // Check some faulty calls related to displays & views. + + // Using nullptr or empty string for required parameters with throw. + OCIO_CHECK_THROW_WHAT(config->addDisplayView(nullptr, "view1", "scs", ""), + OCIO::Exception, "a non-empty display name is needed"); + OCIO_CHECK_THROW_WHAT(config->addDisplayView(display.c_str(), nullptr, "scs", ""), + OCIO::Exception, "a non-empty view name is needed"); + OCIO_CHECK_THROW_WHAT(config->addDisplayView(display.c_str(), "view3", nullptr, ""), + OCIO::Exception, "a non-empty color space name is needed"); + OCIO_CHECK_THROW_WHAT(config->addDisplayView(display.c_str(), "view4", "view_transform", nullptr, + "", "", ""), + OCIO::Exception, "a non-empty color space name is needed"); + OCIO_CHECK_THROW_WHAT(config->addDisplayView("", "view1", "scs", ""), + OCIO::Exception, "a non-empty display name is needed"); + OCIO_CHECK_THROW_WHAT(config->addDisplayView(display.c_str(), "", "scs", ""), + OCIO::Exception, "a non-empty view name is needed"); + OCIO_CHECK_THROW_WHAT(config->addDisplayView(display.c_str(), "view3", "", ""), + OCIO::Exception, "a non-empty color space name is needed"); + OCIO_CHECK_THROW_WHAT(config->addDisplayView(display.c_str(), "view4", "view_transform", "", + "", "", ""), + OCIO::Exception, "a non-empty color space name is needed"); } OCIO_ADD_TEST(Config, not_case_sensitive) @@ -4182,6 +4285,11 @@ ocio_profile_version: 1 name: cs2 allocation: uniform to_reference: ! {src: SCENE_LINEAR, dst: raw} + + - ! + name: cs3 + allocation: uniform + to_reference: ! {src: SCENE_LINEAR, dst: raw, data_bypass: false} )" }; std::istringstream is; @@ -4203,22 +4311,38 @@ ocio_profile_version: 1 OCIO_CHECK_NO_THROW(processor = config->getProcessor("cs1", "cs2")); OCIO_CHECK_ASSERT(processor); + OCIO::ConstColorSpaceRcPtr cs2 = config->getColorSpace("cs2"); + OCIO_REQUIRE_ASSERT(cs2); + auto tr2 = cs2->getTransform(OCIO::COLORSPACE_DIR_TO_REFERENCE); + OCIO_REQUIRE_ASSERT(tr2); + auto cs2Tr = OCIO::DynamicPtrCast(tr2); + OCIO_REQUIRE_ASSERT(cs2Tr); + OCIO_CHECK_ASSERT(cs2Tr->getDataBypass()); + + OCIO::ConstColorSpaceRcPtr cs3 = config->getColorSpace("cs3"); + OCIO_REQUIRE_ASSERT(cs3); + auto tr3 = cs3->getTransform(OCIO::COLORSPACE_DIR_TO_REFERENCE); + OCIO_REQUIRE_ASSERT(tr3); + auto cs3Tr = OCIO::DynamicPtrCast(tr3); + OCIO_REQUIRE_ASSERT(cs3Tr); + OCIO_CHECK_ASSERT(!cs3Tr->getDataBypass()); + // Validate the (display, view) pair with looks. - OCIO::DisplayTransformRcPtr display = OCIO::DisplayTransform::Create(); - display->setInputColorSpaceName("raw"); + OCIO::DisplayViewTransformRcPtr display = OCIO::DisplayViewTransform::Create(); + display->setSrc("raw"); display->setDisplay("Disp1"); display->setView("View1"); OCIO_CHECK_NO_THROW(processor = config->getProcessor(display)); OCIO_CHECK_ASSERT(processor); - display->setInputColorSpaceName("cs1"); + display->setSrc("cs1"); OCIO_CHECK_NO_THROW(processor = config->getProcessor(display)); OCIO_CHECK_ASSERT(processor); - display->setInputColorSpaceName("cs2"); + display->setSrc("cs2"); OCIO_CHECK_NO_THROW(processor = config->getProcessor(display)); OCIO_CHECK_ASSERT(processor); @@ -4293,7 +4417,7 @@ OCIO_ADD_TEST(Config, add_remove_display) // Add a (display, view) pair. - OCIO_CHECK_NO_THROW(config->addDisplay("disp1", "view1", "raw", nullptr)); + OCIO_CHECK_NO_THROW(config->addDisplayView("disp1", "view1", "raw", nullptr)); OCIO_REQUIRE_EQUAL(config->getNumDisplays(), 2); OCIO_CHECK_EQUAL(std::string(config->getDisplay(0)), std::string("sRGB")); OCIO_CHECK_EQUAL(std::string(config->getDisplay(1)), std::string("disp1")); @@ -4301,7 +4425,7 @@ OCIO_ADD_TEST(Config, add_remove_display) // Remove a (display, view) pair. - OCIO_CHECK_NO_THROW(config->removeDisplay("disp1", "view1")); + OCIO_CHECK_NO_THROW(config->removeDisplayView("disp1", "view1")); OCIO_REQUIRE_EQUAL(config->getNumDisplays(), 1); OCIO_CHECK_EQUAL(std::string(config->getDisplay(0)), std::string("sRGB")); } diff --git a/tests/cpu/Display_tests.cpp b/tests/cpu/Display_tests.cpp new file mode 100644 index 0000000000..afec8fc260 --- /dev/null +++ b/tests/cpu/Display_tests.cpp @@ -0,0 +1,233 @@ +// SPDX-License-Identifier: BSD-3-Clause +// Copyright Contributors to the OpenColorIO Project. + + +#include "Display.cpp" + +#include "testutils/UnitTest.h" +#include "UnitTestUtils.h" + +namespace OCIO = OCIO_NAMESPACE; + + +OCIO_ADD_TEST(SharedViews, basic) +{ + // Shared views can not be used with v1 config. + OCIO::ConfigRcPtr config = OCIO::Config::Create(); + OCIO_CHECK_NO_THROW(config->addSharedView("shared1", "", "colorspace", "", "", "")); + std::ostringstream oss; + OCIO_CHECK_THROW_WHAT(config->serialize(oss), OCIO::Exception, + "Only version 2 (or higher) can have shared views"); + + // Using a v2 config. + config = OCIO::Config::CreateRaw()->createEditableCopy(); + OCIO_CHECK_NO_THROW(config->sanityCheck()); + + // Shared views need to refer to existing colorspaces. + OCIO_CHECK_NO_THROW(config->addSharedView("shared1", "", "colorspace1", "", "", "")); + OCIO_CHECK_THROW_WHAT(config->sanityCheck(), OCIO::Exception, + "color space, 'colorspace1', which is not defined"); + + OCIO::ColorSpaceRcPtr cs = OCIO::ColorSpace::Create(); + cs->setName("colorspace1"); + config->addColorSpace(cs); + OCIO_CHECK_NO_THROW(config->sanityCheck()); + + // Shared views need to refer to existing looks. + cs->setName("colorspace2"); + config->addColorSpace(cs); + OCIO_CHECK_NO_THROW(config->addSharedView("shared2", "", "colorspace2", "look1", "", "")); + OCIO_CHECK_THROW_WHAT(config->sanityCheck(), OCIO::Exception, + "refers to a look, 'look1', which is not defined."); + + OCIO::LookRcPtr lk = OCIO::Look::Create(); + lk->setName("look1"); + lk->setProcessSpace("look1_process"); + cs->setName("look1_process"); + config->addColorSpace(cs); + config->addLook(lk); + OCIO_CHECK_NO_THROW(config->sanityCheck()); + + // Shared views need to refer to existing view transforms. + cs = OCIO::ColorSpace::Create(OCIO::REFERENCE_SPACE_DISPLAY); + cs->setName("colorspace3"); + config->addColorSpace(cs); + OCIO_CHECK_NO_THROW(config->addSharedView("shared3", "viewTransform1", "colorspace3", "", "", + "shared view description")); + OCIO_CHECK_THROW_WHAT(config->sanityCheck(), OCIO::Exception, + "refers to a view transform, 'viewTransform1', which is not defined"); + + OCIO::ViewTransformRcPtr vt = OCIO::ViewTransform::Create(OCIO::REFERENCE_SPACE_SCENE); + vt->setName("viewTransform1"); + OCIO_CHECK_NO_THROW(vt->setTransform(OCIO::MatrixTransform::Create(), + OCIO::VIEWTRANSFORM_DIR_FROM_REFERENCE)); + OCIO_CHECK_NO_THROW(config->addViewTransform(vt)); + OCIO_CHECK_NO_THROW(config->sanityCheck()); + + // Shared views need to refer to existing rules. + OCIO_CHECK_NO_THROW(config->addSharedView("shared4", "", "colorspace1", "", "rule1", "")); + OCIO_CHECK_THROW_WHAT(config->sanityCheck(), OCIO::Exception, + "viewing rule, 'rule1', which is not defined"); + + OCIO::ViewingRulesRcPtr vrules = OCIO::ViewingRules::Create(); + OCIO_CHECK_NO_THROW(vrules->insertRule(0, "rule1")); + OCIO_CHECK_NO_THROW(vrules->addColorSpace(0, "colorspace3")); + + OCIO_CHECK_NO_THROW(config->setViewingRules(vrules)); + OCIO_CHECK_NO_THROW(config->sanityCheck()); + + // Add shared view with description. + OCIO_CHECK_NO_THROW(config->addSharedView("shared5", "", "colorspace2", "", "", + "Sample description")); + OCIO_CHECK_NO_THROW(config->sanityCheck()); + + // Add another view to the sRGB display (CreateRaw creates an sRGB display with a Raw view). + OCIO_CHECK_NO_THROW(config->addDisplayView("sRGB", "view1", "colorspace1", "")); + OCIO_CHECK_NO_THROW(config->sanityCheck()); + + OCIO_CHECK_NO_THROW(config->addDisplaySharedView("sRGB", "shared2")); + OCIO_CHECK_NO_THROW(config->addDisplaySharedView("sRGB", "shared3")); + OCIO_CHECK_NO_THROW(config->addDisplaySharedView("sRGB", "shared4")); + OCIO_CHECK_NO_THROW(config->sanityCheck()); + + // Expecting five views: two DISPLAY_DEFINED views plus three SHARED views. + OCIO_REQUIRE_EQUAL(5, config->getNumViews("sRGB")); + OCIO_CHECK_EQUAL(std::string("Raw"), config->getView("sRGB", 0)); + OCIO_CHECK_EQUAL(std::string("view1"), config->getView("sRGB", 1)); + OCIO_CHECK_EQUAL(std::string("shared2"), config->getView("sRGB", 2)); + OCIO_CHECK_EQUAL(std::string("shared3"), config->getView("sRGB", 3)); + OCIO_CHECK_EQUAL(std::string("shared4"), config->getView("sRGB", 4)); + OCIO_REQUIRE_EQUAL(2, config->getNumViews(OCIO::VIEW_DISPLAY_DEFINED, "sRGB")); + OCIO_CHECK_EQUAL(std::string("Raw"), config->getView(OCIO::VIEW_DISPLAY_DEFINED, "sRGB", 0)); + OCIO_CHECK_EQUAL(std::string("view1"), config->getView(OCIO::VIEW_DISPLAY_DEFINED, "sRGB", 1)); + OCIO_REQUIRE_EQUAL(3, config->getNumViews(OCIO::VIEW_SHARED, "sRGB")); + OCIO_CHECK_EQUAL(std::string("shared2"), config->getView(OCIO::VIEW_SHARED, "sRGB", 0)); + OCIO_CHECK_EQUAL(std::string("shared3"), config->getView(OCIO::VIEW_SHARED, "sRGB", 1)); + OCIO_CHECK_EQUAL(std::string("shared4"), config->getView(OCIO::VIEW_SHARED, "sRGB", 2)); + + // Access view properties (either display-defined or shared views). + OCIO_CHECK_EQUAL(std::string("colorspace1"), + config->getDisplayViewColorSpaceName("sRGB", "view1")); + OCIO_CHECK_EQUAL(std::string("colorspace2"), + config->getDisplayViewColorSpaceName("sRGB", "shared2")); + OCIO_CHECK_EQUAL(std::string("viewTransform1"), + config->getDisplayViewTransformName("sRGB", "shared3")); + OCIO_CHECK_EQUAL(std::string("look1"), + config->getDisplayViewLooks("sRGB", "shared2")); + OCIO_CHECK_EQUAL(std::string("rule1"), + config->getDisplayViewRule("sRGB", "shared4")); + OCIO_CHECK_EQUAL(std::string("shared view description"), + config->getDisplayViewDescription("sRGB", "shared3")); + + // A null or empty display name may be used to access shared views (regardless of whether + // they are used in any displays). + OCIO_CHECK_EQUAL(std::string("colorspace1"), + config->getDisplayViewColorSpaceName(nullptr, "shared1")); + OCIO_CHECK_EQUAL(std::string("colorspace2"), + config->getDisplayViewColorSpaceName("", "shared2")); + OCIO_CHECK_EQUAL(std::string("look1"), + config->getDisplayViewLooks(nullptr, "shared2")); + OCIO_CHECK_EQUAL(std::string("viewTransform1"), + config->getDisplayViewTransformName(nullptr, "shared3")); + OCIO_CHECK_EQUAL(std::string("colorspace3"), + config->getDisplayViewColorSpaceName(nullptr, "shared3")); + OCIO_CHECK_EQUAL(std::string("rule1"), + config->getDisplayViewRule(nullptr, "shared4")); + OCIO_CHECK_EQUAL(std::string("Sample description"), + config->getDisplayViewDescription(nullptr, "shared5")); + + // Use active views. + config->setActiveViews("view1, shared3"); + OCIO_REQUIRE_EQUAL(2, config->getNumViews("sRGB")); + OCIO_CHECK_EQUAL(std::string("view1"), config->getView("sRGB", 0)); + OCIO_CHECK_EQUAL(std::string("shared3"), config->getView("sRGB", 1)); + + // Even if not active, view properties can be queried. + OCIO_CHECK_EQUAL(std::string("look1"), + config->getDisplayViewLooks("sRGB", "shared2")); + + // These are not affected by active views. + OCIO_REQUIRE_EQUAL(2, config->getNumViews(OCIO::VIEW_DISPLAY_DEFINED, "sRGB")); + OCIO_REQUIRE_EQUAL(3, config->getNumViews(OCIO::VIEW_SHARED, "sRGB")); + + // Save and reload. + std::ostringstream os; + os << *config.get(); + auto configStr = os.str(); + std::istringstream back; + back.str(configStr); + auto configBack = OCIO::Config::CreateFromStream(back); + + // Verify reloaded version of config. + OCIO_CHECK_EQUAL(config->getNumViews(OCIO::VIEW_SHARED, nullptr), + configBack->getNumViews(OCIO::VIEW_SHARED, nullptr)); + OCIO_CHECK_EQUAL(std::string("viewTransform1"), + configBack->getDisplayViewTransformName(nullptr, "shared3")); + OCIO_CHECK_EQUAL(std::string("colorspace3"), + configBack->getDisplayViewColorSpaceName(nullptr, "shared3")); + OCIO_CHECK_EQUAL(std::string("rule1"), + configBack->getDisplayViewRule(nullptr, "shared4")); + OCIO_CHECK_EQUAL(std::string("Sample description"), + configBack->getDisplayViewDescription(nullptr, "shared5")); + + // Add view to display with name of existing shared view will throw. + OCIO_CHECK_THROW_WHAT(config->addDisplayView("sRGB", "shared2", "colorspace1", ""), OCIO::Exception, + "There is already a shared view named 'shared2' in the display 'sRGB'"); + + // Add shared view to a display with name of existing view will throw. + // Shared1 is a shared view, but it is not used by sRGB, so a view with that name + // can be added as a display-defined view. + OCIO_CHECK_NO_THROW(config->addDisplayView("sRGB", "shared1", "colorspace1", "")); + OCIO_CHECK_NO_THROW(config->sanityCheck()); + OCIO_CHECK_THROW_WHAT(config->addDisplaySharedView("sRGB", "shared1"), OCIO::Exception, + "There is already a view named 'shared1' in the display 'sRGB'"); + + OCIO_CHECK_EQUAL(3, config->getNumViews(OCIO::VIEW_SHARED, "sRGB")); + OCIO_CHECK_NO_THROW(config->sanityCheck()); + + // Add undefined shared view. + OCIO_CHECK_NO_THROW(config->addDisplaySharedView("sRGB", "shared42")); + OCIO_CHECK_THROW_WHAT(config->sanityCheck(), OCIO::Exception, + "contains a shared view 'shared42' that is not defined"); + + // Remove faulty view. + OCIO_CHECK_NO_THROW(config->removeDisplayView("sRGB", "shared42")); + OCIO_CHECK_NO_THROW(config->sanityCheck()); + + // Remove unused shared view. + OCIO_CHECK_NO_THROW(config->removeSharedView("shared1")); + OCIO_CHECK_NO_THROW(config->sanityCheck()); + + // Replace one of the existing shared views. This time, it uses only a view transform and + // special color space name. However, the config is missing a display color space having the + // same name as the display. + OCIO_CHECK_NO_THROW(config->addSharedView("shared3", "viewTransform1", + OCIO::OCIO_VIEW_USE_DISPLAY_NAME, + "", "", "shared view description")); + + OCIO_CHECK_THROW_WHAT(config->sanityCheck(), OCIO::Exception, + "The display 'sRGB' contains a shared view 'shared3' " + "which does not define a color space and there is no color space " + "that matches the display name"); + + cs->setName("sRGB"); + config->addColorSpace(cs); + OCIO_CHECK_NO_THROW(config->sanityCheck()); + + // Verify that shared views with no color space are saved with a special display + // color space name, and that they are properly loaded. + os.clear(); + os.str(""); + + os << *config.get(); + configStr = os.str(); + + OCIO_CHECK_NE(std::string::npos, configStr.find(OCIO::OCIO_VIEW_USE_DISPLAY_NAME)); + + back.clear(); + back.str(configStr); + configBack = OCIO::Config::CreateFromStream(back); + + OCIO_CHECK_EQUAL(std::string(OCIO::OCIO_VIEW_USE_DISPLAY_NAME), + configBack->getDisplayViewColorSpaceName(nullptr, "shared3")); +} diff --git a/tests/cpu/FileRules_tests.cpp b/tests/cpu/FileRules_tests.cpp index 24a9583ff4..1cda8662c9 100644 --- a/tests/cpu/FileRules_tests.cpp +++ b/tests/cpu/FileRules_tests.cpp @@ -121,7 +121,7 @@ OCIO_ADD_TEST(FileRules, config_insert_rule) // Adds a rule with empty name. OCIO_CHECK_THROW_WHAT(fileRules->insertRule(0, nullptr, "raw", "*", "a"), - OCIO::Exception, "rule should have a non empty name"); + OCIO::Exception, "rule should have a non-empty name"); // Pattern and extension can't be null. OCIO_CHECK_THROW_WHAT(fileRules->insertRule(0, "rule", "raw", nullptr, "a"), @@ -152,24 +152,24 @@ OCIO_ADD_TEST(FileRules, config_rule_customkeys) OCIO_CHECK_THROW_WHAT(fileRules->getNumCustomKeys(3), OCIO::Exception, "rule index '3' invalid"); OCIO_CHECK_THROW_WHAT(fileRules->getCustomKeyName(0, 0), OCIO::Exception, - "key index '0' is invalid"); + "Key index '0' is invalid"); OCIO_CHECK_THROW_WHAT(fileRules->getCustomKeyName(1, 0), OCIO::Exception, - "key index '0' is invalid"); + "Key index '0' is invalid"); OCIO_CHECK_THROW_WHAT(fileRules->getCustomKeyName(2, 0), OCIO::Exception, - "key index '0' is invalid"); + "Key index '0' is invalid"); OCIO_CHECK_THROW_WHAT(fileRules->getCustomKeyValue(0, 0), OCIO::Exception, - "key index '0' is invalid"); + "Key index '0' is invalid"); OCIO_CHECK_THROW_WHAT(fileRules->getCustomKeyValue(1, 0), OCIO::Exception, - "key index '0' is invalid"); + "Key index '0' is invalid"); OCIO_CHECK_THROW_WHAT(fileRules->getCustomKeyValue(2, 0), OCIO::Exception, - "key index '0' is invalid"); + "Key index '0' is invalid"); OCIO_CHECK_NO_THROW(fileRules->setCustomKey(0, "key", "val")); OCIO_CHECK_NO_THROW(fileRules->setCustomKey(1, "key", "val")); OCIO_CHECK_NO_THROW(fileRules->setCustomKey(2, "keyDef", "valDef")); OCIO_CHECK_THROW_WHAT(fileRules->setCustomKey(0, nullptr, "val"), OCIO::Exception, - "key has to be a non empty string"); + "Key has to be a non-empty string"); OCIO_CHECK_THROW_WHAT(fileRules->setCustomKey(0, "", "val"), OCIO::Exception, - "key has to be a non empty string"); + "Key has to be a non-empty string"); OCIO_REQUIRE_EQUAL(fileRules->getNumCustomKeys(0), 1); OCIO_REQUIRE_EQUAL(fileRules->getNumCustomKeys(1), 1); OCIO_REQUIRE_EQUAL(fileRules->getNumCustomKeys(2), 1); @@ -1276,7 +1276,6 @@ OCIO_ADD_TEST(FileRules, rule_move) OCIO_CHECK_EQUAL(std::string(rules->getName(4)), "rule4"); } - OCIO_ADD_TEST(FileRules, clone) { // Validate that 'FileRules::createEditableCopy()' does not share FileRule instances. diff --git a/tests/cpu/ParseUtils_tests.cpp b/tests/cpu/ParseUtils_tests.cpp index f46905291f..6b6c2e8115 100644 --- a/tests/cpu/ParseUtils_tests.cpp +++ b/tests/cpu/ParseUtils_tests.cpp @@ -420,33 +420,33 @@ OCIO_ADD_TEST(ParseUtils, string_vec_to_int_vec) OCIO_ADD_TEST(ParseUtils, split_string_env_style) { StringUtils::StringVec outputvec; - OCIO::SplitStringEnvStyle(outputvec, "This:is:a:test"); + outputvec = OCIO::SplitStringEnvStyle("This:is:a:test"); OCIO_CHECK_EQUAL(4, outputvec.size()); OCIO_CHECK_EQUAL("This", outputvec[0]); OCIO_CHECK_EQUAL("is", outputvec[1]); OCIO_CHECK_EQUAL("a", outputvec[2]); OCIO_CHECK_EQUAL("test", outputvec[3]); outputvec.clear(); - OCIO::SplitStringEnvStyle(outputvec, " This : is : a: test "); + outputvec = OCIO::SplitStringEnvStyle(" This : is : a: test "); OCIO_CHECK_EQUAL(4, outputvec.size()); OCIO_CHECK_EQUAL("This", outputvec[0]); OCIO_CHECK_EQUAL("is", outputvec[1]); OCIO_CHECK_EQUAL("a", outputvec[2]); OCIO_CHECK_EQUAL("test", outputvec[3]); outputvec.clear(); - OCIO::SplitStringEnvStyle(outputvec, " This , is , a, test "); + outputvec = OCIO::SplitStringEnvStyle(" This , is , a, test "); OCIO_CHECK_EQUAL(4, outputvec.size()); OCIO_CHECK_EQUAL("This", outputvec[0]); OCIO_CHECK_EQUAL("is", outputvec[1]); OCIO_CHECK_EQUAL("a", outputvec[2]); OCIO_CHECK_EQUAL("test", outputvec[3]); outputvec.clear(); - OCIO::SplitStringEnvStyle(outputvec, "This:is , a:test "); + outputvec = OCIO::SplitStringEnvStyle("This:is , a:test "); OCIO_CHECK_EQUAL(2, outputvec.size()); OCIO_CHECK_EQUAL("This:is", outputvec[0]); OCIO_CHECK_EQUAL("a:test", outputvec[1]); outputvec.clear(); - OCIO::SplitStringEnvStyle(outputvec, ",,"); + outputvec = OCIO::SplitStringEnvStyle(",,"); OCIO_CHECK_EQUAL(3, outputvec.size()); OCIO_CHECK_EQUAL("", outputvec[0]); OCIO_CHECK_EQUAL("", outputvec[1]); diff --git a/tests/cpu/ViewingRules_tests.cpp b/tests/cpu/ViewingRules_tests.cpp new file mode 100644 index 0000000000..87bff7c4b1 --- /dev/null +++ b/tests/cpu/ViewingRules_tests.cpp @@ -0,0 +1,509 @@ +// SPDX-License-Identifier: BSD-3-Clause +// Copyright Contributors to the OpenColorIO Project. + + +#include "ViewingRules.cpp" + +#include "testutils/UnitTest.h" +#include "UnitTestUtils.h" + +namespace OCIO = OCIO_NAMESPACE; + + +OCIO_ADD_TEST(ViewingRules, basic) +{ + OCIO::ViewingRulesRcPtr vrules = OCIO::ViewingRules::Create(); + OCIO_REQUIRE_ASSERT(vrules); + OCIO_CHECK_EQUAL(vrules->getNumEntries(), 0); + + // Rules have to exist to be accessed. + OCIO_CHECK_THROW_WHAT(vrules->getName(0), OCIO::Exception, + "Viewing rules: rule index '0' invalid."); + OCIO_CHECK_THROW_WHAT(vrules->insertRule(1, "test"), OCIO::Exception, + "Viewing rules: rule index '1' invalid."); + // New rules must have a name. + OCIO_CHECK_THROW_WHAT(vrules->insertRule(0, ""), OCIO::Exception, + "Viewing rules: rule must have a non-empty name."); + OCIO_CHECK_THROW_WHAT(vrules->insertRule(0, nullptr), OCIO::Exception, + "Viewing rules: rule must have a non-empty name."); + + // Add rules. + const std::string ruleName0{ "Rule0" }; + OCIO_CHECK_NO_THROW(vrules->insertRule(0, ruleName0.c_str())); + + const std::string ruleName2{ "Rule2" }; + OCIO_CHECK_NO_THROW(vrules->insertRule(1, ruleName2.c_str())); + + // Adding Rule1 at index 1 will move Rule2 at index 2. + const std::string ruleName1{ "Rule1" }; + OCIO_CHECK_NO_THROW(vrules->insertRule(1, ruleName1.c_str())); + + OCIO_REQUIRE_EQUAL(vrules->getNumEntries(), 3); + std::string stringVal; + OCIO_CHECK_NO_THROW(stringVal = vrules->getName(0)); + OCIO_CHECK_EQUAL(stringVal, ruleName0); + OCIO_CHECK_NO_THROW(stringVal = vrules->getName(1)); + OCIO_CHECK_EQUAL(stringVal, ruleName1); + OCIO_CHECK_NO_THROW(stringVal = vrules->getName(2)); + OCIO_CHECK_EQUAL(stringVal, ruleName2); + + // Only have 3 rules, index 3 is invalid. + OCIO_CHECK_THROW_WHAT(vrules->getName(3), OCIO::Exception, + "Viewing rules: rule index '3' invalid."); + + // Rule names are unique. + OCIO_CHECK_THROW_WHAT(vrules->insertRule(1, ruleName1.c_str()), OCIO::Exception, + "A rule named 'Rule1' already exists"); + + // Check added rules properties are empty. + size_t numOf{ 0 }; + for (size_t r = 0; r < 3; ++r) + { + OCIO_CHECK_NO_THROW(numOf = vrules->getNumColorSpaces(r)); + OCIO_CHECK_EQUAL(numOf, 0); + OCIO_CHECK_NO_THROW(numOf = vrules->getNumEncodings(r)); + OCIO_CHECK_EQUAL(numOf, 0); + OCIO_CHECK_NO_THROW(numOf = vrules->getNumCustomKeys(r)); + OCIO_CHECK_EQUAL(numOf, 0); + } + + // Set colorspaces and verify. + const std::string cs0{ "colorspace0" }; + const std::string cs1{ "colorspace1" }; + OCIO_CHECK_NO_THROW(vrules->addColorSpace(0, cs0.c_str())); + OCIO_CHECK_NO_THROW(vrules->addColorSpace(0, cs1.c_str())); + OCIO_CHECK_NO_THROW(numOf = vrules->getNumColorSpaces(0)); + OCIO_CHECK_EQUAL(numOf, 2); + OCIO_CHECK_NO_THROW(stringVal = vrules->getColorSpace(0, 0)); + OCIO_CHECK_EQUAL(stringVal, cs0); + OCIO_CHECK_NO_THROW(stringVal = vrules->getColorSpace(0, 1)); + OCIO_CHECK_EQUAL(stringVal, cs1); + // Can not access non existing colorspaces. + OCIO_CHECK_THROW_WHAT(vrules->getColorSpace(0, 2), OCIO::Exception, + "rule 'Rule0' at index '0': colorspace index '2' is invalid."); + // Remove color space. + OCIO_CHECK_THROW_WHAT(vrules->removeColorSpace(3, 0), OCIO::Exception, + "Viewing rules: rule index '3' invalid."); + OCIO_CHECK_THROW_WHAT(vrules->removeColorSpace(0, 2), OCIO::Exception, + "rule 'Rule0' at index '0': colorspace index '2' is invalid."); + OCIO_CHECK_NO_THROW(vrules->removeColorSpace(0, 0)); + OCIO_CHECK_NO_THROW(numOf = vrules->getNumColorSpaces(0)); + OCIO_CHECK_EQUAL(numOf, 1); + OCIO_CHECK_NO_THROW(stringVal = vrules->getColorSpace(0, 0)); + OCIO_CHECK_EQUAL(stringVal, cs1); + // Re-add color space. + OCIO_CHECK_NO_THROW(vrules->addColorSpace(0, cs0.c_str())); + + // Same with encodings. + const std::string enc0{ "encoding0" }; + const std::string enc1{ "encoding1" }; + OCIO_CHECK_THROW_WHAT(vrules->addEncoding(0, enc0.c_str()), OCIO::Exception, + "encoding can't be added if there are colorspaces."); + OCIO_CHECK_NO_THROW(vrules->addEncoding(1, enc0.c_str())); + OCIO_CHECK_NO_THROW(vrules->addEncoding(1, enc1.c_str())); + OCIO_CHECK_THROW_WHAT(vrules->addColorSpace(1, cs0.c_str()), OCIO::Exception, + "colorspace can't be added if there are encodings."); + OCIO_CHECK_NO_THROW(numOf = vrules->getNumEncodings(1)); + OCIO_CHECK_EQUAL(numOf, 2); + OCIO_CHECK_NO_THROW(stringVal = vrules->getEncoding(1, 0)); + OCIO_CHECK_EQUAL(stringVal, enc0); + OCIO_CHECK_NO_THROW(stringVal = vrules->getEncoding(1, 1)); + OCIO_CHECK_EQUAL(stringVal, enc1); + OCIO_CHECK_THROW_WHAT(vrules->getEncoding(1, 2), OCIO::Exception, + "rule 'Rule1' at index '1': encoding index '2' is invalid."); + // Remove encoding. + OCIO_CHECK_THROW_WHAT(vrules->removeEncoding(3, 0), OCIO::Exception, + "Viewing rules: rule index '3' invalid."); + OCIO_CHECK_THROW_WHAT(vrules->removeEncoding(1, 2), OCIO::Exception, + "rule 'Rule1' at index '1': encoding index '2' is invalid."); + OCIO_CHECK_NO_THROW(vrules->removeEncoding(1, 0)); + OCIO_CHECK_NO_THROW(numOf = vrules->getNumEncodings(1)); + OCIO_CHECK_EQUAL(numOf, 1); + OCIO_CHECK_NO_THROW(stringVal = vrules->getEncoding(1, 0)); + OCIO_CHECK_EQUAL(stringVal, enc1); + // Re-add encoding. + OCIO_CHECK_NO_THROW(vrules->addEncoding(1, enc0.c_str())); + + // Same with custom keys. + const std::string key0{ "key0" }; + const std::string value0{ "value0" }; + const std::string key1{ "key1" }; + const std::string value1{ "value1" }; + OCIO_CHECK_NO_THROW(vrules->setCustomKey(0, key0.c_str(), value0.c_str())); + OCIO_CHECK_NO_THROW(vrules->setCustomKey(0, key1.c_str(), value1.c_str())); + OCIO_CHECK_NO_THROW(numOf = vrules->getNumCustomKeys(0)); + OCIO_CHECK_EQUAL(numOf, 2); + OCIO_CHECK_NO_THROW(stringVal = vrules->getCustomKeyName(0, 0)); + OCIO_CHECK_EQUAL(stringVal, key0); + OCIO_CHECK_NO_THROW(stringVal = vrules->getCustomKeyValue(0, 0)); + OCIO_CHECK_EQUAL(stringVal, value0); + OCIO_CHECK_NO_THROW(stringVal = vrules->getCustomKeyName(0, 1)); + OCIO_CHECK_EQUAL(stringVal, key1); + OCIO_CHECK_NO_THROW(stringVal = vrules->getCustomKeyValue(0, 1)); + OCIO_CHECK_EQUAL(stringVal, value1); + OCIO_CHECK_THROW_WHAT(vrules->getCustomKeyName(0, 2), OCIO::Exception, + "rule named 'Rule0' error: Key index '2' is invalid"); + OCIO_CHECK_THROW_WHAT(vrules->getCustomKeyValue(0, 2), OCIO::Exception, + "rule named 'Rule0' error: Key index '2' is invalid"); + + const std::string newvalue0{ "newvalue0" }; + OCIO_CHECK_NO_THROW(vrules->setCustomKey(0, key0.c_str(), newvalue0.c_str())); + OCIO_CHECK_NO_THROW(numOf = vrules->getNumCustomKeys(0)); + OCIO_CHECK_EQUAL(numOf, 2); + OCIO_CHECK_NO_THROW(stringVal = vrules->getCustomKeyValue(0, 0)); + OCIO_CHECK_EQUAL(stringVal, newvalue0); + + // Test serialization. + std::ostringstream oss; + oss << *vrules; + constexpr char OUTPUT[]{ R"( + +)" }; + + OCIO_CHECK_EQUAL(oss.str(), OUTPUT); + + // Removing a rule: throws if index is not valid. + const auto numRules = vrules->getNumEntries(); + OCIO_CHECK_THROW_WHAT(vrules->removeRule(numRules), OCIO::Exception, + "rule index '3' invalid. There are only '3' rules"); + OCIO_REQUIRE_EQUAL(vrules->getNumEntries(), numRules); + OCIO_CHECK_NO_THROW(numOf = vrules->getNumColorSpaces(0)); + OCIO_CHECK_EQUAL(numOf, 2); + OCIO_CHECK_NO_THROW(numOf = vrules->getNumEncodings(1)); + OCIO_CHECK_EQUAL(numOf, 2); + + // Remove rule, and check it is gone. + OCIO_CHECK_NO_THROW(vrules->removeRule(1)); + OCIO_REQUIRE_EQUAL(vrules->getNumEntries(), 2); + OCIO_CHECK_NO_THROW(stringVal = vrules->getName(0)); + OCIO_CHECK_EQUAL(stringVal, ruleName0); + OCIO_CHECK_NO_THROW(stringVal = vrules->getName(1)); + OCIO_CHECK_EQUAL(stringVal, ruleName2); + + // Get index of a rule. + OCIO_CHECK_NO_THROW(vrules->getIndexForRule(ruleName0.c_str())); + OCIO_CHECK_EQUAL(0, vrules->getIndexForRule(ruleName0.c_str())); + OCIO_CHECK_NO_THROW(vrules->getIndexForRule(ruleName2.c_str())); + OCIO_CHECK_EQUAL(1, vrules->getIndexForRule(ruleName2.c_str())); + OCIO_CHECK_THROW_WHAT(vrules->getIndexForRule("I am not there"), OCIO::Exception, + "rule name 'I am not there' not found"); +} + +OCIO_ADD_TEST(ViewingRules, config_io) +{ + // Create a config with viewing rules. + OCIO::ConfigRcPtr config = OCIO::Config::CreateRaw()->createEditableCopy(); + + OCIO::ViewingRulesRcPtr vrules = OCIO::ViewingRules::Create(); + const std::string ruleName0{ "Rule0" }; + OCIO_CHECK_NO_THROW(vrules->insertRule(0, ruleName0.c_str())); + const std::string ruleName1{ "Rule1" }; + OCIO_CHECK_NO_THROW(vrules->insertRule(1, ruleName1.c_str())); + + const std::string key0{ "key0" }; + const std::string value0{ "value0" }; + const std::string key1{ "key1" }; + const std::string value1{ "value1" }; + OCIO_CHECK_NO_THROW(vrules->setCustomKey(0, key0.c_str(), value0.c_str())); + OCIO_CHECK_NO_THROW(vrules->setCustomKey(0, key1.c_str(), value1.c_str())); + + const std::string enc0{ "encoding0" }; + const std::string enc1{ "encoding1" }; + OCIO_CHECK_NO_THROW(vrules->addEncoding(1, enc0.c_str())); + OCIO_CHECK_NO_THROW(vrules->addEncoding(1, enc1.c_str())); + + // Rules have to refer to colorspace or encoding. + config->setViewingRules(vrules); + OCIO_CHECK_THROW_WHAT(config->sanityCheck(), OCIO::Exception, + "must have either a color space or an encoding"); + + const std::string cs0{ "colorspace0" }; + OCIO_CHECK_NO_THROW(vrules->addColorSpace(0, cs0.c_str())); + auto cs = OCIO::ColorSpace::Create(); + cs->setName(cs0.c_str()); + config->addColorSpace(cs); + + cs->setName("cs_enc0"); + cs->setEncoding(enc0.c_str()); + config->addColorSpace(cs); + + cs->setName("cs_enc1"); + cs->setEncoding(enc1.c_str()); + config->addColorSpace(cs); + + config->setViewingRules(vrules); + OCIO_CHECK_NO_THROW(config->sanityCheck()); + + // Save config and load back. + std::ostringstream oss; + oss << *config.get(); + auto configStr = oss.str(); + std::istringstream back; + back.str(configStr); + auto configBack = OCIO::Config::CreateFromStream(back); + + // Verify rules have been loaded. + auto vr = configBack->getViewingRules(); + OCIO_REQUIRE_EQUAL(vr->getNumEntries(), 2); + + std::string stringVal; + OCIO_CHECK_NO_THROW(stringVal = vr->getName(0)); + OCIO_CHECK_EQUAL(stringVal, ruleName0); + OCIO_CHECK_NO_THROW(stringVal = vr->getName(1)); + OCIO_CHECK_EQUAL(stringVal, ruleName1); + + size_t numOf{ 0 }; + OCIO_CHECK_NO_THROW(numOf = vr->getNumColorSpaces(0)); + OCIO_CHECK_EQUAL(numOf, 1); + OCIO_CHECK_NO_THROW(numOf = vr->getNumEncodings(0)); + OCIO_CHECK_EQUAL(numOf, 0); + OCIO_CHECK_NO_THROW(numOf = vr->getNumCustomKeys(0)); + OCIO_CHECK_EQUAL(numOf, 2); + + OCIO_CHECK_NO_THROW(stringVal = vr->getColorSpace(0, 0)); + OCIO_CHECK_EQUAL(stringVal, cs0); + OCIO_CHECK_NO_THROW(stringVal = vr->getCustomKeyName(0, 0)); + OCIO_CHECK_EQUAL(stringVal, key0); + OCIO_CHECK_NO_THROW(stringVal = vr->getCustomKeyValue(0, 0)); + OCIO_CHECK_EQUAL(stringVal, value0); + OCIO_CHECK_NO_THROW(stringVal = vr->getCustomKeyName(0, 1)); + OCIO_CHECK_EQUAL(stringVal, key1); + OCIO_CHECK_NO_THROW(stringVal = vr->getCustomKeyValue(0, 1)); + OCIO_CHECK_EQUAL(stringVal, value1); + + OCIO_CHECK_NO_THROW(numOf = vr->getNumColorSpaces(1)); + OCIO_CHECK_EQUAL(numOf, 0); + OCIO_CHECK_NO_THROW(numOf = vr->getNumEncodings(1)); + OCIO_CHECK_EQUAL(numOf, 2); + OCIO_CHECK_NO_THROW(numOf = vr->getNumCustomKeys(1)); + OCIO_CHECK_EQUAL(numOf, 0); + OCIO_CHECK_NO_THROW(stringVal = vr->getEncoding(1, 0)); + OCIO_CHECK_EQUAL(stringVal, enc0); + OCIO_CHECK_NO_THROW(stringVal = vr->getEncoding(1, 1)); + OCIO_CHECK_EQUAL(stringVal, enc1); +} + +OCIO_ADD_TEST(ViewingRules, filtered_views) +{ + constexpr char SIMPLE_CONFIG[]{ R"(ocio_profile_version: 2 + +search_path: "" +strictparsing: true +luma: [0.2126, 0.7152, 0.0722] + +roles: + default: raw + scene_linear: c3 + +file_rules: + - ! {name: ColorSpaceNamePathSearch} + - ! {name: Default, colorspace: raw} + +viewing_rules: + - ! {name: Rule_1, colorspaces: c1} + - ! {name: Rule_2, colorspaces: [c2, c3]} + - ! {name: Rule_3, colorspaces: scene_linear} + - ! {name: Rule_4, colorspaces: [c3, c4]} + - ! {name: Rule_5, encodings: log} + - ! {name: Rule_6, encodings: [log, video]} + +shared_views: + - ! {name: SView_a, colorspace: raw, rule: Rule_2} + - ! {name: SView_b, colorspace: raw, rule: Rule_3} + - ! {name: SView_c, colorspace: raw} + - ! {name: SView_d, colorspace: raw, rule: Rule_5} + - ! {name: SView_e, colorspace: raw} + +displays: + sRGB: + - ! {name: View_a, colorspace: raw, rule: Rule_1} + - ! {name: View_b, colorspace: raw, rule: Rule_2} + - ! {name: View_c, colorspace: raw, rule: Rule_2} + - ! {name: View_d, colorspace: raw, rule: Rule_3} + - ! {name: View_e, colorspace: raw, rule: Rule_4} + - ! {name: View_f, colorspace: raw, rule: Rule_5} + - ! {name: View_g, colorspace: raw, rule: Rule_6} + - ! {name: View_h, colorspace: raw} + - ! [SView_a, SView_b, SView_d, SView_e] + +active_displays: [] +active_views: [] + +colorspaces: + - ! + name: raw + family: "" + equalitygroup: "" + bitdepth: unknown + isdata: false + allocation: uniform + + - ! + name: c1 + family: "" + equalitygroup: "" + bitdepth: unknown + isdata: false + encoding: video + allocation: uniform + + - ! + name: c2 + family: "" + equalitygroup: "" + bitdepth: unknown + isdata: false + allocation: uniform + + - ! + name: c3 + family: "" + equalitygroup: "" + bitdepth: unknown + isdata: false + allocation: uniform + + - ! + name: c4 + family: "" + equalitygroup: "" + bitdepth: unknown + isdata: false + encoding: log + allocation: uniform + + - ! + name: c5 + family: "" + equalitygroup: "" + bitdepth: unknown + isdata: false + encoding: data + allocation: uniform + + - ! + name: c6 + family: "" + equalitygroup: "" + bitdepth: unknown + isdata: false + encoding: video + allocation: uniform +)" }; + + std::istringstream is(SIMPLE_CONFIG); + OCIO::ConstConfigRcPtr config; + OCIO_CHECK_NO_THROW(config = OCIO::Config::CreateFromStream(is)); + OCIO_CHECK_NO_THROW(config->sanityCheck()); + + // Check 2 rules of 2 non-existing display/views. + std::string rule; + rule = config->getDisplayViewRule("no", "unknown"); + OCIO_CHECK_EQUAL(rule, ""); + rule = config->getDisplayViewRule("sRGB", "unknown"); + OCIO_CHECK_EQUAL(rule, ""); + // sRGB/View_b uses Rule_2. + rule = config->getDisplayViewRule("sRGB", "View_b"); + OCIO_CHECK_EQUAL(rule, "Rule_2"); + + int numViews{ 0 }; + std::string view; + // Access views by colorspace on non existing display: 0 and empty string. + OCIO_CHECK_NO_THROW(numViews = config->getNumViews("no", "unknown")); + OCIO_CHECK_EQUAL(numViews, 0); + OCIO_CHECK_NO_THROW(view = config->getView("no", "unknown", 0)); + OCIO_CHECK_EQUAL(view, ""); + + // When display exists, colorspace has to exist or it will throw. + OCIO_CHECK_THROW_WHAT(config->getNumViews("sRGB", "unknown"), OCIO::Exception, + "Could not find source color space 'unknown'."); + OCIO_CHECK_THROW_WHAT(config->getView("sRGB", "unknown", 0), OCIO::Exception, + "Could not find source color space 'unknown'."); + + // Views by existing colorspace on existing display. + OCIO_CHECK_NO_THROW(numViews = config->getNumViews("sRGB", "c6")); + OCIO_CHECK_EQUAL(numViews, 3); + OCIO_CHECK_NO_THROW(view = config->getView("sRGB", "c6", 0)); + // View_g rule is Rule_6 that lists encoding video, c6 has encoding video. + OCIO_CHECK_EQUAL(view, "View_g"); + OCIO_CHECK_NO_THROW(view = config->getView("sRGB", "c6", 1)); + // View_h has no rule. + OCIO_CHECK_EQUAL(view, "View_h"); + OCIO_CHECK_NO_THROW(view = config->getView("sRGB", "c6", 2)); + // Shared SView_e has no rule. + OCIO_CHECK_EQUAL(view, "SView_e"); + // There is no 4th view: empty string. + OCIO_CHECK_NO_THROW(view = config->getView("sRGB", "c6", 3)); + OCIO_CHECK_ASSERT(view.empty()); + + OCIO_CHECK_NO_THROW(numViews = config->getNumViews("sRGB", "c3")); + OCIO_CHECK_EQUAL(numViews, 8); + OCIO_CHECK_NO_THROW(view = config->getView("sRGB", "c3", 0)); + // View_b rule is Rule_2 that lists c3. + OCIO_CHECK_EQUAL(view, "View_b"); + OCIO_CHECK_NO_THROW(view = config->getView("sRGB", "c3", 1)); + // View_c rule is Rule_2 that lists c3. + OCIO_CHECK_EQUAL(view, "View_c"); + OCIO_CHECK_NO_THROW(view = config->getView("sRGB", "c3", 2)); + // View_d rule is Rule_3 that lists c3. + OCIO_CHECK_EQUAL(view, "View_d"); + OCIO_CHECK_NO_THROW(view = config->getView("sRGB", "c3", 3)); + // View_e rule is Rule_4 that lists c3. + OCIO_CHECK_EQUAL(view, "View_e"); + OCIO_CHECK_NO_THROW(view = config->getView("sRGB", "c3", 4)); + // View_h has no rule. + OCIO_CHECK_EQUAL(view, "View_h"); + OCIO_CHECK_NO_THROW(view = config->getView("sRGB", "c3", 5)); + // SView_a has rule Rule_2 that lists c3. + OCIO_CHECK_EQUAL(view, "SView_a"); + OCIO_CHECK_NO_THROW(view = config->getView("sRGB", "c3", 6)); + // SView_b has rule Rule_3 that lists c3. + OCIO_CHECK_EQUAL(view, "SView_b"); + OCIO_CHECK_NO_THROW(view = config->getView("sRGB", "c3", 7)); + // SView_e has no rule. + OCIO_CHECK_EQUAL(view, "SView_e"); + + OCIO_CHECK_NO_THROW(numViews = config->getNumViews("sRGB", "c4")); + OCIO_CHECK_EQUAL(numViews, 6); + OCIO_CHECK_NO_THROW(view = config->getView("sRGB", "c4", 0)); + // View_e rule is Rule_4 that lists c4. + OCIO_CHECK_EQUAL(view, "View_e"); + OCIO_CHECK_NO_THROW(view = config->getView("sRGB", "c4", 1)); + // View_f rule is Rule_5 that lists encoding log, c4 has encoding log. + OCIO_CHECK_EQUAL(view, "View_f"); + OCIO_CHECK_NO_THROW(view = config->getView("sRGB", "c4", 2)); + // View_g rule is Rule_6 that lists encoding log, c4 has encoding log. + OCIO_CHECK_EQUAL(view, "View_g"); + OCIO_CHECK_NO_THROW(view = config->getView("sRGB", "c4", 3)); + // View_h has no rule. + OCIO_CHECK_EQUAL(view, "View_h"); + OCIO_CHECK_NO_THROW(view = config->getView("sRGB", "c4", 4)); + // SView_d rule is Rule_5 that lists encoding log, c4 has encoding log. + OCIO_CHECK_EQUAL(view, "SView_d"); + OCIO_CHECK_NO_THROW(view = config->getView("sRGB", "c4", 5)); + // SView_e has no rule. + OCIO_CHECK_EQUAL(view, "SView_e"); + + std::stringstream os; + os << *config.get(); + OCIO_CHECK_EQUAL(os.str(), SIMPLE_CONFIG); + + // Copy to set active views. + OCIO::ConfigRcPtr configav = config->createEditableCopy(); + configav->setActiveViews("SView_e, View_h, SView_d, View_d, SView_a, View_b"); + OCIO_CHECK_NO_THROW(configav->sanityCheck()); + + // Viewing rule results are further filtered and re-ordered by the active views list. + OCIO_CHECK_NO_THROW(numViews = configav->getNumViews("sRGB", "c3")); + OCIO_CHECK_EQUAL(numViews, 5); + OCIO_CHECK_NO_THROW(view = configav->getView("sRGB", "c3", 0)); + OCIO_CHECK_EQUAL(view, "SView_e"); + OCIO_CHECK_NO_THROW(view = configav->getView("sRGB", "c3", 1)); + OCIO_CHECK_EQUAL(view, "View_h"); + OCIO_CHECK_NO_THROW(view = configav->getView("sRGB", "c3", 2)); + OCIO_CHECK_EQUAL(view, "View_d"); + OCIO_CHECK_NO_THROW(view = configav->getView("sRGB", "c3", 3)); + OCIO_CHECK_EQUAL(view, "SView_a"); + OCIO_CHECK_NO_THROW(view = configav->getView("sRGB", "c3", 4)); + OCIO_CHECK_EQUAL(view, "View_b"); +} diff --git a/tests/cpu/transforms/ColorSpaceTransform_tests.cpp b/tests/cpu/transforms/ColorSpaceTransform_tests.cpp index e638ffac82..53f8212424 100644 --- a/tests/cpu/transforms/ColorSpaceTransform_tests.cpp +++ b/tests/cpu/transforms/ColorSpaceTransform_tests.cpp @@ -4,8 +4,8 @@ #include "transforms/ColorSpaceTransform.cpp" -#include "ops/exponent/ExponentOp.h" #include "ops/fixedfunction/FixedFunctionOpData.h" +#include "ops/gamma/GammaOpData.h" #include "ops/log/LogOpData.h" #include "ops/matrix/MatrixOpData.h" #include "testutils/UnitTest.h" @@ -33,6 +33,12 @@ OCIO_ADD_TEST(ColorSpaceTransform, basic) cst->setDst(dst.c_str()); OCIO_CHECK_EQUAL(dst, cst->getDst()); + OCIO_CHECK_EQUAL(true, cst->getDataBypass()); + cst->setDataBypass(false); + OCIO_CHECK_EQUAL(false, cst->getDataBypass()); + cst->setDataBypass(true); + OCIO_CHECK_EQUAL(true, cst->getDataBypass()); + OCIO_CHECK_NO_THROW(cst->validate()); cst->setSrc(""); @@ -61,7 +67,7 @@ OCIO_ADD_TEST(ColorSpaceTransform, build_colorspace_ops) const std::string dst{ "destination" }; cst->setDst(dst.c_str()); - OCIO::ConfigRcPtr config = OCIO::Config::Create(); + OCIO::ConfigRcPtr config = OCIO::Config::CreateRaw()->createEditableCopy(); auto csSceneToRef = OCIO::ColorSpace::Create(OCIO::REFERENCE_SPACE_SCENE); csSceneToRef->setName(src.c_str()); auto mat = OCIO::MatrixTransform::Create(); @@ -77,7 +83,7 @@ OCIO_ADD_TEST(ColorSpaceTransform, build_colorspace_ops) csSceneFromRef->setTransform(ff, OCIO::COLORSPACE_DIR_FROM_REFERENCE); config->addColorSpace(csSceneFromRef); - config->addDisplay("display", "view", dst.c_str(), ""); + config->addDisplayView("display", "view", dst.c_str(), ""); OCIO_CHECK_NO_THROW(config->sanityCheck()); @@ -122,6 +128,52 @@ OCIO_ADD_TEST(ColorSpaceTransform, build_colorspace_ops) OCIO_CHECK_EQUAL(data->getType(), OCIO::OpData::NoOpType); } + { + // Test that data color space will not create a color space conversion unless the + // color space transform forces data to be processed. + + csSceneToRef->setIsData(true); + config->addColorSpace(csSceneToRef); + + OCIO::OpRcPtrVec ops; + OCIO_CHECK_NO_THROW(OCIO::BuildColorSpaceOps(ops, *config, config->getCurrentContext(), + *cst, OCIO::TRANSFORM_DIR_FORWARD)); + OCIO_CHECK_NO_THROW(ops.validate()); + OCIO_CHECK_EQUAL(ops.size(), 0); + + cst->setDataBypass(false); + OCIO_CHECK_NO_THROW(OCIO::BuildColorSpaceOps(ops, *config, config->getCurrentContext(), + *cst, OCIO::TRANSFORM_DIR_FORWARD)); + OCIO_CHECK_NO_THROW(ops.validate()); + OCIO_CHECK_EQUAL(ops.size(), 4); + + // Restore default data flags. + csSceneToRef->setIsData(false); + config->addColorSpace(csSceneToRef); + cst->setDataBypass(true); + + // Same with destination color space. + csSceneFromRef->setIsData(true); + config->addColorSpace(csSceneFromRef); + + ops.clear(); + OCIO_CHECK_NO_THROW(OCIO::BuildColorSpaceOps(ops, *config, config->getCurrentContext(), + *cst, OCIO::TRANSFORM_DIR_FORWARD)); + OCIO_CHECK_NO_THROW(ops.validate()); + OCIO_CHECK_EQUAL(ops.size(), 0); + + cst->setDataBypass(false); + OCIO_CHECK_NO_THROW(OCIO::BuildColorSpaceOps(ops, *config, config->getCurrentContext(), + *cst, OCIO::TRANSFORM_DIR_FORWARD)); + OCIO_CHECK_NO_THROW(ops.validate()); + OCIO_CHECK_EQUAL(ops.size(), 4); + + // Restore default data flags. + csSceneFromRef->setIsData(false); + config->addColorSpace(csSceneFromRef); + cst->setDataBypass(true); + } + { // Test in other direction. // Expecting destination-from reference inverted + source-to reference inverted. @@ -160,6 +212,7 @@ OCIO_ADD_TEST(ColorSpaceTransform, build_colorspace_ops) OCIO_CHECK_EQUAL(data->getType(), OCIO::OpData::NoOpType); // Finalize converts invert matrix into forward matrix. + OCIO_CHECK_NO_THROW(ops.validate()); OCIO_CHECK_NO_THROW(ops.finalize(OCIO::OPTIMIZATION_NONE)); // No-ops are gone. OCIO_REQUIRE_EQUAL(ops.size(), 2); @@ -178,12 +231,12 @@ OCIO_ADD_TEST(ColorSpaceTransform, build_colorspace_ops) { // Color space to reference ops: color space only defines from_reference, expecting the - // inverse of that transform. + // inverse of that transform. Don't bypass data color spaces. OCIO::OpRcPtrVec ops; OCIO_CHECK_NO_THROW(OCIO::BuildColorSpaceToReferenceOps(ops, *config, config->getCurrentContext(), - csSceneFromRef)); + csSceneFromRef, false)); OCIO_CHECK_NO_THROW(ops.validate()); OCIO_REQUIRE_EQUAL(ops.size(), 2); auto op = OCIO_DYNAMIC_POINTER_CAST(ops[1]); @@ -200,7 +253,7 @@ OCIO_ADD_TEST(ColorSpaceTransform, build_colorspace_ops) OCIO::OpRcPtrVec ops; OCIO_CHECK_NO_THROW(OCIO::BuildColorSpaceFromReferenceOps(ops, *config, config->getCurrentContext(), - csSceneFromRef)); + csSceneFromRef, true)); OCIO_CHECK_NO_THROW(ops.validate()); OCIO_REQUIRE_EQUAL(ops.size(), 2); auto op = OCIO_DYNAMIC_POINTER_CAST(ops[0]); @@ -217,10 +270,22 @@ OCIO_ADD_TEST(ColorSpaceTransform, build_colorspace_ops) auto csSceneBoth = csSceneFromRef->createEditableCopy(); ff->setStyle(OCIO::FIXED_FUNCTION_ACES_GLOW_10); csSceneBoth->setTransform(ff, OCIO::COLORSPACE_DIR_TO_REFERENCE); + + // Make it a data colorspace. + csSceneBoth->setIsData(true); + + // If data is bypassed, nothing is created. OCIO::OpRcPtrVec ops; OCIO_CHECK_NO_THROW(OCIO::BuildColorSpaceFromReferenceOps(ops, *config, config->getCurrentContext(), - csSceneBoth)); + csSceneBoth, true)); + OCIO_CHECK_NO_THROW(ops.validate()); + OCIO_REQUIRE_EQUAL(ops.size(), 0); + + // If data is not bypassed ops are created. + OCIO_CHECK_NO_THROW(OCIO::BuildColorSpaceFromReferenceOps(ops, *config, + config->getCurrentContext(), + csSceneBoth, false)); OCIO_CHECK_NO_THROW(ops.validate()); OCIO_REQUIRE_EQUAL(ops.size(), 2); auto op = OCIO_DYNAMIC_POINTER_CAST(ops[0]); @@ -228,10 +293,13 @@ OCIO_ADD_TEST(ColorSpaceTransform, build_colorspace_ops) OCIO_REQUIRE_EQUAL(data->getType(), OCIO::OpData::FixedFunctionType); auto ffData = OCIO_DYNAMIC_POINTER_CAST(data); OCIO_CHECK_EQUAL(ffData->getStyle(), OCIO::FixedFunctionOpData::ACES_GLOW_03_FWD); + + // Remove the data property and try in the other direction. + csSceneBoth->setIsData(false); ops.clear(); OCIO_CHECK_NO_THROW(OCIO::BuildColorSpaceToReferenceOps(ops, *config, config->getCurrentContext(), - csSceneBoth)); + csSceneBoth, true)); OCIO_CHECK_NO_THROW(ops.validate()); OCIO_REQUIRE_EQUAL(ops.size(), 2); op = OCIO_DYNAMIC_POINTER_CAST(ops[1]); @@ -253,12 +321,14 @@ OCIO_ADD_TEST(ColorSpaceTransform, build_colorspace_ops) config->addColorSpace(csDisplayFromRef); // Because there are display-referred color spaces, there need to be a view transform. + config->upgradeToLatestVersion(); // View transforms are a v2 feature. auto vt = OCIO::ViewTransform::Create(OCIO::REFERENCE_SPACE_SCENE); vt->setName("view_transform"); vt->setTransform(mat, OCIO::VIEWTRANSFORM_DIR_FROM_REFERENCE); OCIO_CHECK_NO_THROW(config->addViewTransform(vt)); - OCIO_CHECK_EQUAL(config->getNumColorSpaces(), 2); + // 3 color spaces including "raw". + OCIO_CHECK_EQUAL(config->getNumColorSpaces(), 3); OCIO_CHECK_NO_THROW(config->sanityCheck()); // cst is now from csDisplayToRef to csDisplayFromRef. @@ -317,7 +387,7 @@ OCIO_ADD_TEST(ColorSpaceTransform, build_reference_conversion_ops) { const std::string scn{ "scene" }; - OCIO::ConfigRcPtr config = OCIO::Config::Create(); + OCIO::ConfigRcPtr config = OCIO::Config::CreateRaw()->createEditableCopy(); auto cs = OCIO::ColorSpace::Create(OCIO::REFERENCE_SPACE_SCENE); cs->setName(scn.c_str()); auto ff = OCIO::FixedFunctionTransform::Create(); @@ -325,7 +395,7 @@ OCIO_ADD_TEST(ColorSpaceTransform, build_reference_conversion_ops) cs->setTransform(ff, OCIO::COLORSPACE_DIR_FROM_REFERENCE); config->addColorSpace(cs); - config->addDisplay("display", "view", scn.c_str(), ""); + config->addDisplayView("display", "view", scn.c_str(), ""); OCIO_CHECK_NO_THROW(config->sanityCheck()); @@ -366,6 +436,7 @@ OCIO_ADD_TEST(ColorSpaceTransform, build_reference_conversion_ops) // Add scene-referred view transform. // + config->upgradeToLatestVersion(); auto vt = OCIO::ViewTransform::Create(OCIO::REFERENCE_SPACE_SCENE); vt->setName("view_transform"); auto mat = OCIO::MatrixTransform::Create(); @@ -423,6 +494,8 @@ OCIO_ADD_TEST(ColorSpaceTransform, build_colorspace_ops_with_reference_conversio const std::string scn{ "scene" }; OCIO::ConfigRcPtr config = OCIO::Config::Create(); + config->upgradeToLatestVersion(); + auto cs = OCIO::ColorSpace::Create(OCIO::REFERENCE_SPACE_SCENE); cs->setName(scn.c_str()); auto ff = OCIO::FixedFunctionTransform::Create(); @@ -430,7 +503,7 @@ OCIO_ADD_TEST(ColorSpaceTransform, build_colorspace_ops_with_reference_conversio cs->setTransform(ff, OCIO::COLORSPACE_DIR_FROM_REFERENCE); config->addColorSpace(cs); - config->addDisplay("display", "view", scn.c_str(), ""); + config->addDisplayView("display", "view", scn.c_str(), ""); // Add scene-referred view transform. auto vt = OCIO::ViewTransform::Create(OCIO::REFERENCE_SPACE_SCENE); @@ -590,9 +663,9 @@ OCIO_ADD_TEST(ColorSpaceTransform, build_colorspace_ops_with_reference_conversio // Display reference to scene reference. op = OCIO_DYNAMIC_POINTER_CAST(ops[2]); data = op->data(); - OCIO_REQUIRE_EQUAL(data->getType(), OCIO::OpData::ExponentType); - auto expData = OCIO_DYNAMIC_POINTER_CAST(data); - OCIO_CHECK_EQUAL(expData->m_exp4[0], 1.0); + OCIO_REQUIRE_EQUAL(data->getType(), OCIO::OpData::GammaType); + auto gammaData = OCIO_DYNAMIC_POINTER_CAST(data); + OCIO_CHECK_EQUAL(gammaData->getRedParams()[0], 1.0); op = OCIO_DYNAMIC_POINTER_CAST(ops[3]); data = op->data(); diff --git a/tests/cpu/transforms/DisplayTransform_tests.cpp b/tests/cpu/transforms/DisplayTransform_tests.cpp deleted file mode 100644 index 43cf0cddad..0000000000 --- a/tests/cpu/transforms/DisplayTransform_tests.cpp +++ /dev/null @@ -1,643 +0,0 @@ -// SPDX-License-Identifier: BSD-3-Clause -// Copyright Contributors to the OpenColorIO Project. - - -#include "transforms/DisplayTransform.cpp" - -#include "ops/fixedfunction/FixedFunctionOpData.h" -#include "ops/gamma/GammaOpData.h" -#include "ops/log/LogOpData.h" -#include "ops/matrix/MatrixOpData.h" -#include "ops/range/RangeOpData.h" -#include "testutils/UnitTest.h" -#include "UnitTestUtils.h" - -namespace OCIO = OCIO_NAMESPACE; - - -OCIO_ADD_TEST(DisplayTransform, basic) -{ - const std::string empty; - auto dt = OCIO::DisplayTransform::Create(); - - OCIO_CHECK_EQUAL(dt->getDirection(), OCIO::TRANSFORM_DIR_FORWARD); - OCIO_CHECK_EQUAL(empty, dt->getInputColorSpaceName()); - OCIO_CHECK_ASSERT(!dt->getLinearCC()); - OCIO_CHECK_ASSERT(!dt->getColorTimingCC()); - OCIO_CHECK_ASSERT(!dt->getChannelView()); - OCIO_CHECK_EQUAL(empty, dt->getDisplay()); - OCIO_CHECK_EQUAL(empty, dt->getView()); - OCIO_CHECK_ASSERT(!dt->getDisplayCC()); - OCIO_CHECK_EQUAL(empty, dt->getLooksOverride()); - OCIO_CHECK_ASSERT(!dt->getLooksOverrideEnabled()); - - const std::string inputCS{ "inputCS" }; - dt->setInputColorSpaceName(inputCS.c_str()); - OCIO_CHECK_EQUAL(inputCS, dt->getInputColorSpaceName()); - - const std::string display{ "display" }; - dt->setDisplay(display.c_str()); - OCIO_CHECK_EQUAL(display, dt->getDisplay()); - - const std::string view{ "view" }; - dt->setView(view.c_str()); - OCIO_CHECK_EQUAL(view, dt->getView()); - - OCIO_CHECK_NO_THROW(dt->validate()); - - dt->setDirection(OCIO::TRANSFORM_DIR_UNKNOWN); - OCIO_CHECK_THROW_WHAT(dt->validate(), OCIO::Exception, "invalid direction"); - dt->setDirection(OCIO::TRANSFORM_DIR_INVERSE); - OCIO_CHECK_EQUAL(dt->getDirection(), OCIO::TRANSFORM_DIR_INVERSE); - - dt->setInputColorSpaceName(""); - OCIO_CHECK_THROW_WHAT(dt->validate(), OCIO::Exception, - "DisplayTransform: empty input color space name"); - dt->setInputColorSpaceName(inputCS.c_str()); - - dt->setDisplay(""); - OCIO_CHECK_THROW_WHAT(dt->validate(), OCIO::Exception, "DisplayTransform: empty display name"); - dt->setDisplay(display.c_str()); - - dt->setView(""); - OCIO_CHECK_THROW_WHAT(dt->validate(), OCIO::Exception, "DisplayTransform: empty view name"); - dt->setView(view.c_str()); - - OCIO_CHECK_NO_THROW(dt->validate()); - - OCIO::ConstTransformRcPtr linearCC = OCIO::MatrixTransform::Create(); - dt->setLinearCC(linearCC); - auto linearCCBack = dt->getLinearCC(); - OCIO_CHECK_ASSERT(OCIO_DYNAMIC_POINTER_CAST(linearCCBack)); - - OCIO::ConstTransformRcPtr timimgCC = OCIO::ExponentTransform::Create(); - dt->setColorTimingCC(timimgCC); - auto timingCCBack = dt->getColorTimingCC(); - OCIO_CHECK_ASSERT(OCIO_DYNAMIC_POINTER_CAST(timingCCBack)); - - OCIO::ConstTransformRcPtr cvTrans = OCIO::MatrixTransform::Create(); - dt->setChannelView(cvTrans); - auto cvTransBack = dt->getChannelView(); - OCIO_CHECK_ASSERT(OCIO_DYNAMIC_POINTER_CAST(cvTransBack)); - - OCIO::ConstTransformRcPtr displayCC = OCIO::RangeTransform::Create(); - dt->setDisplayCC(displayCC); - auto displayCCBack = dt->getDisplayCC(); - OCIO_CHECK_ASSERT(OCIO_DYNAMIC_POINTER_CAST(displayCCBack)); - - const std::string looksOveride{ "looks_override" }; - dt->setLooksOverride(looksOveride.c_str()); - OCIO_CHECK_EQUAL(looksOveride, dt->getLooksOverride()); - - dt->setLooksOverrideEnabled(true); - OCIO_CHECK_ASSERT(dt->getLooksOverrideEnabled()); -} - -OCIO_ADD_TEST(DisplayTransform, build_ops) -{ - // - // Validate BuildDisplayOps where the display/view is a simple color space - // (i.e., no ViewTransform). - // - - const std::string src{ "source" }; - const std::string dst{ "destination" }; - const std::string linearCS{ "linear_cs" }; - const std::string timingCS{ "color_timing_cs" }; - - OCIO::ConfigRcPtr config = OCIO::Config::CreateRaw()->createEditableCopy(); - auto csSource = OCIO::ColorSpace::Create(); - csSource->setName(src.c_str()); - auto mat = OCIO::MatrixTransform::Create(); - constexpr double offset[4] = { 0., 0.1, 0.2, 0. }; - mat->setOffset(offset); - csSource->setTransform(mat, OCIO::COLORSPACE_DIR_TO_REFERENCE); - config->addColorSpace(csSource); - - auto cs = OCIO::ColorSpace::Create(); - cs->setName(dst.c_str()); - auto ff = OCIO::FixedFunctionTransform::Create(); - ff->setStyle(OCIO::FIXED_FUNCTION_ACES_GLOW_03); - cs->setTransform(ff, OCIO::COLORSPACE_DIR_FROM_REFERENCE); - config->addColorSpace(cs); - - cs = OCIO::ColorSpace::Create(); - cs->setName(linearCS.c_str()); - ff = OCIO::FixedFunctionTransform::Create(); - ff->setStyle(OCIO::FIXED_FUNCTION_ACES_GLOW_10); - cs->setTransform(ff, OCIO::COLORSPACE_DIR_FROM_REFERENCE); - ff = OCIO::FixedFunctionTransform::Create(); - ff->setStyle(OCIO::FIXED_FUNCTION_ACES_RED_MOD_10); - cs->setTransform(ff, OCIO::COLORSPACE_DIR_TO_REFERENCE); - config->addColorSpace(cs); - config->setRole(OCIO::ROLE_SCENE_LINEAR, linearCS.c_str()); - - cs = OCIO::ColorSpace::Create(); - cs->setName(timingCS.c_str()); - ff = OCIO::FixedFunctionTransform::Create(); - ff->setStyle(OCIO::FIXED_FUNCTION_RGB_TO_HSV); - cs->setTransform(ff, OCIO::COLORSPACE_DIR_FROM_REFERENCE); - ff = OCIO::FixedFunctionTransform::Create(); - ff->setStyle(OCIO::FIXED_FUNCTION_ACES_DARK_TO_DIM_10); - cs->setTransform(ff, OCIO::COLORSPACE_DIR_TO_REFERENCE); - config->addColorSpace(cs); - config->setRole(OCIO::ROLE_COLOR_TIMING, timingCS.c_str()); - - const std::string display{ "display" }; - const std::string view{ "view" }; - OCIO_CHECK_NO_THROW(config->addDisplay(display.c_str(), view.c_str(), dst.c_str(), "")); - - OCIO_CHECK_NO_THROW(config->sanityCheck()); - - auto dt = OCIO::DisplayTransform::Create(); - dt->setInputColorSpaceName(src.c_str()); - - dt->setDisplay(display.c_str()); - dt->setView(view.c_str()); - - auto linearCC = OCIO::MatrixTransform::Create(); - constexpr double offsetLinearCC[4] = { 0.2, 0.3, 0.4, 0. }; - linearCC->setOffset(offsetLinearCC); - dt->setLinearCC(linearCC); - auto timimgCC = OCIO::ExponentTransform::Create(); - constexpr double valueTimingCC[4] = { 2.2, 2.3, 2.4, 1. }; - timimgCC->setValue(valueTimingCC); - dt->setColorTimingCC(timimgCC); - auto cvTrans = OCIO::MatrixTransform::Create(); - const std::string cv{ "channel view transform" }; - cvTrans->getFormatMetadata().setValue(cv.c_str()); - dt->setChannelView(cvTrans); - auto displayCC = OCIO::ExposureContrastTransform::Create(); - dt->setDisplayCC(displayCC); - - { - OCIO::OpRcPtrVec ops; - OCIO_CHECK_NO_THROW(OCIO::BuildDisplayOps(ops, *config, - config->getCurrentContext(), *dt, - OCIO::TRANSFORM_DIR_FORWARD)); - OCIO_CHECK_EQUAL(ops.size(), 16); - OCIO_CHECK_NO_THROW(ops.validate()); - - // 0-3. InputCS -> scene linear role: - // 0. GPU Allocation No-op. - // 1. Input to reference. - // 2. Scene linear role from reference. - // 3. GPU Allocation No-op. - // 4. LinearCC. - // 5-8. Scene linear -> color timing role: - // 5. GPU Allocation No-op. - // 6. Scene linear role to reference. - // 7. ColorTiming from reference. - // 8. GPU Allocation No-op. - // 9. ColorTimingCC. - // * No look. - // 10. ChannelView. - // 11-14. Color timing role -> display/view color space: - // 11. GPU Allocation No-op. - // 12. ColorTiming to reference. - // 13. DisplayCS from reference. - // 14. GPU Allocation No-op. - // 15. DisplayCC. - - // 0. GPU Allocation No-op. - auto op = OCIO_DYNAMIC_POINTER_CAST(ops[0]); - auto data = op->data(); - OCIO_REQUIRE_EQUAL(data->getType(), OCIO::OpData::NoOpType); - - // 1. Input to reference. - op = OCIO_DYNAMIC_POINTER_CAST(ops[1]); - data = op->data(); - OCIO_REQUIRE_EQUAL(data->getType(), OCIO::OpData::MatrixType); - auto matData = OCIO_DYNAMIC_POINTER_CAST(data); - OCIO_CHECK_EQUAL(offset[0], matData->getOffsetValue(0)); - OCIO_CHECK_EQUAL(offset[1], matData->getOffsetValue(1)); - OCIO_CHECK_EQUAL(offset[2], matData->getOffsetValue(2)); - OCIO_CHECK_EQUAL(offset[3], matData->getOffsetValue(3)); - - // 2. Scene linear role from reference. - op = OCIO_DYNAMIC_POINTER_CAST(ops[2]); - data = op->data(); - OCIO_REQUIRE_EQUAL(data->getType(), OCIO::OpData::FixedFunctionType); - auto ffData = OCIO_DYNAMIC_POINTER_CAST(data); - OCIO_CHECK_EQUAL(ffData->getStyle(), OCIO::FixedFunctionOpData::ACES_GLOW_10_FWD); - - // 3. GPU Allocation No-op. - op = OCIO_DYNAMIC_POINTER_CAST(ops[3]); - data = op->data(); - OCIO_REQUIRE_EQUAL(data->getType(), OCIO::OpData::NoOpType); - - // 4. LinearCC. - op = OCIO_DYNAMIC_POINTER_CAST(ops[4]); - data = op->data(); - OCIO_REQUIRE_EQUAL(data->getType(), OCIO::OpData::MatrixType); - matData = OCIO_DYNAMIC_POINTER_CAST(data); - OCIO_CHECK_EQUAL(offsetLinearCC[0], matData->getOffsetValue(0)); - OCIO_CHECK_EQUAL(offsetLinearCC[1], matData->getOffsetValue(1)); - OCIO_CHECK_EQUAL(offsetLinearCC[2], matData->getOffsetValue(2)); - OCIO_CHECK_EQUAL(offsetLinearCC[3], matData->getOffsetValue(3)); - - // 5. GPU Allocation No-op. - op = OCIO_DYNAMIC_POINTER_CAST(ops[5]); - data = op->data(); - OCIO_REQUIRE_EQUAL(data->getType(), OCIO::OpData::NoOpType); - - // 6. Scene linear role to reference. - op = OCIO_DYNAMIC_POINTER_CAST(ops[6]); - data = op->data(); - OCIO_REQUIRE_EQUAL(data->getType(), OCIO::OpData::FixedFunctionType); - ffData = OCIO_DYNAMIC_POINTER_CAST(data); - OCIO_CHECK_EQUAL(ffData->getStyle(), OCIO::FixedFunctionOpData::ACES_RED_MOD_10_FWD); - - // 7. ColorTiming from reference. - op = OCIO_DYNAMIC_POINTER_CAST(ops[7]); - data = op->data(); - OCIO_REQUIRE_EQUAL(data->getType(), OCIO::OpData::FixedFunctionType); - ffData = OCIO_DYNAMIC_POINTER_CAST(data); - OCIO_CHECK_EQUAL(ffData->getStyle(), OCIO::FixedFunctionOpData::RGB_TO_HSV); - - // 8. GPU Allocation No-op. - op = OCIO_DYNAMIC_POINTER_CAST(ops[8]); - data = op->data(); - OCIO_REQUIRE_EQUAL(data->getType(), OCIO::OpData::NoOpType); - - // 9. ColorTimingCC. - op = OCIO_DYNAMIC_POINTER_CAST(ops[9]); - data = op->data(); - OCIO_REQUIRE_EQUAL(data->getType(), OCIO::OpData::GammaType); - auto gammaData = OCIO_DYNAMIC_POINTER_CAST(data); - OCIO_CHECK_EQUAL(valueTimingCC[0], gammaData->getRedParams()[0]); - OCIO_CHECK_EQUAL(valueTimingCC[1], gammaData->getGreenParams()[0]); - OCIO_CHECK_EQUAL(valueTimingCC[2], gammaData->getBlueParams()[0]); - OCIO_CHECK_EQUAL(valueTimingCC[3], gammaData->getAlphaParams()[0]); - - // 10. ChannelView. - op = OCIO_DYNAMIC_POINTER_CAST(ops[10]); - data = op->data(); - OCIO_REQUIRE_EQUAL(data->getType(), OCIO::OpData::MatrixType); - OCIO_CHECK_EQUAL(cv, data->getFormatMetadata().getValue()); - - // 11. GPU Allocation No-op. - op = OCIO_DYNAMIC_POINTER_CAST(ops[11]); - data = op->data(); - OCIO_REQUIRE_EQUAL(data->getType(), OCIO::OpData::NoOpType); - - // 12. ColorTiming to reference. - op = OCIO_DYNAMIC_POINTER_CAST(ops[12]); - data = op->data(); - OCIO_REQUIRE_EQUAL(data->getType(), OCIO::OpData::FixedFunctionType); - ffData = OCIO_DYNAMIC_POINTER_CAST(data); - OCIO_CHECK_EQUAL(ffData->getStyle(), OCIO::FixedFunctionOpData::ACES_DARK_TO_DIM_10_FWD); - - // 13. DisplayCS from reference. - op = OCIO_DYNAMIC_POINTER_CAST(ops[13]); - data = op->data(); - OCIO_REQUIRE_EQUAL(data->getType(), OCIO::OpData::FixedFunctionType); - ffData = OCIO_DYNAMIC_POINTER_CAST(data); - OCIO_CHECK_EQUAL(ffData->getStyle(), OCIO::FixedFunctionOpData::ACES_GLOW_03_FWD); - - // 14. GPU Allocation No-op. - op = OCIO_DYNAMIC_POINTER_CAST(ops[14]); - data = op->data(); - OCIO_REQUIRE_EQUAL(data->getType(), OCIO::OpData::NoOpType); - - // 15. DisplayCC. - op = OCIO_DYNAMIC_POINTER_CAST(ops[15]); - data = op->data(); - OCIO_REQUIRE_EQUAL(data->getType(), OCIO::OpData::ExposureContrastType); - } - - // - // Using a scene-referred ViewTransform. - // - - const std::string dsp{ "display" }; - cs = OCIO::ColorSpace::Create(OCIO::REFERENCE_SPACE_DISPLAY); - cs->setName(dsp.c_str()); - auto ec = OCIO::ExposureContrastTransform::Create(); - cs->setTransform(ec, OCIO::COLORSPACE_DIR_FROM_REFERENCE); - config->addColorSpace(cs); - - const std::string scenevt{ "scene_vt" }; - auto vt = OCIO::ViewTransform::Create(OCIO::REFERENCE_SPACE_SCENE); - vt->setName(scenevt.c_str()); - auto log = OCIO::LogTransform::Create(); - log->setBase(4.2); - vt->setTransform(log, OCIO::VIEWTRANSFORM_DIR_FROM_REFERENCE); - config->addViewTransform(vt); - - const std::string viewt{ "viewt" }; - OCIO_CHECK_NO_THROW(config->addDisplay(display.c_str(), viewt.c_str(), scenevt.c_str(), dsp.c_str(), "")); - OCIO_CHECK_NO_THROW(config->sanityCheck()); - - dt->setView(viewt.c_str()); - - { - OCIO::OpRcPtrVec ops; - OCIO_CHECK_NO_THROW(OCIO::BuildDisplayOps(ops, *config, - config->getCurrentContext(), *dt, - OCIO::TRANSFORM_DIR_FORWARD)); - - // Getting an additional op for the reference space change. - OCIO_CHECK_EQUAL(ops.size(), 17); - OCIO_CHECK_NO_THROW(ops.validate()); - - // Same as previous up to colorTiming to reference. - // 0. GPU Allocation No-op. - // 1. Input to reference. - // 2. Scene linear role from reference. - // 3. GPU Allocation No-op. - // 4. LinearCC. - // 5. GPU Allocation No-op. - // 6. Scene linear role to reference. - // 7. ColorTiming from reference. - // 8. GPU Allocation No-op. - // 9. ColorTimingCC. - // 10. ChannelView. - // 11. GPU Allocation No-op. - // 12. ColorTiming to reference. - - // 13. Changing from scene-referred space to display-referred space done - // with the specified view transform. - auto op = OCIO_DYNAMIC_POINTER_CAST(ops[13]); - auto data = op->data(); - OCIO_REQUIRE_EQUAL(data->getType(), OCIO::OpData::LogType); - auto logData = OCIO_DYNAMIC_POINTER_CAST(data); - OCIO_CHECK_EQUAL(4.2, logData->getBase()); - - // 14. DisplayCS from reference. - op = OCIO_DYNAMIC_POINTER_CAST(ops[14]); - data = op->data(); - OCIO_REQUIRE_EQUAL(data->getType(), OCIO::OpData::ExposureContrastType); - - // 15. GPU Allocation No-op. - op = OCIO_DYNAMIC_POINTER_CAST(ops[15]); - data = op->data(); - OCIO_REQUIRE_EQUAL(data->getType(), OCIO::OpData::NoOpType); - - // 16. DisplayCC. - op = OCIO_DYNAMIC_POINTER_CAST(ops[16]); - data = op->data(); - OCIO_REQUIRE_EQUAL(data->getType(), OCIO::OpData::ExposureContrastType); - - } - - // - // Adding a display-referred ViewTransform. - // - - const std::string displayvt{ "display_vt" }; - vt = OCIO::ViewTransform::Create(OCIO::REFERENCE_SPACE_DISPLAY); - vt->setName(displayvt.c_str()); - log = OCIO::LogTransform::Create(); - log->setBase(2.1); - vt->setTransform(log, OCIO::VIEWTRANSFORM_DIR_FROM_REFERENCE); - config->addViewTransform(vt); - - // Replace view display. - OCIO_CHECK_NO_THROW(config->addDisplay(display.c_str(), viewt.c_str(), displayvt.c_str(), dsp.c_str(), "")); - OCIO_CHECK_NO_THROW(config->sanityCheck()); - - { - OCIO::OpRcPtrVec ops; - OCIO_CHECK_NO_THROW(OCIO::BuildDisplayOps(ops, *config, - config->getCurrentContext(), *dt, - OCIO::TRANSFORM_DIR_FORWARD)); - - // Getting an additional op for the display to display view transform. - OCIO_CHECK_EQUAL(ops.size(), 18); - OCIO_CHECK_NO_THROW(ops.validate()); - - // Same as previous up to scene-referred to display referred. - // 0. GPU Allocation No-op. - // 1. Input to reference. - // 2. Scene linear role from reference. - // 3. GPU Allocation No-op. - // 4. LinearCC. - // 5. GPU Allocation No-op. - // 6. Scene linear role to reference. - // 7. ColorTiming from reference. - // 8. GPU Allocation No-op. - // 9. ColorTimingCC. - // 10. ChannelView. - // 11. GPU Allocation No-op. - // 12. ColorTiming to reference. - // 13. Changing from scene-referred space to display-referred space using the - // default view transform. - - // 14. Display-referred reference to display-referred reference using the specified view transform. - auto op = OCIO_DYNAMIC_POINTER_CAST(ops[14]); - auto data = op->data(); - OCIO_REQUIRE_EQUAL(data->getType(), OCIO::OpData::LogType); - auto logData = OCIO_DYNAMIC_POINTER_CAST(data); - OCIO_CHECK_EQUAL(2.1, logData->getBase()); - - // 15. DisplayCS from reference. - op = OCIO_DYNAMIC_POINTER_CAST(ops[15]); - data = op->data(); - OCIO_REQUIRE_EQUAL(data->getType(), OCIO::OpData::ExposureContrastType); - - // 16. GPU Allocation No-op. - op = OCIO_DYNAMIC_POINTER_CAST(ops[16]); - data = op->data(); - OCIO_REQUIRE_EQUAL(data->getType(), OCIO::OpData::NoOpType); - - // 17. DisplayCC. - op = OCIO_DYNAMIC_POINTER_CAST(ops[17]); - data = op->data(); - OCIO_REQUIRE_EQUAL(data->getType(), OCIO::OpData::ExposureContrastType); - } - - csSource->setIsData(true); - config->addColorSpace(csSource); - OCIO_CHECK_NO_THROW(config->sanityCheck()); - - { - OCIO::OpRcPtrVec ops; - OCIO_CHECK_NO_THROW(OCIO::BuildDisplayOps(ops, *config, - config->getCurrentContext(), *dt, - OCIO::TRANSFORM_DIR_FORWARD)); - - // Color space conversion is skipped. - OCIO_CHECK_EQUAL(ops.size(), 4); - OCIO_CHECK_NO_THROW(ops.validate()); - - // With isData true, the view/display transform is not applied. The CC and channelView - // are applied, but without converting to their usual process spaces. - // 0. LinearCC. - // 1. ColorTimingCC. - // 2. ChannelView. - // 3. DisplayCC. - auto op = OCIO_DYNAMIC_POINTER_CAST(ops[0]); - auto data = op->data(); - OCIO_REQUIRE_EQUAL(data->getType(), OCIO::OpData::MatrixType); - - op = OCIO_DYNAMIC_POINTER_CAST(ops[1]); - data = op->data(); - OCIO_REQUIRE_EQUAL(data->getType(), OCIO::OpData::GammaType); - - op = OCIO_DYNAMIC_POINTER_CAST(ops[2]); - data = op->data(); - OCIO_REQUIRE_EQUAL(data->getType(), OCIO::OpData::MatrixType); - - op = OCIO_DYNAMIC_POINTER_CAST(ops[3]); - data = op->data(); - OCIO_REQUIRE_EQUAL(data->getType(), OCIO::OpData::ExposureContrastType); - } -} - -OCIO_ADD_TEST(DisplayTransform, build_ops_with_looks) -{ - // - // Validate BuildDisplayOps using a display-referred ViewTransform and a Look with a - // display-referred ProcessSpace. - // - - const std::string in{ "displayCSIn" }; - const std::string out{ "displayCSOut" }; - - OCIO::ConfigRcPtr config = OCIO::Config::CreateRaw()->createEditableCopy(); - auto csIn = OCIO::ColorSpace::Create(OCIO::REFERENCE_SPACE_DISPLAY); - csIn->setName(in.c_str()); - auto mat = OCIO::MatrixTransform::Create(); - constexpr double offset[4] = { 0., 0.1, 0.2, 0. }; - mat->setOffset(offset); - csIn->setTransform(mat, OCIO::COLORSPACE_DIR_TO_REFERENCE); - config->addColorSpace(csIn); - - auto csOut = OCIO::ColorSpace::Create(OCIO::REFERENCE_SPACE_DISPLAY); - csOut->setName(out.c_str()); - auto ff = OCIO::FixedFunctionTransform::Create(); - ff->setStyle(OCIO::FIXED_FUNCTION_ACES_GLOW_03); - csOut->setTransform(ff, OCIO::COLORSPACE_DIR_FROM_REFERENCE); - config->addColorSpace(csOut); - - const std::string display{ "display" }; - const std::string view{ "view" }; - const std::string look{ "look" }; - const std::string displayCSProcess{ "displayCSProcess" }; - - auto csProcess = OCIO::ColorSpace::Create(OCIO::REFERENCE_SPACE_DISPLAY); - csProcess->setName(displayCSProcess.c_str()); - auto expProcess = OCIO::ExponentTransform::Create(); - constexpr double valueProcess[4] = { 2.2, 2.3, 2.4, 1. }; - expProcess->setValue(valueProcess); - csProcess->setTransform(expProcess, OCIO::COLORSPACE_DIR_FROM_REFERENCE); - - config->addColorSpace(csProcess); - - // Create look. - auto lk = OCIO::Look::Create(); - lk->setName(look.c_str()); - lk->setProcessSpace(displayCSProcess.c_str()); - auto cdl = OCIO::CDLTransform::Create(); - cdl->setSat(1.5); - lk->setTransform(cdl); - config->addLook(lk); - - auto defaultVT = OCIO::ViewTransform::Create(OCIO::REFERENCE_SPACE_SCENE); - defaultVT->setName("default_vt"); - mat = OCIO::MatrixTransform::Create(); - defaultVT->setTransform(mat, OCIO::VIEWTRANSFORM_DIR_FROM_REFERENCE); - config->addViewTransform(defaultVT); - - // Add display-referred view transform. - const std::string displayvt{ "display_vt" }; - auto vt = OCIO::ViewTransform::Create(OCIO::REFERENCE_SPACE_DISPLAY); - vt->setName(displayvt.c_str()); - auto log = OCIO::LogTransform::Create(); - log->setBase(2.1); - vt->setTransform(log, OCIO::VIEWTRANSFORM_DIR_FROM_REFERENCE); - config->addViewTransform(vt); - - // Add view display. - OCIO_CHECK_NO_THROW(config->addDisplay(display.c_str(), view.c_str(), displayvt.c_str(), - out.c_str(), look.c_str())); - - auto dt = OCIO::DisplayTransform::Create(); - dt->setInputColorSpaceName(in.c_str()); - dt->setDisplay(display.c_str()); - dt->setView(view.c_str()); - - OCIO_CHECK_NO_THROW(config->sanityCheck()); - - OCIO::OpRcPtrVec ops; - OCIO_CHECK_NO_THROW(OCIO::BuildDisplayOps(ops, *config, - config->getCurrentContext(), *dt, - OCIO::TRANSFORM_DIR_FORWARD)); - OCIO_CHECK_EQUAL(ops.size(), 11); - OCIO_CHECK_NO_THROW(ops.validate()); - - // 0-3. DisplayCSIn->displayCSProcess: - // 0. GPU Allocation No-op. - // 1. In to reference. - // 2. Look process space from reference. - // 3. GPU Allocation No-op. - // 4-5. Look-noop + look transform. - // 6-7. displayCSProcess->display reference: - // 6. GPU Allocation No-op. - // 7. DisplayCSProcess to display reference. - // 8. Display-referred VT. - // 9-10. Reference->DisplayCSOutput: - // 9. DisplayCSOutput from display reference. - // 10. GPU Allocation No-op. - - // 0. GPU Allocation No-op. - auto op = OCIO_DYNAMIC_POINTER_CAST(ops[0]); - auto data = op->data(); - OCIO_REQUIRE_EQUAL(data->getType(), OCIO::OpData::NoOpType); - - // 1. In to reference. - op = OCIO_DYNAMIC_POINTER_CAST(ops[1]); - data = op->data(); - OCIO_REQUIRE_EQUAL(data->getType(), OCIO::OpData::MatrixType); - auto matData = OCIO_DYNAMIC_POINTER_CAST(data); - OCIO_CHECK_EQUAL(offset[0], matData->getOffsetValue(0)); - OCIO_CHECK_EQUAL(offset[1], matData->getOffsetValue(1)); - OCIO_CHECK_EQUAL(offset[2], matData->getOffsetValue(2)); - OCIO_CHECK_EQUAL(offset[3], matData->getOffsetValue(3)); - - // 2. Look process space from reference. - op = OCIO_DYNAMIC_POINTER_CAST(ops[2]); - data = op->data(); - OCIO_CHECK_EQUAL(data->getType(), OCIO::OpData::GammaType); - - // 3. GPU Allocation No-op. - op = OCIO_DYNAMIC_POINTER_CAST(ops[3]); - data = op->data(); - OCIO_CHECK_EQUAL(data->getType(), OCIO::OpData::NoOpType); - - // 4. Look No-op. - op = OCIO_DYNAMIC_POINTER_CAST(ops[4]); - data = op->data(); - OCIO_CHECK_EQUAL(data->getType(), OCIO::OpData::NoOpType); - - // 5. Look transform. - op = OCIO_DYNAMIC_POINTER_CAST(ops[5]); - data = op->data(); - OCIO_CHECK_EQUAL(data->getType(), OCIO::OpData::CDLType); - - // 6. GPU Allocation No-op. - op = OCIO_DYNAMIC_POINTER_CAST(ops[6]); - data = op->data(); - OCIO_CHECK_EQUAL(data->getType(), OCIO::OpData::NoOpType); - - // 7. DisplayCSProcess to display reference. - op = OCIO_DYNAMIC_POINTER_CAST(ops[7]); - data = op->data(); - OCIO_CHECK_EQUAL(data->getType(), OCIO::OpData::GammaType); - - // 8. Display-referred VT. - op = OCIO_DYNAMIC_POINTER_CAST(ops[8]); - data = op->data(); - OCIO_CHECK_EQUAL(data->getType(), OCIO::OpData::LogType); - - // 9. DisplayCSOutput from display reference. - op = OCIO_DYNAMIC_POINTER_CAST(ops[9]); - data = op->data(); - OCIO_CHECK_EQUAL(data->getType(), OCIO::OpData::FixedFunctionType); - - // 10. GPU Allocation No-op. - op = OCIO_DYNAMIC_POINTER_CAST(ops[10]); - data = op->data(); - OCIO_CHECK_EQUAL(data->getType(), OCIO::OpData::NoOpType); -} diff --git a/tests/cpu/transforms/DisplayViewTransform_tests.cpp b/tests/cpu/transforms/DisplayViewTransform_tests.cpp new file mode 100644 index 0000000000..ccb66cd61f --- /dev/null +++ b/tests/cpu/transforms/DisplayViewTransform_tests.cpp @@ -0,0 +1,1020 @@ +// SPDX-License-Identifier: BSD-3-Clause +// Copyright Contributors to the OpenColorIO Project. + + +#include "transforms/DisplayViewTransform.cpp" + +#include "ops/cdl/CDLOpData.h" +#include "ops/fixedfunction/FixedFunctionOpData.h" +#include "ops/gamma/GammaOpData.h" +#include "ops/log/LogOpData.h" +#include "ops/matrix/MatrixOpData.h" +#include "ops/range/RangeOpData.h" +#include "testutils/UnitTest.h" +#include "UnitTestUtils.h" + +namespace OCIO = OCIO_NAMESPACE; + + +OCIO_ADD_TEST(DisplayViewTransform, basic) +{ + const std::string empty; + auto dt = OCIO::DisplayViewTransform::Create(); + + OCIO_CHECK_EQUAL(dt->getDirection(), OCIO::TRANSFORM_DIR_FORWARD); + OCIO_CHECK_EQUAL(empty, dt->getSrc()); + OCIO_CHECK_EQUAL(empty, dt->getDisplay()); + OCIO_CHECK_EQUAL(empty, dt->getView()); + OCIO_CHECK_ASSERT(!dt->getLooksBypass()); + OCIO_CHECK_ASSERT(dt->getDataBypass()); + dt->setDataBypass(false); + OCIO_CHECK_ASSERT(!dt->getDataBypass()); + dt->setDataBypass(true); + OCIO_CHECK_ASSERT(dt->getDataBypass()); + + const std::string inputCS{ "inputCS" }; + dt->setSrc(inputCS.c_str()); + OCIO_CHECK_EQUAL(inputCS, dt->getSrc()); + + const std::string display{ "display" }; + dt->setDisplay(display.c_str()); + OCIO_CHECK_EQUAL(display, dt->getDisplay()); + + const std::string view{ "view" }; + dt->setView(view.c_str()); + OCIO_CHECK_EQUAL(view, dt->getView()); + + OCIO_CHECK_NO_THROW(dt->validate()); + + dt->setDirection(OCIO::TRANSFORM_DIR_UNKNOWN); + OCIO_CHECK_THROW_WHAT(dt->validate(), OCIO::Exception, "invalid direction"); + dt->setDirection(OCIO::TRANSFORM_DIR_INVERSE); + OCIO_CHECK_EQUAL(dt->getDirection(), OCIO::TRANSFORM_DIR_INVERSE); + + dt->setSrc(""); + OCIO_CHECK_THROW_WHAT(dt->validate(), OCIO::Exception, + "DisplayViewTransform: empty source color space name"); + dt->setSrc(inputCS.c_str()); + + dt->setDisplay(""); + OCIO_CHECK_THROW_WHAT(dt->validate(), OCIO::Exception, "DisplayViewTransform: empty display name"); + dt->setDisplay(display.c_str()); + + dt->setView(""); + OCIO_CHECK_THROW_WHAT(dt->validate(), OCIO::Exception, "DisplayViewTransform: empty view name"); + dt->setView(view.c_str()); + + OCIO_CHECK_NO_THROW(dt->validate()); + + dt->setLooksBypass(true); + OCIO_CHECK_ASSERT(dt->getLooksBypass()); + + dt->setDataBypass(false); + + // Verify that copy has same values. + auto t = dt->createEditableCopy(); + dt = OCIO_DYNAMIC_POINTER_CAST(t); + OCIO_CHECK_EQUAL(inputCS, dt->getSrc()); + OCIO_CHECK_EQUAL(display, dt->getDisplay()); + OCIO_CHECK_EQUAL(view, dt->getView()); + OCIO_CHECK_EQUAL(dt->getDirection(), OCIO::TRANSFORM_DIR_INVERSE); + OCIO_CHECK_ASSERT(dt->getLooksBypass()); + OCIO_CHECK_ASSERT(!dt->getDataBypass()); +} + +OCIO_ADD_TEST(DisplayViewTransform, build_ops) +{ + // + // Validate BuildDisplayOps where the display/view is a simple color space + // (i.e., no ViewTransform). + // + + const std::string src{ "source" }; + const std::string dst{ "destination" }; + + OCIO::ConfigRcPtr config = OCIO::Config::CreateRaw()->createEditableCopy(); + auto csSource = OCIO::ColorSpace::Create(); + csSource->setName(src.c_str()); + auto mat = OCIO::MatrixTransform::Create(); + constexpr double offset[4] = { 0., 0.1, 0.2, 0. }; + mat->setOffset(offset); + csSource->setTransform(mat, OCIO::COLORSPACE_DIR_TO_REFERENCE); + config->addColorSpace(csSource); + + auto cs = OCIO::ColorSpace::Create(); + cs->setName(dst.c_str()); + auto ff = OCIO::FixedFunctionTransform::Create(); + ff->setStyle(OCIO::FIXED_FUNCTION_ACES_GLOW_03); + cs->setTransform(ff, OCIO::COLORSPACE_DIR_FROM_REFERENCE); + config->addColorSpace(cs); + + const std::string display{ "display" }; + const std::string view{ "view" }; + OCIO_CHECK_NO_THROW(config->addDisplayView(display.c_str(), view.c_str(), dst.c_str(), "")); + + OCIO_CHECK_NO_THROW(config->sanityCheck()); + + auto dt = OCIO::DisplayViewTransform::Create(); + dt->setSrc(src.c_str()); + + dt->setDisplay(display.c_str()); + dt->setView(view.c_str()); + + { + OCIO::OpRcPtrVec ops; + OCIO_CHECK_NO_THROW(OCIO::BuildDisplayOps(ops, *config, + config->getCurrentContext(), *dt, + OCIO::TRANSFORM_DIR_FORWARD)); + OCIO_REQUIRE_EQUAL(ops.size(), 4); + OCIO_CHECK_NO_THROW(ops.validate()); + + // No look. + // Input -> destination color space: + + // 0. GPU Allocation No-op. + auto op = OCIO_DYNAMIC_POINTER_CAST(ops[0]); + auto data = op->data(); + OCIO_REQUIRE_EQUAL(data->getType(), OCIO::OpData::NoOpType); + + // 1. Input color space (source) to reference. + op = OCIO_DYNAMIC_POINTER_CAST(ops[1]); + data = op->data(); + OCIO_REQUIRE_EQUAL(data->getType(), OCIO::OpData::MatrixType); + auto matData = OCIO_DYNAMIC_POINTER_CAST(data); + OCIO_CHECK_EQUAL(offset[0], matData->getOffsetValue(0)); + OCIO_CHECK_EQUAL(offset[1], matData->getOffsetValue(1)); + OCIO_CHECK_EQUAL(offset[2], matData->getOffsetValue(2)); + OCIO_CHECK_EQUAL(offset[3], matData->getOffsetValue(3)); + + // 2. Display color space (destination) from reference. + op = OCIO_DYNAMIC_POINTER_CAST(ops[2]); + data = op->data(); + OCIO_REQUIRE_EQUAL(data->getType(), OCIO::OpData::FixedFunctionType); + auto ffData = OCIO_DYNAMIC_POINTER_CAST(data); + OCIO_CHECK_EQUAL(ffData->getStyle(), OCIO::FixedFunctionOpData::ACES_GLOW_03_FWD); + + // 3. GPU Allocation No-op. + op = OCIO_DYNAMIC_POINTER_CAST(ops[3]); + data = op->data(); + OCIO_REQUIRE_EQUAL(data->getType(), OCIO::OpData::NoOpType); + } + + // + // Using a scene-referred ViewTransform. + // + + // Create a new display color space and use the same name as the display. + cs = OCIO::ColorSpace::Create(OCIO::REFERENCE_SPACE_DISPLAY); + cs->setName(display.c_str()); + auto ec = OCIO::ExposureContrastTransform::Create(); + cs->setTransform(ec, OCIO::COLORSPACE_DIR_FROM_REFERENCE); + config->addColorSpace(cs); + + auto vt = OCIO::ViewTransform::Create(OCIO::REFERENCE_SPACE_SCENE); + vt->setName("default_vt"); + auto cdl = OCIO::CDLTransform::Create(); + cdl->setSat(1.2); + vt->setTransform(cdl, OCIO::VIEWTRANSFORM_DIR_FROM_REFERENCE); + config->addViewTransform(vt); + + const std::string scenevt{ "scene_vt" }; + vt = OCIO::ViewTransform::Create(OCIO::REFERENCE_SPACE_SCENE); + vt->setName(scenevt.c_str()); + auto log = OCIO::LogTransform::Create(); + log->setBase(4.2); + vt->setTransform(log, OCIO::VIEWTRANSFORM_DIR_FROM_REFERENCE); + config->addViewTransform(vt); + + const std::string viewt{ "viewt" }; + // Explicitly use the display color space named "display". + OCIO_CHECK_NO_THROW(config->addDisplayView(display.c_str(), viewt.c_str(), scenevt.c_str(), + display.c_str(), "", "", "")); + OCIO_CHECK_NO_THROW(config->sanityCheck()); + + dt->setView(viewt.c_str()); + + { + OCIO::OpRcPtrVec ops; + OCIO_CHECK_NO_THROW(OCIO::BuildDisplayOps(ops, *config, + config->getCurrentContext(), *dt, + OCIO::TRANSFORM_DIR_FORWARD)); + + // Getting an additional op for the view transform. + OCIO_CHECK_EQUAL(ops.size(), 5); + OCIO_CHECK_NO_THROW(ops.validate()); + + // 0. GPU Allocation No-op. + auto op = OCIO_DYNAMIC_POINTER_CAST(ops[0]); + auto data = op->data(); + OCIO_REQUIRE_EQUAL(data->getType(), OCIO::OpData::NoOpType); + + // 1. Input to reference. + op = OCIO_DYNAMIC_POINTER_CAST(ops[1]); + data = op->data(); + OCIO_REQUIRE_EQUAL(data->getType(), OCIO::OpData::MatrixType); + auto matData = OCIO_DYNAMIC_POINTER_CAST(data); + OCIO_CHECK_EQUAL(offset[0], matData->getOffsetValue(0)); + OCIO_CHECK_EQUAL(offset[1], matData->getOffsetValue(1)); + OCIO_CHECK_EQUAL(offset[2], matData->getOffsetValue(2)); + OCIO_CHECK_EQUAL(offset[3], matData->getOffsetValue(3)); + + // 2. View Transform (converts scene-referred to display-referred reference space). + op = OCIO_DYNAMIC_POINTER_CAST(ops[2]); + data = op->data(); + OCIO_REQUIRE_EQUAL(data->getType(), OCIO::OpData::LogType); + auto logData = OCIO_DYNAMIC_POINTER_CAST(data); + OCIO_CHECK_EQUAL(4.2, logData->getBase()); + + // 3. DisplayCS from reference. + op = OCIO_DYNAMIC_POINTER_CAST(ops[3]); + data = op->data(); + OCIO_REQUIRE_EQUAL(data->getType(), OCIO::OpData::ExposureContrastType); + + // 4. GPU Allocation No-op. + op = OCIO_DYNAMIC_POINTER_CAST(ops[4]); + data = op->data(); + OCIO_REQUIRE_EQUAL(data->getType(), OCIO::OpData::NoOpType); + } + + // + // Adding a display-referred ViewTransform. + // + + const std::string displayvt{ "display_vt" }; + vt = OCIO::ViewTransform::Create(OCIO::REFERENCE_SPACE_DISPLAY); + vt->setName(displayvt.c_str()); + log = OCIO::LogTransform::Create(); + log->setBase(2.1); + vt->setTransform(log, OCIO::VIEWTRANSFORM_DIR_FROM_REFERENCE); + config->addViewTransform(vt); + + // Replace view display. + OCIO_CHECK_NO_THROW(config->addDisplayView(display.c_str(), viewt.c_str(), displayvt.c_str(), + display.c_str(), "", "", "")); + OCIO_CHECK_NO_THROW(config->sanityCheck()); + + { + OCIO::OpRcPtrVec ops; + OCIO_CHECK_NO_THROW(OCIO::BuildDisplayOps(ops, *config, + config->getCurrentContext(), *dt, + OCIO::TRANSFORM_DIR_FORWARD)); + + // Getting an additional op for the reference space change. + OCIO_CHECK_EQUAL(ops.size(), 6); + OCIO_CHECK_NO_THROW(ops.validate()); + + // 0. GPU Allocation No-op. + auto op = OCIO_DYNAMIC_POINTER_CAST(ops[0]); + auto data = op->data(); + OCIO_REQUIRE_EQUAL(data->getType(), OCIO::OpData::NoOpType); + + // 1. Input to reference. + op = OCIO_DYNAMIC_POINTER_CAST(ops[1]); + data = op->data(); + OCIO_REQUIRE_EQUAL(data->getType(), OCIO::OpData::MatrixType); + + // 2. Convert from the scene-referred reference space to the display-referred reference + // space (using the default view transform). + op = OCIO_DYNAMIC_POINTER_CAST(ops[2]); + data = op->data(); + OCIO_REQUIRE_EQUAL(data->getType(), OCIO::OpData::CDLType); + + // 3. The view's View Transform converts from the display-referred reference space to the + // same display-referred reference space. + op = OCIO_DYNAMIC_POINTER_CAST(ops[3]); + data = op->data(); + OCIO_REQUIRE_EQUAL(data->getType(), OCIO::OpData::LogType); + auto logData = OCIO_DYNAMIC_POINTER_CAST(data); + OCIO_CHECK_EQUAL(2.1, logData->getBase()); + + // 4. DisplayCS from reference. + op = OCIO_DYNAMIC_POINTER_CAST(ops[4]); + data = op->data(); + OCIO_REQUIRE_EQUAL(data->getType(), OCIO::OpData::ExposureContrastType); + + // 5. GPU Allocation No-op. + op = OCIO_DYNAMIC_POINTER_CAST(ops[5]); + data = op->data(); + OCIO_REQUIRE_EQUAL(data->getType(), OCIO::OpData::NoOpType); + } + + // Redo the same test using a shared view that uses USE_DISPLAY_NAME. The results should be + // exactly the same + + const std::string sharedView{ "shared_view" }; + OCIO_CHECK_NO_THROW(config->addSharedView(sharedView.c_str(), displayvt.c_str(), + OCIO::OCIO_VIEW_USE_DISPLAY_NAME, "", "", "")); + OCIO_CHECK_NO_THROW(config->addDisplaySharedView(display.c_str(), sharedView.c_str())); + + // This is valid because shared view refers to a view transform, is used in "display" and + // there is a color space named "display". + OCIO_CHECK_NO_THROW(config->sanityCheck()); + dt->setView(sharedView.c_str()); + + { + // Same as previous. + OCIO::OpRcPtrVec ops; + OCIO_CHECK_NO_THROW(OCIO::BuildDisplayOps(ops, *config, + config->getCurrentContext(), *dt, + OCIO::TRANSFORM_DIR_FORWARD)); + + OCIO_CHECK_NO_THROW(ops.validate()); + OCIO_REQUIRE_EQUAL(ops.size(), 6); + + // 0. GPU Allocation No-op. + auto op = OCIO_DYNAMIC_POINTER_CAST(ops[0]); + auto data = op->data(); + OCIO_REQUIRE_EQUAL(data->getType(), OCIO::OpData::NoOpType); + + // 1. Input to reference. + op = OCIO_DYNAMIC_POINTER_CAST(ops[1]); + data = op->data(); + OCIO_REQUIRE_EQUAL(data->getType(), OCIO::OpData::MatrixType); + auto matData = OCIO_DYNAMIC_POINTER_CAST(data); + OCIO_CHECK_EQUAL(offset[0], matData->getOffsetValue(0)); + OCIO_CHECK_EQUAL(offset[1], matData->getOffsetValue(1)); + OCIO_CHECK_EQUAL(offset[2], matData->getOffsetValue(2)); + OCIO_CHECK_EQUAL(offset[3], matData->getOffsetValue(3)); + + // 2. Changing from scene-referred space to display-referred space done + // using the default scene view transform. + op = OCIO_DYNAMIC_POINTER_CAST(ops[2]); + data = op->data(); + OCIO_REQUIRE_EQUAL(data->getType(), OCIO::OpData::CDLType); + + // 3. Display-referred reference to display-referred reference using the specified view + // transform. + op = OCIO_DYNAMIC_POINTER_CAST(ops[3]); + data = op->data(); + OCIO_REQUIRE_EQUAL(data->getType(), OCIO::OpData::LogType); + auto logData = OCIO_DYNAMIC_POINTER_CAST(data); + OCIO_CHECK_EQUAL(2.1, logData->getBase()); + + // 4. DisplayCS from reference. + op = OCIO_DYNAMIC_POINTER_CAST(ops[4]); + data = op->data(); + OCIO_REQUIRE_EQUAL(data->getType(), OCIO::OpData::ExposureContrastType); + + // 5. GPU Allocation No-op. + op = OCIO_DYNAMIC_POINTER_CAST(ops[5]); + data = op->data(); + OCIO_REQUIRE_EQUAL(data->getType(), OCIO::OpData::NoOpType); + } + + // Repeat with data color space. + csSource->setIsData(true); + config->addColorSpace(csSource); + OCIO_CHECK_NO_THROW(config->sanityCheck()); + + { + OCIO::OpRcPtrVec ops; + OCIO_CHECK_NO_THROW(OCIO::BuildDisplayOps(ops, *config, + config->getCurrentContext(), *dt, + OCIO::TRANSFORM_DIR_FORWARD)); + + // Data color space conversion is skipped. + OCIO_CHECK_EQUAL(ops.size(), 0); + } + + // Process data color space. + dt->setDataBypass(false); + + { + // Getting same results as before. + OCIO::OpRcPtrVec ops; + OCIO_CHECK_NO_THROW(OCIO::BuildDisplayOps(ops, *config, + config->getCurrentContext(), *dt, + OCIO::TRANSFORM_DIR_FORWARD)); + + // Data color space conversion is not skipped. + OCIO_CHECK_EQUAL(ops.size(), 6); + } +} + +namespace +{ +void ValidateTransform(OCIO::ConstOpRcPtr & op, const std::string name, + OCIO::TransformDirection dir, unsigned line) +{ + OCIO_REQUIRE_EQUAL_FROM(op->data()->getFormatMetadata().getNumAttributes(), 1, line); + OCIO_CHECK_EQUAL_FROM(name, op->data()->getFormatMetadata().getAttributeValue(0), line); + + auto cdl = OCIO_DYNAMIC_POINTER_CAST(op->data()); + OCIO_REQUIRE_ASSERT_FROM(cdl, line); + OCIO_CHECK_EQUAL_FROM(dir, cdl->getDirection(), line); +} +} + +OCIO_ADD_TEST(DisplayViewTransform, build_ops_with_looks) +{ + // + // Validate BuildDisplayOps using a display-referred ViewTransform and a look with a + // display-referred ProcessSpace. + // + + constexpr char CONFIG[]{ R"( +ocio_profile_version: 2 + +roles: + default: raw + +displays: + sRGB: + - ! {name: Raw, colorspace: raw} + display: + - ! {name: view, view_transform: display_vt, display_colorspace: displayCSOut, looks: look} + - ! {name: viewNoVT, colorspace: displayCSOut, looks: look} + +looks: + - ! + name: look + process_space: displayCSProcess + transform: ! {name: look forward, sat: 1.5} + inverse_transform: ! {name: look inverse, sat: 1.5} + +view_transforms: + - ! + name: default_vt + to_reference: ! {sat: 1.5} + + - ! + name: display_vt + to_display_reference: ! {name: display vt to ref, sat: 1.5} + from_display_reference: ! {name: display vt from ref, sat: 1.5} + +display_colorspaces: + - ! + name: displayCSIn + to_display_reference: ! {name: in cs to ref, sat: 1.5} + from_display_reference: ! {name: in cs from ref, sat: 1.5} + + - ! + name: displayCSOut + to_display_reference: ! {name: out cs to ref, sat: 1.5} + from_display_reference: ! {name: out cs from ref, sat: 1.5} + + - ! + name: displayCSProcess + to_display_reference: ! {name: process cs to ref, sat: 1.5} + from_display_reference: ! {name: process cs from ref, sat: 1.5} + +colorspaces: + - ! + name: raw + family: raw + description: A raw color space. + isdata: true +)" }; + + std::istringstream is; + is.str(CONFIG); + + OCIO::ConstConfigRcPtr config; + OCIO_CHECK_NO_THROW(config = OCIO::Config::CreateFromStream(is)); + OCIO_CHECK_NO_THROW(config->sanityCheck()); + + auto dt = OCIO::DisplayViewTransform::Create(); + dt->setSrc("displayCSIn"); + dt->setDisplay("display"); + dt->setView("view"); + + // + // Test in forward direction. + // + + OCIO::OpRcPtrVec ops; + OCIO_CHECK_NO_THROW(OCIO::BuildDisplayOps(ops, *config, + config->getCurrentContext(), *dt, + OCIO::TRANSFORM_DIR_FORWARD)); + OCIO_REQUIRE_EQUAL(ops.size(), 11); + OCIO_CHECK_NO_THROW(ops.validate()); + + // DisplayCSIn->displayCSProcess: + // 0. GPU Allocation No-op. + // 1. In to reference. + // 2. Look process space from reference. + // 3. GPU Allocation No-op. + // 4-5. Look-noop + look transform. + // DisplayCSProcess->display reference: + // 6. GPU Allocation No-op. + // 7. DisplayCSProcess to display reference. + // 8. Display-referred VT. + // Reference->DisplayCSOutput: + // 9. DisplayCSOutput from display reference. + // 10. GPU Allocation No-op. + + // 0. GPU Allocation No-op. + auto op = OCIO_DYNAMIC_POINTER_CAST(ops[0]); + auto data = op->data(); + OCIO_REQUIRE_EQUAL(data->getType(), OCIO::OpData::NoOpType); + + // 1. In to reference. + op = OCIO_DYNAMIC_POINTER_CAST(ops[1]); + ValidateTransform(op, "in cs to ref", OCIO::TRANSFORM_DIR_FORWARD, __LINE__); + + // 2. Look process space from reference. + op = OCIO_DYNAMIC_POINTER_CAST(ops[2]); + data = op->data(); + ValidateTransform(op, "process cs from ref", OCIO::TRANSFORM_DIR_FORWARD, __LINE__); + + // 3. GPU Allocation No-op. + op = OCIO_DYNAMIC_POINTER_CAST(ops[3]); + data = op->data(); + OCIO_CHECK_EQUAL(data->getType(), OCIO::OpData::NoOpType); + + // 4. Look No-op. + op = OCIO_DYNAMIC_POINTER_CAST(ops[4]); + data = op->data(); + OCIO_CHECK_EQUAL(data->getType(), OCIO::OpData::NoOpType); + + // 5. Look transform. + op = OCIO_DYNAMIC_POINTER_CAST(ops[5]); + data = op->data(); + ValidateTransform(op, "look forward", OCIO::TRANSFORM_DIR_FORWARD, __LINE__); + + // 6. GPU Allocation No-op. + op = OCIO_DYNAMIC_POINTER_CAST(ops[6]); + data = op->data(); + OCIO_CHECK_EQUAL(data->getType(), OCIO::OpData::NoOpType); + + // 7. DisplayCSProcess to display reference. + op = OCIO_DYNAMIC_POINTER_CAST(ops[7]); + data = op->data(); + ValidateTransform(op, "process cs to ref", OCIO::TRANSFORM_DIR_FORWARD, __LINE__); + + // 8. Display-referred VT. + op = OCIO_DYNAMIC_POINTER_CAST(ops[8]); + data = op->data(); + ValidateTransform(op, "display vt from ref", OCIO::TRANSFORM_DIR_FORWARD, __LINE__); + + // 9. DisplayCSOutput from display reference. + op = OCIO_DYNAMIC_POINTER_CAST(ops[9]); + data = op->data(); + ValidateTransform(op, "out cs from ref", OCIO::TRANSFORM_DIR_FORWARD, __LINE__); + + // 10. GPU Allocation No-op. + op = OCIO_DYNAMIC_POINTER_CAST(ops[10]); + data = op->data(); + OCIO_CHECK_EQUAL(data->getType(), OCIO::OpData::NoOpType); + + // + // Test in inverse direction. + // + + ops.clear(); + OCIO_CHECK_NO_THROW(OCIO::BuildDisplayOps(ops, *config, + config->getCurrentContext(), *dt, + OCIO::TRANSFORM_DIR_INVERSE)); + + OCIO_REQUIRE_EQUAL(ops.size(), 11); + OCIO_CHECK_NO_THROW(ops.validate()); + + // 0. GPU Allocation No-op. + op = OCIO_DYNAMIC_POINTER_CAST(ops[0]); + data = op->data(); + OCIO_CHECK_EQUAL(data->getType(), OCIO::OpData::NoOpType); + + // 1. DisplayCSOutput to display reference. + op = OCIO_DYNAMIC_POINTER_CAST(ops[1]); + data = op->data(); + ValidateTransform(op, "out cs to ref", OCIO::TRANSFORM_DIR_FORWARD, __LINE__); + + // 2. Display-referred VT. + op = OCIO_DYNAMIC_POINTER_CAST(ops[2]); + data = op->data(); + ValidateTransform(op, "display vt to ref", OCIO::TRANSFORM_DIR_FORWARD, __LINE__); + + // 3. DisplayCSProcess from display reference. + op = OCIO_DYNAMIC_POINTER_CAST(ops[3]); + data = op->data(); + ValidateTransform(op, "process cs from ref", OCIO::TRANSFORM_DIR_FORWARD, __LINE__); + + // 4. GPU Allocation No-op. + op = OCIO_DYNAMIC_POINTER_CAST(ops[4]); + data = op->data(); + OCIO_CHECK_EQUAL(data->getType(), OCIO::OpData::NoOpType); + + // 5. Look No-op. + op = OCIO_DYNAMIC_POINTER_CAST(ops[5]); + data = op->data(); + OCIO_CHECK_EQUAL(data->getType(), OCIO::OpData::NoOpType); + + // 6. Look transform (inverse). + op = OCIO_DYNAMIC_POINTER_CAST(ops[6]); + data = op->data(); + ValidateTransform(op, "look inverse", OCIO::TRANSFORM_DIR_FORWARD, __LINE__); + + // 7. GPU Allocation No-op. + op = OCIO_DYNAMIC_POINTER_CAST(ops[7]); + data = op->data(); + OCIO_CHECK_EQUAL(data->getType(), OCIO::OpData::NoOpType); + + // 8. Look process space to reference. + op = OCIO_DYNAMIC_POINTER_CAST(ops[8]); + data = op->data(); + ValidateTransform(op, "process cs to ref", OCIO::TRANSFORM_DIR_FORWARD, __LINE__); + + // 9. In from reference. + op = OCIO_DYNAMIC_POINTER_CAST(ops[9]); + data = op->data(); + ValidateTransform(op, "in cs from ref", OCIO::TRANSFORM_DIR_FORWARD, __LINE__); + + // 10. GPU Allocation No-op. + op = OCIO_DYNAMIC_POINTER_CAST(ops[10]); + data = op->data(); + OCIO_REQUIRE_EQUAL(data->getType(), OCIO::OpData::NoOpType); + + // + // Check that looks can be bypassed. + // + + dt->setLooksBypass(true); + ops.clear(); + OCIO_CHECK_NO_THROW(OCIO::BuildDisplayOps(ops, *config, + config->getCurrentContext(), *dt, + OCIO::TRANSFORM_DIR_FORWARD)); + OCIO_REQUIRE_EQUAL(ops.size(), 5); + OCIO_CHECK_NO_THROW(ops.validate()); + + // 0. GPU Allocation No-op. + op = OCIO_DYNAMIC_POINTER_CAST(ops[0]); + data = op->data(); + OCIO_CHECK_EQUAL(data->getType(), OCIO::OpData::NoOpType); + + // 1. In to reference. + op = OCIO_DYNAMIC_POINTER_CAST(ops[1]); + data = op->data(); + ValidateTransform(op, "in cs to ref", OCIO::TRANSFORM_DIR_FORWARD, __LINE__); + + // 2. Display-referred VT. + op = OCIO_DYNAMIC_POINTER_CAST(ops[2]); + data = op->data(); + ValidateTransform(op, "display vt from ref", OCIO::TRANSFORM_DIR_FORWARD, __LINE__); + + // 3. DisplayCSOutput from display reference. + op = OCIO_DYNAMIC_POINTER_CAST(ops[3]); + data = op->data(); + ValidateTransform(op, "out cs from ref", OCIO::TRANSFORM_DIR_FORWARD, __LINE__); + + // 4. GPU Allocation No-op. + op = OCIO_DYNAMIC_POINTER_CAST(ops[4]); + data = op->data(); + OCIO_CHECK_EQUAL(data->getType(), OCIO::OpData::NoOpType); + + // + // Tests without a view transform. + // + + dt->setLooksBypass(false); + dt->setView("viewNoVT"); + + // + // Test in forward direction. + // + + ops.clear(); + OCIO_CHECK_NO_THROW(OCIO::BuildDisplayOps(ops, *config, + config->getCurrentContext(), *dt, + OCIO::TRANSFORM_DIR_FORWARD)); + OCIO_REQUIRE_EQUAL(ops.size(), 10); + OCIO_CHECK_NO_THROW(ops.validate()); + + // 0. GPU Allocation No-op. + op = OCIO_DYNAMIC_POINTER_CAST(ops[0]); + data = op->data(); + OCIO_REQUIRE_EQUAL(data->getType(), OCIO::OpData::NoOpType); + + // 1. In to reference. + op = OCIO_DYNAMIC_POINTER_CAST(ops[1]); + ValidateTransform(op, "in cs to ref", OCIO::TRANSFORM_DIR_FORWARD, __LINE__); + + // 2. Look process space from reference. + op = OCIO_DYNAMIC_POINTER_CAST(ops[2]); + data = op->data(); + ValidateTransform(op, "process cs from ref", OCIO::TRANSFORM_DIR_FORWARD, __LINE__); + + // 3. GPU Allocation No-op. + op = OCIO_DYNAMIC_POINTER_CAST(ops[3]); + data = op->data(); + OCIO_CHECK_EQUAL(data->getType(), OCIO::OpData::NoOpType); + + // 4. Look No-op. + op = OCIO_DYNAMIC_POINTER_CAST(ops[4]); + data = op->data(); + OCIO_CHECK_EQUAL(data->getType(), OCIO::OpData::NoOpType); + + // 5. Look transform. + op = OCIO_DYNAMIC_POINTER_CAST(ops[5]); + data = op->data(); + ValidateTransform(op, "look forward", OCIO::TRANSFORM_DIR_FORWARD, __LINE__); + + // 6. GPU Allocation No-op. + op = OCIO_DYNAMIC_POINTER_CAST(ops[6]); + data = op->data(); + OCIO_CHECK_EQUAL(data->getType(), OCIO::OpData::NoOpType); + + // 7. DisplayCSProcess to display reference. + op = OCIO_DYNAMIC_POINTER_CAST(ops[7]); + data = op->data(); + ValidateTransform(op, "process cs to ref", OCIO::TRANSFORM_DIR_FORWARD, __LINE__); + + // 8. DisplayCSOutput from display reference. + op = OCIO_DYNAMIC_POINTER_CAST(ops[8]); + data = op->data(); + ValidateTransform(op, "out cs from ref", OCIO::TRANSFORM_DIR_FORWARD, __LINE__); + + // 9. GPU Allocation No-op. + op = OCIO_DYNAMIC_POINTER_CAST(ops[9]); + data = op->data(); + OCIO_CHECK_EQUAL(data->getType(), OCIO::OpData::NoOpType); + + // + // Test in inverse direction. + // + + ops.clear(); + OCIO_CHECK_NO_THROW(OCIO::BuildDisplayOps(ops, *config, + config->getCurrentContext(), *dt, + OCIO::TRANSFORM_DIR_INVERSE)); + OCIO_REQUIRE_EQUAL(ops.size(), 10); + OCIO_CHECK_NO_THROW(ops.validate()); + + // 0. GPU Allocation No-op. + op = OCIO_DYNAMIC_POINTER_CAST(ops[0]); + data = op->data(); + OCIO_CHECK_EQUAL(data->getType(), OCIO::OpData::NoOpType); + + // 1. DisplayCSOutput to display reference. + op = OCIO_DYNAMIC_POINTER_CAST(ops[1]); + data = op->data(); + ValidateTransform(op, "out cs to ref", OCIO::TRANSFORM_DIR_FORWARD, __LINE__); + + // 2. DisplayCSProcess from display reference. + op = OCIO_DYNAMIC_POINTER_CAST(ops[2]); + data = op->data(); + ValidateTransform(op, "process cs from ref", OCIO::TRANSFORM_DIR_FORWARD, __LINE__); + + // 3. GPU Allocation No-op. + op = OCIO_DYNAMIC_POINTER_CAST(ops[3]); + data = op->data(); + OCIO_CHECK_EQUAL(data->getType(), OCIO::OpData::NoOpType); + + // 4. Look No-op. + op = OCIO_DYNAMIC_POINTER_CAST(ops[4]); + data = op->data(); + OCIO_CHECK_EQUAL(data->getType(), OCIO::OpData::NoOpType); + + // 5. Look transform (inverse). + op = OCIO_DYNAMIC_POINTER_CAST(ops[5]); + data = op->data(); + ValidateTransform(op, "look inverse", OCIO::TRANSFORM_DIR_FORWARD, __LINE__); + + // 6. GPU Allocation No-op. + op = OCIO_DYNAMIC_POINTER_CAST(ops[6]); + data = op->data(); + OCIO_CHECK_EQUAL(data->getType(), OCIO::OpData::NoOpType); + + // 7. Look process space to reference. + op = OCIO_DYNAMIC_POINTER_CAST(ops[7]); + data = op->data(); + ValidateTransform(op, "process cs to ref", OCIO::TRANSFORM_DIR_FORWARD, __LINE__); + + // 8. In from reference. + op = OCIO_DYNAMIC_POINTER_CAST(ops[8]); + data = op->data(); + ValidateTransform(op, "in cs from ref", OCIO::TRANSFORM_DIR_FORWARD, __LINE__); + + // 9. GPU Allocation No-op. + op = OCIO_DYNAMIC_POINTER_CAST(ops[9]); + data = op->data(); + OCIO_REQUIRE_EQUAL(data->getType(), OCIO::OpData::NoOpType); + +} + +OCIO_ADD_TEST(DisplayViewTransform, config_load) +{ + constexpr const char * SIMPLE_CONFIG{ R"( +ocio_profile_version: 2 + +roles: + default: raw + +displays: + displayName: + - ! {name: viewName, colorspace: out} + +colorspaces: + - ! + name: raw + + - ! + name: in + to_reference: ! {offset: [0.11, 0.12, 0.13, 0]} + + - ! + name: out + from_reference: ! {offset: [0.11, 0.12, 0.13, 0]} + + - ! + name: test + from_reference: ! {src: in, display: displayName, view: viewName} + to_reference: ! {src: in, display: displayName, view: viewName, looks_bypass: true, data_bypass: false} +)" }; + + std::istringstream is; + is.str(SIMPLE_CONFIG); + OCIO::ConstConfigRcPtr config; + OCIO_CHECK_NO_THROW(config = OCIO::Config::CreateFromStream(is)); + + OCIO::ConstColorSpaceRcPtr cs = config->getColorSpace("test"); + OCIO_REQUIRE_ASSERT(cs); + auto tr = cs->getTransform(OCIO::COLORSPACE_DIR_FROM_REFERENCE); + OCIO_REQUIRE_ASSERT(tr); + auto displayTr = OCIO_DYNAMIC_POINTER_CAST(tr); + OCIO_REQUIRE_ASSERT(displayTr); + OCIO_CHECK_EQUAL(OCIO::TRANSFORM_DIR_FORWARD, displayTr->getDirection()); + OCIO_CHECK_EQUAL(std::string("in"), displayTr->getSrc()); + OCIO_CHECK_EQUAL(std::string("displayName"), displayTr->getDisplay()); + OCIO_CHECK_EQUAL(std::string("viewName"), displayTr->getView()); + OCIO_CHECK_ASSERT(!displayTr->getLooksBypass()); + OCIO_CHECK_ASSERT(displayTr->getDataBypass()); + + tr = cs->getTransform(OCIO::COLORSPACE_DIR_TO_REFERENCE); + OCIO_REQUIRE_ASSERT(tr); + displayTr = OCIO_DYNAMIC_POINTER_CAST(tr); + OCIO_REQUIRE_ASSERT(displayTr); + OCIO_CHECK_ASSERT(displayTr->getLooksBypass()); + OCIO_CHECK_ASSERT(!displayTr->getDataBypass()); +} + +OCIO_ADD_TEST(DisplayViewTransform, apply_fwd_inv) +{ + constexpr char CONFIG[]{ R"( +ocio_profile_version: 2 + +roles: + default: raw + +displays: + sRGB: + - ! {name: Raw, colorspace: raw} + display: + - ! {name: view, view_transform: display_vt, display_colorspace: displayCSOut, looks: look} + - ! {name: viewNoVT, colorspace: displayCSOut, looks: look} + +looks: + - ! + name: look + process_space: displayCSProcess + transform: ! {offset: [0.1, 0.2, 0.3, 0]} + +view_transforms: + - ! + name: default_vt + to_reference: ! {offset: [0.2, 0.2, 0.4, 0]} + + - ! + name: display_vt + to_display_reference: ! {offset: [0.3, 0.1, 0.1, 0]} + +display_colorspaces: + - ! + name: displayCSOut + to_display_reference: ! {offset: [0.25, 0.15, 0.35, 0]} + + - ! + name: displayCSProcess + to_display_reference: ! {offset: [0.1, 0.1, 0.1, 0]} + +colorspaces: + - ! + name: raw + family: raw + description: A raw color space. + isdata: true + + - ! + name: displayCSIn + to_reference: ! {offset: [-0.15, 0.15, 0.15, 0.05]} +)" }; + + std::istringstream is; + is.str(CONFIG); + + OCIO::ConstConfigRcPtr config; + OCIO_CHECK_NO_THROW(config = OCIO::Config::CreateFromStream(is)); + OCIO_CHECK_NO_THROW(config->sanityCheck()); + + // Create a display transform using a view that use a view transform and a scene-referred + // input color space. Create forward and inverse processor and apply them one after the + // other to a set of pixels. Finally check that the processor created from a group that + // holds the forward transform and the inverse transform is a no-op. + + auto dt = OCIO::DisplayViewTransform::Create(); + dt->setSrc("displayCSIn"); + dt->setDisplay("display"); + dt->setView("view"); + + OCIO::ConstProcessorRcPtr proc; + OCIO_CHECK_NO_THROW(proc = config->getProcessor(dt)); + OCIO_REQUIRE_ASSERT(proc); + OCIO_CHECK_EQUAL(proc->getNumTransforms(), 7); + auto procGroup = proc->createGroupTransform(); + OCIO_REQUIRE_ASSERT(procGroup); + OCIO_CHECK_EQUAL(procGroup->getNumTransforms(), 7); + OCIO::ConstCPUProcessorRcPtr cpuProc; + OCIO_CHECK_NO_THROW(cpuProc = proc->getDefaultCPUProcessor()); + OCIO_REQUIRE_ASSERT(cpuProc); + OCIO_CHECK_EQUAL(proc->getNumTransforms(), 7); + + OCIO::ConstProcessorRcPtr procInv; + OCIO_CHECK_NO_THROW(procInv = config->getProcessor(dt, OCIO::TRANSFORM_DIR_INVERSE)); + OCIO_REQUIRE_ASSERT(procInv); + OCIO_CHECK_EQUAL(procInv->getNumTransforms(), 7); + procGroup = procInv->createGroupTransform(); + OCIO_REQUIRE_ASSERT(procGroup); + OCIO_CHECK_EQUAL(procGroup->getNumTransforms(), 7); + OCIO::ConstCPUProcessorRcPtr cpuProcInv; + OCIO_CHECK_NO_THROW(cpuProcInv = procInv->getDefaultCPUProcessor()); + OCIO_REQUIRE_ASSERT(cpuProcInv); + + const float ref[] = { 0.0f, 0.1f, 0.2f, 0.0f, + 0.3f, 0.4f, 0.5f, 0.5f, + 0.6f, 0.7f, 0.8f, 0.7f, + 0.9f, 1.0f, 1.1f, 1.0f }; + + constexpr float error = 1e-6f; + for (int i = 0; i < 4; ++i) + { + float rgba[] = { ref[4 * i + 0], + ref[4 * i + 1], + ref[4 * i + 2], + ref[4 * i + 3] }; + cpuProc->applyRGBA(rgba); + cpuProcInv->applyRGBA(rgba); + OCIO_CHECK_CLOSE(rgba[0], ref[4 * i + 0], error); + OCIO_CHECK_CLOSE(rgba[1], ref[4 * i + 1], error); + OCIO_CHECK_CLOSE(rgba[2], ref[4 * i + 2], error); + OCIO_CHECK_CLOSE(rgba[3], ref[4 * i + 3], error); + } + + auto group = OCIO::GroupTransform::Create(); + group->appendTransform(dt); + auto dtInv = dt->createEditableCopy(); + dtInv->setDirection(OCIO::TRANSFORM_DIR_INVERSE); + group->appendTransform(dtInv); + + // Note that optimization does only happen once each transform has been converted to ops. + auto groupProc = config->getProcessor(group); + groupProc = groupProc->getOptimizedProcessor(OCIO::BIT_DEPTH_F32, OCIO::BIT_DEPTH_F32, + OCIO::OPTIMIZATION_DEFAULT); + OCIO_CHECK_ASSERT(groupProc->isNoOp()); + + // Do a similar test using a display transform that does not use a view transform. + + dt->setDisplay("display"); + dt->setView("viewNoVT"); + + OCIO_CHECK_NO_THROW(proc = config->getProcessor(dt)); + OCIO_REQUIRE_ASSERT(proc); + OCIO_CHECK_EQUAL(proc->getNumTransforms(), 6); + procGroup = proc->createGroupTransform(); + OCIO_REQUIRE_ASSERT(procGroup); + OCIO_CHECK_EQUAL(procGroup->getNumTransforms(), 6); + OCIO_CHECK_NO_THROW(cpuProc = proc->getDefaultCPUProcessor()); + OCIO_REQUIRE_ASSERT(cpuProc); + + OCIO_CHECK_NO_THROW(procInv = config->getProcessor(dt, OCIO::TRANSFORM_DIR_INVERSE)); + OCIO_REQUIRE_ASSERT(procInv); + OCIO_CHECK_EQUAL(procInv->getNumTransforms(), 6); + procGroup = procInv->createGroupTransform(); + OCIO_REQUIRE_ASSERT(procGroup); + OCIO_CHECK_EQUAL(procGroup->getNumTransforms(), 6); + OCIO_CHECK_NO_THROW(cpuProcInv = procInv->getDefaultCPUProcessor()); + OCIO_REQUIRE_ASSERT(cpuProcInv); + + for (int i = 0; i < 4; ++i) + { + float rgba[] = { ref[4 * i + 0], + ref[4 * i + 1], + ref[4 * i + 2], + ref[4 * i + 3] }; + cpuProc->applyRGBA(rgba); + cpuProcInv->applyRGBA(rgba); + OCIO_CHECK_CLOSE(rgba[0], ref[4 * i + 0], error); + OCIO_CHECK_CLOSE(rgba[1], ref[4 * i + 1], error); + OCIO_CHECK_CLOSE(rgba[2], ref[4 * i + 2], error); + OCIO_CHECK_CLOSE(rgba[3], ref[4 * i + 3], error); + } + + group = OCIO::GroupTransform::Create(); + group->appendTransform(dt); + dtInv = dt->createEditableCopy(); + dtInv->setDirection(OCIO::TRANSFORM_DIR_INVERSE); + group->appendTransform(dtInv); + + groupProc = config->getProcessor(group); + groupProc = groupProc->getOptimizedProcessor(OCIO::BIT_DEPTH_F32, OCIO::BIT_DEPTH_F32, + OCIO::OPTIMIZATION_DEFAULT); + OCIO_CHECK_ASSERT(groupProc->isNoOp()); +} diff --git a/tests/cpu/transforms/LookTransform_tests.cpp b/tests/cpu/transforms/LookTransform_tests.cpp new file mode 100644 index 0000000000..f5ba3fd644 --- /dev/null +++ b/tests/cpu/transforms/LookTransform_tests.cpp @@ -0,0 +1,445 @@ +// SPDX-License-Identifier: BSD-3-Clause +// Copyright Contributors to the OpenColorIO Project. + + +#include "ops/fixedfunction/FixedFunctionOpData.h" + +#include "transforms/LookTransform.cpp" + +#include "testutils/UnitTest.h" +#include "UnitTestUtils.h" + +namespace OCIO = OCIO_NAMESPACE; + + +OCIO_ADD_TEST(LookTransform, basic) +{ + OCIO::LookTransformRcPtr look = OCIO::LookTransform::Create(); + OCIO_CHECK_EQUAL(look->getDirection(), OCIO::TRANSFORM_DIR_FORWARD); + + look->setDirection(OCIO::TRANSFORM_DIR_INVERSE); + OCIO_CHECK_EQUAL(look->getDirection(), OCIO::TRANSFORM_DIR_INVERSE); + + OCIO_CHECK_EQUAL(look->getSrc(), std::string("")); + OCIO_CHECK_EQUAL(look->getDst(), std::string("")); + OCIO_CHECK_EQUAL(look->getLooks(), std::string("")); + + OCIO_CHECK_THROW_WHAT(look->validate(), OCIO::Exception, "empty source"); + + const std::string src{ "src" }; + const std::string dst{ "dst" }; + const std::string looks{ "look1, look2, look3" }; + + look->setSrc(src.c_str()); + OCIO_CHECK_EQUAL(look->getSrc(), src); + + OCIO_CHECK_THROW_WHAT(look->validate(), OCIO::Exception, "empty destination"); + + look->setDst(dst.c_str()); + OCIO_CHECK_EQUAL(look->getDst(), dst); + + OCIO_CHECK_NO_THROW(look->validate()); + + look->setLooks(looks.c_str()); + OCIO_CHECK_EQUAL(look->getLooks(), looks); + + OCIO_CHECK_ASSERT(!look->getSkipColorSpaceConversion()); + look->setSkipColorSpaceConversion(true); + OCIO_CHECK_ASSERT(look->getSkipColorSpaceConversion()); + + // Copy and check copy has same values. + auto tr = look->createEditableCopy(); + look = OCIO_DYNAMIC_POINTER_CAST(tr); + OCIO_CHECK_EQUAL(look->getSrc(), src); + OCIO_CHECK_EQUAL(look->getDst(), dst); + OCIO_CHECK_EQUAL(look->getLooks(), looks); + OCIO_CHECK_ASSERT(look->getSkipColorSpaceConversion()); + + // Using null is similar as using an empty string. + look->setSrc(nullptr); + OCIO_CHECK_EQUAL(look->getSrc(), std::string("")); + + look->setDst(nullptr); + OCIO_CHECK_EQUAL(look->getDst(), std::string("")); +} + +namespace +{ +void ValidateTransform(OCIO::ConstOpRcPtr & op, const std::string & name, + OCIO::TransformDirection dir, unsigned line) +{ + OCIO_REQUIRE_EQUAL_FROM(op->data()->getFormatMetadata().getNumAttributes(), 1, line); + OCIO_CHECK_EQUAL_FROM(op->data()->getFormatMetadata().getAttributeValue(0), name, line); + + auto ff = OCIO_DYNAMIC_POINTER_CAST(op->data()); + OCIO_REQUIRE_ASSERT_FROM(ff, line); + OCIO_CHECK_EQUAL_FROM(ff->getDirection(), dir, line); +} +} + +OCIO_ADD_TEST(LookTransform, build_look_ops) +{ + constexpr const char * OCIO_CONFIG{ R"( +ocio_profile_version: 2 + +roles: + default: raw + +displays: + sRGB: + - ! {name: Raw, colorspace: raw} + +looks: + - ! + name: look1 + process_space: look1_cs + transform: ! {name: look1 trans, style: ACES_RedMod03} + + - ! + name: look2 + process_space: look2_3_cs + transform: ! {name: look2 trans, style: ACES_RedMod03} + inverse_transform: ! {name: look2 inverse trans, style: ACES_RedMod03} + + - ! + name: look3 + process_space: look2_3_cs + inverse_transform: ! {name: look3 inverse trans, style: ACES_RedMod03} + +colorspaces: + - ! + name: raw + family: raw + bitdepth: 32f + description: | + A raw color space. Conversions to and from this space are no-ops. + isdata: true + + - ! + name: source + to_reference: ! {name: src, style: ACES_RedMod03} + + - ! + name: destination + from_reference: ! {name: dst, style: ACES_RedMod03} + + - ! + name: look1_cs + to_reference: ! {name: look1_cs trans, style: ACES_RedMod03} + + - ! + name: look2_3_cs + to_reference: ! {name: look2_3_cs trans, style: ACES_RedMod03} +)" }; + + std::istringstream is; + is.str(OCIO_CONFIG); + + OCIO::ConstConfigRcPtr config; + OCIO_CHECK_NO_THROW(config = OCIO::Config::CreateFromStream(is)); + OCIO_CHECK_NO_THROW(config->sanityCheck()); + + // Create look transform with source and destination color spaces, and 3 looks. Each look + // has its own process space. + OCIO::LookTransformRcPtr lt = OCIO::LookTransform::Create(); + lt->setSrc("source"); + lt->setDst("destination"); + lt->setLooks("look1, +look2, -look3"); + + // Create ops in forward direction. + OCIO::OpRcPtrVec ops; + OCIO_CHECK_NO_THROW(OCIO::BuildLookOps(ops, *config, config->getCurrentContext(), + *lt, OCIO::TRANSFORM_DIR_FORWARD)); + OCIO_CHECK_NO_THROW(ops.validate()); + OCIO_REQUIRE_EQUAL(ops.size(), 18); // There are many no-ops. + + // Source color space to look1 process color space. + // No-ops are created at the beginning and at the end of the color space conversion. + OCIO::ConstOpRcPtr op = ops[0]; + OCIO_CHECK_ASSERT(op->isNoOpType()); + op = ops[1]; // Source to ref. + ValidateTransform(op, "src", OCIO::TRANSFORM_DIR_FORWARD, __LINE__); + op = ops[2]; // Ref to look1_cs. + ValidateTransform(op, "look1_cs trans", OCIO::TRANSFORM_DIR_INVERSE, __LINE__); + op = ops[3]; + OCIO_CHECK_ASSERT(op->isNoOpType()); + + // Look1 transform. + op = ops[4]; // No-op added before each look. + OCIO_CHECK_ASSERT(op->isNoOpType()); + op = ops[5]; + ValidateTransform(op, "look1 trans", OCIO::TRANSFORM_DIR_FORWARD, __LINE__); + + // Look1 process color space to look2 process color space. + op = ops[6]; + OCIO_CHECK_ASSERT(op->isNoOpType()); + op = ops[7]; // Look1 cs to ref. + ValidateTransform(op, "look1_cs trans", OCIO::TRANSFORM_DIR_FORWARD, __LINE__); + op = ops[8]; // Ref to look2_3_cs. + ValidateTransform(op, "look2_3_cs trans", OCIO::TRANSFORM_DIR_INVERSE, __LINE__); + op = ops[9]; + OCIO_CHECK_ASSERT(op->isNoOpType()); + + // Look2 transform. + op = ops[10]; + OCIO_CHECK_ASSERT(op->isNoOpType()); + // Look2 has both forward and inverse, using forward. + op = ops[11]; + ValidateTransform(op, "look2 trans", OCIO::TRANSFORM_DIR_FORWARD, __LINE__); + + // No color space conversion: look2 & look3 have the same process color space. + + // Look3 transform. + op = ops[12]; + OCIO_CHECK_ASSERT(op->isNoOpType()); + // Look3 is applied with a "-" so want to use the inverse_transform direction. + op = ops[13]; + ValidateTransform(op, "look3 inverse trans", OCIO::TRANSFORM_DIR_FORWARD, __LINE__); + + // Look3 process color space to destination color space. + op = ops[14]; + OCIO_CHECK_ASSERT(op->isNoOpType()); + op = ops[15]; // Look2_3_cs to ref. + ValidateTransform(op, "look2_3_cs trans", OCIO::TRANSFORM_DIR_FORWARD, __LINE__); + op = ops[16]; // Ref to detination. + ValidateTransform(op, "dst", OCIO::TRANSFORM_DIR_FORWARD, __LINE__); + op = ops[17]; + OCIO_CHECK_ASSERT(op->isNoOpType()); + + // Test in inverse direction. + ops.clear(); + OCIO_CHECK_NO_THROW(OCIO::BuildLookOps(ops, *config, config->getCurrentContext(), + *lt, OCIO::TRANSFORM_DIR_INVERSE)); + OCIO_CHECK_NO_THROW(ops.validate()); + OCIO_REQUIRE_EQUAL(ops.size(), 18); + + // Destination color space to Look3 process color space. + op = ops[0]; + OCIO_CHECK_ASSERT(op->isNoOpType()); + op = ops[1]; + ValidateTransform(op, "dst", OCIO::TRANSFORM_DIR_INVERSE, __LINE__); + op = ops[2]; + ValidateTransform(op, "look2_3_cs trans", OCIO::TRANSFORM_DIR_INVERSE, __LINE__); + op = ops[3]; + OCIO_CHECK_ASSERT(op->isNoOpType()); + + // Look3 transform. + op = ops[4]; + OCIO_CHECK_ASSERT(op->isNoOpType()); + op = ops[5]; + // Forward transform is not available, so use the inverse of the inverse_transform. + ValidateTransform(op, "look3 inverse trans", OCIO::TRANSFORM_DIR_INVERSE, __LINE__); + + // No color space conversion: look3 and look2 have the same process color space. + + // Look2 transform. + op = ops[6]; + OCIO_CHECK_ASSERT(op->isNoOpType()); + // Look2 has both forward and inverse, using inverse. + op = ops[7]; + ValidateTransform(op, "look2 inverse trans", OCIO::TRANSFORM_DIR_FORWARD, __LINE__); + + // Look2 process color space to look1 process color space. + op = ops[8]; + OCIO_CHECK_ASSERT(op->isNoOpType()); + op = ops[9]; + ValidateTransform(op, "look2_3_cs trans", OCIO::TRANSFORM_DIR_FORWARD, __LINE__); + op = ops[10]; + ValidateTransform(op, "look1_cs trans", OCIO::TRANSFORM_DIR_INVERSE, __LINE__); + op = ops[11]; + OCIO_CHECK_ASSERT(op->isNoOpType()); + + // Look1 transform. + op = ops[12]; + OCIO_CHECK_ASSERT(op->isNoOpType()); + op = ops[13]; + // Inverse_transform not available so use the inverse of the forward transform. + ValidateTransform(op, "look1 trans", OCIO::TRANSFORM_DIR_INVERSE, __LINE__); + + // Look1 process color space to source color space. + op = ops[14]; + OCIO_CHECK_ASSERT(op->isNoOpType()); + op = ops[15]; + ValidateTransform(op, "look1_cs trans", OCIO::TRANSFORM_DIR_FORWARD, __LINE__); + op = ops[16]; + ValidateTransform(op, "src", OCIO::TRANSFORM_DIR_INVERSE, __LINE__); + op = ops[17]; + OCIO_CHECK_ASSERT(op->isNoOpType()); +} + +OCIO_ADD_TEST(LookTransform, build_look_options_ops) +{ + constexpr const char * OCIO_CONFIG{ R"( +ocio_profile_version: 2 + +roles: + default: raw + +displays: + sRGB: + - ! {name: Raw, colorspace: raw} + +looks: + - ! + name: look1 + process_space: raw + transform: ! {src: missingfile} + + - ! + name: look2 + process_space: look2_cs + transform: ! {name: look2 trans, style: ACES_RedMod03} + + - ! + name: look3 + process_space: look3_cs + transform: ! {name: look3 trans, style: ACES_RedMod03} + + - ! + name: look4 + process_space: look4_cs + transform: ! {name: look4 trans, style: ACES_RedMod03} + + - ! + name: look5 + process_space: raw + transform: ! {src: missingfile} + +colorspaces: + - ! + name: raw + family: raw + bitdepth: 32f + description: | + A raw color space. Conversions to and from this space are no-ops. + isdata: true + + - ! + name: source + to_reference: ! {name: src, style: ACES_RedMod03} + + - ! + name: destination + from_reference: ! {name: dst, style: ACES_RedMod03} + + - ! + name: look2_cs + to_reference: ! {name: look2_cs trans, style: ACES_RedMod03} + + - ! + name: look3_cs + to_reference: ! {name: look3_cs trans, style: ACES_RedMod03} + + - ! + name: look4_cs + to_reference: ! {name: look4_cs trans, style: ACES_RedMod03} +)" }; + + std::istringstream is; + is.str(OCIO_CONFIG); + + OCIO::ConstConfigRcPtr config; + OCIO_CHECK_NO_THROW(config = OCIO::Config::CreateFromStream(is)); + OCIO_CHECK_NO_THROW(config->sanityCheck()); + + // LookTransform options test. First option (1) gets missing file error, + // second option (2 & 3) works, third option (3 & 4) not needed. + + OCIO::LookTransformRcPtr lt = OCIO::LookTransform::Create(); + const std::string src{ "source" }; + lt->setSrc(src.c_str()); + const std::string dst{ "destination" }; + lt->setDst(dst.c_str()); + lt->setLooks("look1 | look2, look3 | look3, look4"); + + // First option fails with a missing file, second option is fine: look2, look3. + OCIO::OpRcPtrVec ops; + OCIO_CHECK_NO_THROW(OCIO::BuildLookOps(ops, *config, config->getCurrentContext(), + *lt, OCIO::TRANSFORM_DIR_FORWARD)); + OCIO_CHECK_NO_THROW(ops.validate()); + OCIO_REQUIRE_EQUAL(ops.size(), 16); + OCIO::ConstOpRcPtr op = ops[0]; + OCIO_CHECK_ASSERT(op->isNoOpType()); + op = ops[1]; // Src to ref. + ValidateTransform(op, "src", OCIO::TRANSFORM_DIR_FORWARD, __LINE__); + op = ops[2]; // Ref to look2_cs. + ValidateTransform(op, "look2_cs trans", OCIO::TRANSFORM_DIR_INVERSE, __LINE__); + op = ops[3]; + OCIO_CHECK_ASSERT(op->isNoOpType()); + op = ops[4]; + OCIO_CHECK_ASSERT(op->isNoOpType()); + op = ops[5]; // Look2 transform. + ValidateTransform(op, "look2 trans", OCIO::TRANSFORM_DIR_FORWARD, __LINE__); + op = ops[6]; + OCIO_CHECK_ASSERT(op->isNoOpType()); + op = ops[7]; // Look2_cs to ref. + ValidateTransform(op, "look2_cs trans", OCIO::TRANSFORM_DIR_FORWARD, __LINE__); + op = ops[8]; // Ref to look3_cs. + ValidateTransform(op, "look3_cs trans", OCIO::TRANSFORM_DIR_INVERSE, __LINE__); + op = ops[9]; + OCIO_CHECK_ASSERT(op->isNoOpType()); + op = ops[10]; + OCIO_CHECK_ASSERT(op->isNoOpType()); + op = ops[11]; // Look3 transform. + ValidateTransform(op, "look3 trans", OCIO::TRANSFORM_DIR_FORWARD, __LINE__); + op = ops[12]; + OCIO_CHECK_ASSERT(op->isNoOpType()); + op = ops[13]; // Look3_cs to ref. + ValidateTransform(op, "look3_cs trans", OCIO::TRANSFORM_DIR_FORWARD, __LINE__); + op = ops[14]; // Ref to dst. + ValidateTransform(op, "dst", OCIO::TRANSFORM_DIR_FORWARD, __LINE__); + op = ops[15]; + OCIO_CHECK_ASSERT(op->isNoOpType()); + + // Test in inverse direction. + // Options are tried in the same order (3rd option is not tried before second one). + // Looks of the second option are reversed: look3, look2. + ops.clear(); + OCIO_CHECK_NO_THROW(OCIO::BuildLookOps(ops, *config, config->getCurrentContext(), + *lt, OCIO::TRANSFORM_DIR_INVERSE)); + OCIO_CHECK_NO_THROW(ops.validate()); + OCIO_REQUIRE_EQUAL(ops.size(), 16); + op = ops[0]; + OCIO_CHECK_ASSERT(op->isNoOpType()); + op = ops[1]; + ValidateTransform(op, "dst", OCIO::TRANSFORM_DIR_INVERSE, __LINE__); + op = ops[2]; + ValidateTransform(op, "look3_cs trans", OCIO::TRANSFORM_DIR_INVERSE, __LINE__); + op = ops[3]; + OCIO_CHECK_ASSERT(op->isNoOpType()); + op = ops[4]; + OCIO_CHECK_ASSERT(op->isNoOpType()); + op = ops[5]; + ValidateTransform(op, "look3 trans", OCIO::TRANSFORM_DIR_INVERSE, __LINE__); + op = ops[6]; + OCIO_CHECK_ASSERT(op->isNoOpType()); + op = ops[7]; + ValidateTransform(op, "look3_cs trans", OCIO::TRANSFORM_DIR_FORWARD, __LINE__); + op = ops[8]; + ValidateTransform(op, "look2_cs trans", OCIO::TRANSFORM_DIR_INVERSE, __LINE__); + op = ops[9]; + OCIO_CHECK_ASSERT(op->isNoOpType()); + op = ops[10]; + OCIO_CHECK_ASSERT(op->isNoOpType()); + op = ops[11]; + ValidateTransform(op, "look2 trans", OCIO::TRANSFORM_DIR_INVERSE, __LINE__); + op = ops[12]; + OCIO_CHECK_ASSERT(op->isNoOpType()); + op = ops[13]; + ValidateTransform(op, "look2_cs trans", OCIO::TRANSFORM_DIR_FORWARD, __LINE__); + op = ops[14]; + ValidateTransform(op, "src", OCIO::TRANSFORM_DIR_INVERSE, __LINE__); + op = ops[15]; + OCIO_CHECK_ASSERT(op->isNoOpType()); + + // Replace look3 by look5 so that look options will fail, an exception will be thrown. + // Looks has three options, first one involves look1 and the other two involve look5. + + lt->setLooks("look1 | look2, look5 | look5, look4"); + + OCIO_CHECK_THROW_WHAT(OCIO::BuildLookOps(ops, *config, config->getCurrentContext(), + *lt, OCIO::TRANSFORM_DIR_FORWARD), + OCIO::Exception, + "The specified file reference 'missingfile' could not be located"); + +} diff --git a/tests/python/ColorSpaceTest.py b/tests/python/ColorSpaceTest.py index 8cff13f0a5..11fe23c626 100644 --- a/tests/python/ColorSpaceTest.py +++ b/tests/python/ColorSpaceTest.py @@ -125,7 +125,7 @@ def test_config(self): Test the ColorSpace object from an OCIO config. """ - # Get simple config file from Constants.py + # Get simple config file from UnitTestUtils.py cfg = OCIO.Config().CreateFromStream(SIMPLE_CONFIG) # Test ColorSpace class object getters from config @@ -151,6 +151,7 @@ def test_constructor_with_keyword(self): # With keywords in their proper order. cs = OCIO.ColorSpace(name='test', family='ocio family', + encoding='scene-linear', equalityGroup='My_Equality', description='This is a test colourspace!', bitDepth=OCIO.BIT_DEPTH_F32, @@ -160,6 +161,7 @@ def test_constructor_with_keyword(self): self.assertEqual(cs.getName(), 'test') self.assertEqual(cs.getFamily(), 'ocio family') + self.assertEqual(cs.getEncoding(), 'scene-linear') self.assertEqual(cs.getEqualityGroup(), 'My_Equality') self.assertEqual(cs.getDescription(), 'This is a test colourspace!') self.assertEqual(cs.getBitDepth(), OCIO.BIT_DEPTH_F32) @@ -175,11 +177,13 @@ def test_constructor_with_keyword(self): allocation=OCIO.ALLOCATION_LG2, description='This is a test colourspace!', equalityGroup='My_Equality', + encoding='scene-linear', bitDepth=OCIO.BIT_DEPTH_F32, ) self.assertEqual(cs2.getName(), 'test') self.assertEqual(cs2.getFamily(), 'ocio family') + self.assertEqual(cs2.getEncoding(), 'scene-linear') self.assertEqual(cs2.getEqualityGroup(), 'My_Equality') self.assertEqual(cs2.getDescription(), 'This is a test colourspace!') self.assertEqual(cs2.getBitDepth(), OCIO.BIT_DEPTH_F32) @@ -195,6 +199,7 @@ def test_constructor_without_keyword(self): cs = OCIO.ColorSpace(OCIO.REFERENCE_SPACE_SCENE, 'test', 'ocio family', + 'scene-linear', 'My_Equality', 'This is a test colourspace!', OCIO.BIT_DEPTH_F32, @@ -204,6 +209,7 @@ def test_constructor_without_keyword(self): self.assertEqual(cs.getName(), 'test') self.assertEqual(cs.getFamily(), 'ocio family') + self.assertEqual(cs.getEncoding(), 'scene-linear') self.assertEqual(cs.getEqualityGroup(), 'My_Equality') self.assertEqual(cs.getDescription(), 'This is a test colourspace!') self.assertEqual(cs.getBitDepth(), OCIO.BIT_DEPTH_F32) @@ -221,6 +227,7 @@ def test_constructor_without_parameter(self): self.assertEqual(cs.getName(), '') self.assertEqual(cs.getFamily(), '') self.assertEqual(cs.getEqualityGroup(), '') + self.assertEqual(cs.getEncoding(), '') self.assertEqual(cs.getDescription(), '') self.assertEqual(cs.getBitDepth(), OCIO.BIT_DEPTH_UNKNOWN) self.assertFalse(cs.isData()) @@ -253,6 +260,15 @@ def test_description(self): self.colorspace.setDescription(desc) self.assertEqual(desc, self.colorspace.getDescription()) + def test_encoding(self): + """ + Test the setEncoding() and getEncoding() methods. + """ + + for name in TEST_NAMES: + self.colorspace.setEncoding(name) + self.assertEqual(name, self.colorspace.getEncoding()) + def test_equality(self): """ Test the setEqualityGroup() and getEqualityGroup() methods. diff --git a/tests/python/ColorSpaceTransformTest.py b/tests/python/ColorSpaceTransformTest.py new file mode 100644 index 0000000000..b8b4ca8fa6 --- /dev/null +++ b/tests/python/ColorSpaceTransformTest.py @@ -0,0 +1,137 @@ +# SPDX-License-Identifier: BSD-3-Clause +# Copyright Contributors to the OpenColorIO Project. + +import unittest +import os +import sys + +import PyOpenColorIO as OCIO + + +class ColorSpaceTransformTest(unittest.TestCase): + + TEST_COLORSPACE = ['abc', 'raw', '$test'] + + def test_constructor(self): + """ + Test ColorSpaceTransform constructor without and with keywords. + """ + ct = OCIO.ColorSpaceTransform() + self.assertEqual("", ct.getSrc()) + self.assertEqual("", ct.getDst()) + self.assertEqual(OCIO.TRANSFORM_DIR_FORWARD, ct.getDirection()) + self.assertEqual(True, ct.getDataBypass()) + + ct = OCIO.ColorSpaceTransform("src", "dst") + self.assertEqual("src", ct.getSrc()) + self.assertEqual("dst", ct.getDst()) + self.assertEqual(OCIO.TRANSFORM_DIR_FORWARD, ct.getDirection()) + self.assertEqual(True, ct.getDataBypass()) + + ct = OCIO.ColorSpaceTransform("src", "dst", OCIO.TRANSFORM_DIR_INVERSE) + self.assertEqual("src", ct.getSrc()) + self.assertEqual("dst", ct.getDst()) + self.assertEqual(OCIO.TRANSFORM_DIR_INVERSE, ct.getDirection()) + self.assertEqual(True, ct.getDataBypass()) + + ct = OCIO.ColorSpaceTransform("src", "dst", OCIO.TRANSFORM_DIR_INVERSE, False) + self.assertEqual("src", ct.getSrc()) + self.assertEqual("dst", ct.getDst()) + self.assertEqual(OCIO.TRANSFORM_DIR_INVERSE, ct.getDirection()) + self.assertEqual(False, ct.getDataBypass()) + + ct = OCIO.ColorSpaceTransform(src="src", dst="dst", dataBypass=False) + self.assertEqual("src", ct.getSrc()) + self.assertEqual("dst", ct.getDst()) + self.assertEqual(OCIO.TRANSFORM_DIR_FORWARD, ct.getDirection()) + self.assertEqual(False, ct.getDataBypass()) + + ct = OCIO.ColorSpaceTransform(src="src", dst="dst", + dir=OCIO.TRANSFORM_DIR_INVERSE, + dataBypass=False) + self.assertEqual("src", ct.getSrc()) + self.assertEqual("dst", ct.getDst()) + self.assertEqual(OCIO.TRANSFORM_DIR_INVERSE, ct.getDirection()) + self.assertEqual(False, ct.getDataBypass()) + + # Src & dst can't be omitted and can't be empty. + with self.assertRaises(OCIO.Exception): + ct = OCIO.ColorSpaceTransform(dst="dst") + with self.assertRaises(OCIO.Exception): + ct = OCIO.ColorSpaceTransform(src="src") + with self.assertRaises(OCIO.Exception): + ct = OCIO.ColorSpaceTransform(src="", dst="dst") + with self.assertRaises(OCIO.Exception): + ct = OCIO.ColorSpaceTransform(src="src", dst="") + with self.assertRaises(OCIO.Exception): + ct = OCIO.ColorSpaceTransform("src", "") + + def test_src(self): + """ + Test setSrc() and getSrc(). + """ + ct = OCIO.ColorSpaceTransform() + for src in self.TEST_COLORSPACE: + ct.setSrc(src) + self.assertEqual(src, ct.getSrc()) + + def test_dst(self): + """ + Test setDst() and getDst(). + """ + ct = OCIO.ColorSpaceTransform() + for dst in self.TEST_COLORSPACE: + ct.setDst(dst) + self.assertEqual(dst, ct.getDst()) + + def test_data_bypass(self): + """ + Test setDataBypass() and getDataBypass(). + """ + ct = OCIO.ColorSpaceTransform() + ct.setDataBypass(False) + self.assertEqual(False, ct.getDataBypass()) + ct.setDataBypass(True) + self.assertEqual(True, ct.getDataBypass()) + + def test_direction(self): + """ + Test the setDirection() and getDirection() methods. + """ + + ct = OCIO.ColorSpaceTransform() + for direction in OCIO.TransformDirection.__members__.values(): + # Setting the unknown direction preserves the current direction. + if direction != OCIO.TRANSFORM_DIR_UNKNOWN: + ct.setDirection(direction) + self.assertEqual(direction, ct.getDirection()) + + def test_validate(self): + """ + Test the validate(). + """ + ct = OCIO.ColorSpaceTransform() + ct.setSrc("src") + ct.setDst("dst") + ct.validate() + + # Src has to be non-empty. + ct.setSrc("") + with self.assertRaises(OCIO.Exception): + ct.validate() + ct.setSrc("src") + + # Dst has to be non-empty. + ct.setDst("") + with self.assertRaises(OCIO.Exception): + ct.validate() + ct.setDst("dst") + + # Direction can't be unknown. + for direction in OCIO.TransformDirection.__members__.values(): + ct.setDirection(direction) + if direction != OCIO.TRANSFORM_DIR_UNKNOWN: + self.assertIsNone(ct.validate()) + else: + with self.assertRaises(OCIO.Exception): + ct.validate() diff --git a/tests/python/ConfigTest.py b/tests/python/ConfigTest.py index a2c80b22e9..16258165ee 100644 --- a/tests/python/ConfigTest.py +++ b/tests/python/ConfigTest.py @@ -1,28 +1,420 @@ # SPDX-License-Identifier: BSD-3-Clause # Copyright Contributors to the OpenColorIO Project. -import unittest, os, sys +import unittest +import os +import sys + import PyOpenColorIO as OCIO +from UnitTestUtils import TEST_DATAFILES_DIR, TEST_NAMES, TEST_DESCS -import platform -osname = platform.system() +# Legacy tests kept for reference. +# +#class ConfigTest(unittest.TestCase): +# +# SIMPLE_PROFILE = """ocio_profile_version: 1 +# +#search_path: luts +#strictparsing: false +#luma: [0.2126, 0.7152, 0.0722] +# +#roles: +# default: raw +# scene_linear: lnh +# +#displays: +# sRGB: +# - ! {name: Film1D, colorspace: vd8} +# - ! {name: Raw, colorspace: raw} +# +#active_displays: [] +#active_views: [] +# +#colorspaces: +# - ! +# name: raw +# family: raw +# equalitygroup: "" +# bitdepth: 32f +# description: | +# A raw color space. Conversions to and from this space are no-ops. +# +# isdata: true +# allocation: uniform +# +# - ! +# name: lnh +# family: ln +# equalitygroup: "" +# bitdepth: 16f +# description: | +# The show reference space. This is a sensor referred linear +# representation of the scene with primaries that correspond to +# scanned film. 0.18 in this space corresponds to a properly +# exposed 18% grey card. +# +# isdata: false +# allocation: lg2 +# +# - ! +# name: vd8 +# family: vd8 +# equalitygroup: "" +# bitdepth: 8ui +# description: | +# how many transforms can we use? +# +# isdata: false +# allocation: uniform +# to_reference: ! +# children: +# - ! {value: 2.2} +# - ! {matrix: [1, 2, 3, 4, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1], offset: [1, 2, 0, 0]} +# - ! {slope: [0.9, 1, 1], offset: [0.1, 0.3, 0.4], power: [1.1, 1.1, 1.1], sat: 0.9} +#""" +# +# def setUp(self): +# +# osx_hack = '' +# if osname=="Darwin": +# osx_hack = """ +#// OSX segfault work-around: Force a no-op sampling of the 3D LUT. +#texture3D(lut3d, 0.96875 * out_pixel.rgb + 0.015625).rgb;""" +# +# self.GLSLResult = """ +#// Generated by OpenColorIO +# +#vec4 pytestocio(in vec4 inPixel, +# const sampler3D lut3d) +#{ +#vec4 out_pixel = inPixel; +#out_pixel = out_pixel * mat4(1.0874889, -0.079466686, -0.0080222245, 0., -0.023622228, 1.0316445, -0.0080222245, 0., -0.023622226, -0.079466686, 1.1030889, 0., 0., 0., 0., 1.); +#out_pixel = pow(max(out_pixel, vec4(0., 0., 0., 0.)), vec4(0.90909088, 0.90909088, 0.90909088, 1.)); +#out_pixel = out_pixel * mat4(1.1111112, -2., -3., -4., 0., 1., 0., 0., 0., 0., 1., 0., 0., 0., 0., 1.); +#out_pixel = vec4(4.688889, -2.3, -0.40000001, -0.) + out_pixel; +#out_pixel = pow(max(out_pixel, vec4(0., 0., 0., 0.)), vec4(0.45454544, 0.45454544, 0.45454544, 1.));""" \ +# + osx_hack + \ +#""" +#return out_pixel; +#} +# +#""" +# +# def test_is_editable(self): +# +# cfg = OCIO.Config().CreateFromStream(self.SIMPLE_PROFILE) +# self.assertEqual(cfg.isEditable(), False) +# cfg = cfg.createEditableCopy() +# self.assertEqual(cfg.isEditable(), True) +# ctx = cfg.getCurrentContext() +# self.assertEqual(ctx.isEditable(), False) +# ctx = ctx.createEditableCopy() +# self.assertEqual(ctx.isEditable(), True) +# ctx.setEnvironmentMode(OCIO.ENV_ENVIRONMENT_LOAD_ALL) +# +# def test_interface(self): +# +# _cfge = OCIO.Config().CreateFromStream(self.SIMPLE_PROFILE) +# _cfge.clearEnvironmentVars() +# self.assertEqual(0, _cfge.getNumEnvironmentVars()) +# _cfge.addEnvironmentVar("FOO", "test1") +# _cfge.addEnvironmentVar("FOO2", "test2${FOO}") +# self.assertEqual(2, _cfge.getNumEnvironmentVars()) +# self.assertEqual("FOO", _cfge.getEnvironmentVarNameByIndex(0)) +# self.assertEqual("FOO2", _cfge.getEnvironmentVarNameByIndex(1)) +# self.assertEqual("test1", _cfge.getEnvironmentVarDefault("FOO")) +# self.assertEqual("test2${FOO}", _cfge.getEnvironmentVarDefault("FOO2")) +# self.assertEqual("test2test1", _cfge.getCurrentContext().resolveStringVar("${FOO2}")) +# self.assertEqual({'FOO': 'test1', 'FOO2': 'test2${FOO}'}, _cfge.getEnvironmentVarDefaults()) +# _cfge.clearEnvironmentVars() +# self.assertEqual(0, _cfge.getNumEnvironmentVars()) +# self.assertEqual("luts", _cfge.getSearchPath()) +# _cfge.setSearchPath("otherdir") +# self.assertEqual("otherdir", _cfge.getSearchPath()) +# _cfge.sanityCheck() +# _cfge.setDescription("testdesc") +# self.assertEqual("testdesc", _cfge.getDescription()) +# self.assertEqual(self.SIMPLE_PROFILE, _cfg.serialize()) +# #self.assertEqual("$07d1fb1509eeae1837825fd4242f8a69:$885ad1683add38a11f7bbe34e8bf9ac0", +# # _cfg.getCacheID()) +# con = _cfge.getCurrentContext() +# self.assertNotEqual(0, con.getNumStringVars()) +# _cfge.setWorkingDir("/foobar") +# self.assertEqual("/foobar", _cfge.getWorkingDir()) +# self.assertEqual(3, _cfge.getNumColorSpaces()) +# self.assertEqual("lnh", _cfge.getColorSpaceNameByIndex(1)) +# lnh = _cfge.getColorSpace("lnh") +# self.assertEqual("ln", lnh.getFamily()) +# self.assertEqual(-1, _cfge.getIndexForColorSpace("foobar")) +# cs = OCIO.ColorSpace() +# cs.setName("blah") +# _cfge.addColorSpace(cs) +# self.assertEqual(3, _cfge.getIndexForColorSpace("blah")) +# #_cfge.clearColorSpaces() +# #_cfge.parseColorSpaceFromString("foo") +# self.assertEqual(False, _cfg.isStrictParsingEnabled()) +# _cfge.setStrictParsingEnabled(True) +# self.assertEqual(True, _cfge.isStrictParsingEnabled()) +# self.assertEqual(2, _cfge.getNumRoles()) +# self.assertEqual(False, _cfg.hasRole("foo")) +# _cfge.setRole("foo", "vd8") +# self.assertEqual(3, _cfge.getNumRoles()) +# self.assertEqual(True, _cfge.hasRole("foo")) +# self.assertEqual("foo", _cfge.getRoleName(1)) +# self.assertEqual("sRGB", _cfge.getDefaultDisplay()) +# self.assertEqual(1, _cfge.getNumDisplays()) +# self.assertEqual("sRGB", _cfge.getDisplay(0)) +# self.assertEqual("Film1D", _cfge.getDefaultView("sRGB")) +# self.assertEqual(2, _cfge.getNumViews("sRGB")) +# self.assertEqual("Raw", _cfge.getView("sRGB", 1)) +# self.assertEqual("vd8", _cfge.getDisplayColorSpaceName("sRGB", "Film1D")) +# self.assertEqual("", _cfg.getDisplayLooks("sRGB", "Film1D")) +# _cfge.addDisplay("foo", "bar", "foo", "wee") +# _cfge.clearDisplays() +# _cfge.setActiveDisplays("sRGB") +# self.assertEqual("sRGB", _cfge.getActiveDisplays()) +# _cfge.setActiveViews("Film1D") +# self.assertEqual("Film1D", _cfge.getActiveViews()) +# luma = _cfge.getDefaultLumaCoefs() +# self.assertAlmostEqual(0.2126, luma[0], delta=1e-8) +# _cfge.setDefaultLumaCoefs([0.1, 0.2, 0.3]) +# tnewluma = _cfge.getDefaultLumaCoefs() +# self.assertAlmostEqual(0.1, tnewluma[0], delta=1e-8) +# self.assertEqual(0, _cfge.getNumLooks()) +# lk = OCIO.Look() +# lk.setName("coollook") +# lk.setProcessSpace("somespace") +# et = OCIO.ExponentTransform() +# et.setValue([0.1, 0.2, 0.3, 0.4]) +# lk.setTransform(et) +# iet = OCIO.ExponentTransform() +# iet.setValue([-0.1, -0.2, -0.3, -0.4]) +# lk.setInverseTransform(iet) +# _cfge.addLook(lk) +# self.assertEqual(1, _cfge.getNumLooks()) +# self.assertEqual("coollook", _cfge.getLookNameByIndex(0)) +# glk = _cfge.getLook("coollook") +# self.assertEqual("somespace", glk.getProcessSpace()) +# _cfge.clearLooks() +# self.assertEqual(0, _cfge.getNumLooks()) +# +# #getProcessor(context, srcColorSpace, dstColorSpace) +# #getProcessor(context, srcName,dstName); +# #getProcessor(transform); +# #getProcessor(transform, direction); +# #getProcessor(context, transform, direction); +# +# _proc = _cfg.getProcessor("lnh", "vd8") +# self.assertEqual(False, _proc.isNoOp()) +# self.assertEqual(True, _proc.hasChannelCrosstalk()) +# +# #float packedpix[] = new float[]{0.48f, 0.18f, 0.9f, 1.0f, +# # 0.48f, 0.18f, 0.18f, 1.0f, +# # 0.48f, 0.18f, 0.18f, 1.0f, +# # 0.48f, 0.18f, 0.18f, 1.0f }; +# #FloatBuffer buf = ByteBuffer.allocateDirect(2 * 2 * 4 * Float.SIZE / 8).asFloatBuffer(); +# #buf.put(packedpix); +# #PackedImageDesc foo = new PackedImageDesc(buf, 2, 2, 4); +# #_proc.apply(foo); +# #FloatBuffer wee = foo.getData(); +# #self.assertEqual(-2.4307251581696764E-35f, wee.get(2), 1e-8); +# +# # TODO: these should work in-place +# rgbfoo = _proc.applyRGB([0.48, 0.18, 0.18]) +# self.assertAlmostEqual(1.9351077, rgbfoo[0], delta=1e-7); +# # TODO: these should work in-place +# rgbafoo = _proc.applyRGBA([0.48, 0.18, 0.18, 1.0]) +# self.assertAlmostEqual(1.0, rgbafoo[3], delta=1e-8) +# #self.assertEqual("$a92ef63abd9edf61ad5a7855da064648", _proc.getCpuCacheID()) +# +# _cfge.clearSearchPaths() +# self.assertEqual(0, _cfge.getNumSearchPaths()) +# _cfge.addSearchPath("First/ Path") +# self.assertEqual(1, _cfge.getNumSearchPaths()) +# _cfge.addSearchPath("D:\\Second\\Path\\") +# self.assertEqual(2, _cfge.getNumSearchPaths()) +# self.assertEqual("First/ Path", _cfge.getSearchPathByIndex(0)) +# self.assertEqual("D:\\Second\\Path\\", _cfge.getSearchPathByIndex(1)) +# +# del _cfge +# del _cfg class ConfigTest(unittest.TestCase): - SIMPLE_PROFILE = """ocio_profile_version: 1 + def test_shared_views(self): + # Test these Config functions: addSharedView, getSharedViews, removeSharedView. + + cfg = OCIO.Config().CreateRaw() + views = cfg.getSharedViews() + self.assertEqual(0, len(views)) + + # Shared view has to have a name. + with self.assertRaises(OCIO.Exception): + cfg.addSharedView(view='', + viewTransformName='', + colorSpaceName='c1', + looks='', + ruleName='', + description='') + # Shared view has to have a color space name. + with self.assertRaises(OCIO.Exception): + cfg.addSharedView(view='view1', + viewTransformName='', + colorSpaceName='', + looks='', + ruleName='', + description='') + cfg.addSharedView(view='view1', + viewTransformName='', + colorSpaceName='c1', + looks='', + ruleName='', + description='') + cfg.addSharedView(view='view2', + colorSpaceName='c2', + viewTransformName='t2', + looks='', + ruleName='', + description='') + cfg.addSharedView(view='view3', + colorSpaceName='c3', + looks='l3', + viewTransformName='', + ruleName='', + description='') + cfg.addSharedView(view='view4', + colorSpaceName='c4', + ruleName='r4', + looks='', + viewTransformName='', + description='') + cfg.addSharedView(view='view5', + colorSpaceName='c5', + ruleName='', + looks='', + viewTransformName='', + description='description 5') + cfg.addSharedView('view6', 't6', 'c6', 'l6','r6', 'desc6') + views = cfg.getSharedViews() + self.assertEqual(6, len(views)) + self.assertEqual('view1', next(views)) + self.assertEqual('view2', next(views)) + self.assertEqual('view3', next(views)) + self.assertEqual('view4', next(views)) + self.assertEqual('view5', next(views)) + self.assertEqual('view6', next(views)) + + self.assertEqual('', cfg.getDisplayViewTransformName('', 'view1')) + self.assertEqual('t2', cfg.getDisplayViewTransformName('', 'view2')) + self.assertEqual('', cfg.getDisplayViewTransformName('', 'view3')) + self.assertEqual('', cfg.getDisplayViewTransformName('', 'view4')) + self.assertEqual('', cfg.getDisplayViewTransformName('', 'view5')) + self.assertEqual('t6', cfg.getDisplayViewTransformName('', 'view6')) + + self.assertEqual('c1', cfg.getDisplayViewColorSpaceName('', 'view1')) + self.assertEqual('c2', cfg.getDisplayViewColorSpaceName('', 'view2')) + self.assertEqual('c3', cfg.getDisplayViewColorSpaceName('', 'view3')) + self.assertEqual('c4', cfg.getDisplayViewColorSpaceName('', 'view4')) + self.assertEqual('c5', cfg.getDisplayViewColorSpaceName('', 'view5')) + self.assertEqual('c6', cfg.getDisplayViewColorSpaceName('', 'view6')) + + self.assertEqual('', cfg.getDisplayViewLooks('', 'view1')) + self.assertEqual('', cfg.getDisplayViewLooks('', 'view2')) + self.assertEqual('l3', cfg.getDisplayViewLooks('', 'view3')) + self.assertEqual('', cfg.getDisplayViewLooks('', 'view4')) + self.assertEqual('', cfg.getDisplayViewLooks('', 'view5')) + self.assertEqual('l6', cfg.getDisplayViewLooks('', 'view6')) + + self.assertEqual('', cfg.getDisplayViewRule('', 'view1')) + self.assertEqual('', cfg.getDisplayViewRule('', 'view2')) + self.assertEqual('', cfg.getDisplayViewRule('', 'view3')) + self.assertEqual('r4', cfg.getDisplayViewRule('', 'view4')) + self.assertEqual('', cfg.getDisplayViewRule('', 'view5')) + self.assertEqual('r6', cfg.getDisplayViewRule('', 'view6')) + + self.assertEqual('', cfg.getDisplayViewDescription('', 'view1')) + self.assertEqual('', cfg.getDisplayViewDescription('', 'view2')) + self.assertEqual('', cfg.getDisplayViewDescription('', 'view3')) + self.assertEqual('', cfg.getDisplayViewDescription('', 'view4')) + self.assertEqual('description 5', cfg.getDisplayViewDescription('', 'view5')) + self.assertEqual('desc6', cfg.getDisplayViewDescription('', 'view6')) + + # Adding a shared view using an existing name is replacing the existing view. + cfg.addSharedView(view='view3', + colorSpaceName='c3 new', + looks='l3 new', + viewTransformName='t3 new', + ruleName='r3 new', + description='desc3 new') + views = cfg.getSharedViews() + self.assertEqual(6, len(views)) + self.assertEqual('t3 new', cfg.getDisplayViewTransformName('', 'view3')) + self.assertEqual('c3 new', cfg.getDisplayViewColorSpaceName('', 'view3')) + self.assertEqual('l3 new', cfg.getDisplayViewLooks('', 'view3')) + self.assertEqual('r3 new', cfg.getDisplayViewRule('', 'view3')) + self.assertEqual('desc3 new', cfg.getDisplayViewDescription('', 'view3')) + + # Remove shared views. + + # View has to exist. + with self.assertRaises(OCIO.Exception): + cfg.removeSharedView('unknown view') -search_path: luts -strictparsing: false + # Existing views can be removed. + cfg.removeSharedView('view3') + views = cfg.getSharedViews() + self.assertEqual(5, len(views)) + cfg.removeSharedView('view4') + cfg.removeSharedView('view5') + cfg.removeSharedView('view6') + cfg.removeSharedView('view1') + cfg.removeSharedView('view2') + views = cfg.getSharedViews() + self.assertEqual(0, len(views)) + + def test_ruled_views(self): + # Test these Config functions: getDisplays, getViews, removeDisplayView + + SIMPLE_PROFILE = """ocio_profile_version: 2 + +search_path: "" +strictparsing: true luma: [0.2126, 0.7152, 0.0722] roles: default: raw - scene_linear: lnh + scene_linear: c3 + +file_rules: + - ! {name: ColorSpaceNamePathSearch} + - ! {name: Default, colorspace: raw} + +viewing_rules: + - ! {name: Rule_1, colorspaces: c1} + - ! {name: Rule_2, colorspaces: [c2, c3]} + - ! {name: Rule_3, colorspaces: scene_linear} + - ! {name: Rule_4, colorspaces: [c3, c4]} + - ! {name: Rule_5, encodings: log} + - ! {name: Rule_6, encodings: [log, video]} + +shared_views: + - ! {name: SView_a, colorspace: raw, rule: Rule_2} + - ! {name: SView_b, colorspace: raw, rule: Rule_3} + - ! {name: SView_c, colorspace: raw} + - ! {name: SView_d, colorspace: raw, rule: Rule_5} + - ! {name: SView_e, colorspace: raw} displays: sRGB: - - ! {name: Film1D, colorspace: vd8} - - ! {name: Raw, colorspace: raw} + - ! {name: View_a, colorspace: raw, rule: Rule_1} + - ! {name: View_b, colorspace: raw, rule: Rule_2} + - ! {name: View_c, colorspace: raw, rule: Rule_2} + - ! {name: View_d, colorspace: raw, rule: Rule_3} + - ! {name: View_e, colorspace: raw, rule: Rule_4} + - ! {name: View_f, colorspace: raw, rule: Rule_5} + - ! {name: View_g, colorspace: raw, rule: Rule_6} + - ! {name: View_h, colorspace: raw} + - ! [SView_a, SView_b, SView_d, SView_e] active_displays: [] active_views: [] @@ -30,208 +422,156 @@ class ConfigTest(unittest.TestCase): colorspaces: - ! name: raw - family: raw + family: "" + equalitygroup: "" + bitdepth: unknown + isdata: false + allocation: uniform + + - ! + name: c1 + family: "" equalitygroup: "" - bitdepth: 32f - description: | - A raw color space. Conversions to and from this space are no-ops. + bitdepth: unknown + isdata: false + encoding: video + allocation: uniform - isdata: true + - ! + name: c2 + family: "" + equalitygroup: "" + bitdepth: unknown + isdata: false allocation: uniform - ! - name: lnh - family: ln + name: c3 + family: "" equalitygroup: "" - bitdepth: 16f - description: | - The show reference space. This is a sensor referred linear - representation of the scene with primaries that correspond to - scanned film. 0.18 in this space corresponds to a properly - exposed 18% grey card. + bitdepth: unknown + isdata: false + allocation: uniform + - ! + name: c4 + family: "" + equalitygroup: "" + bitdepth: unknown isdata: false - allocation: lg2 + encoding: log + allocation: uniform - ! - name: vd8 - family: vd8 + name: c5 + family: "" equalitygroup: "" - bitdepth: 8ui - description: | - how many transforms can we use? + bitdepth: unknown + isdata: false + encoding: data + allocation: uniform + - ! + name: c6 + family: "" + equalitygroup: "" + bitdepth: unknown isdata: false + encoding: video allocation: uniform - to_reference: ! - children: - - ! {value: 2.2} - - ! {matrix: [1, 2, 3, 4, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1], offset: [1, 2, 0, 0]} - - ! {slope: [0.9, 1, 1], offset: [0.1, 0.3, 0.4], power: [1.1, 1.1, 1.1], sat: 0.9} """ + # Create a config. + cfg = OCIO.Config().CreateFromStream(SIMPLE_PROFILE) + # Check number of displays. + displays = cfg.getDisplays() + self.assertEqual(1, len(displays)) + # Add a view in a new display. + cfg.addDisplayView('otherDisplay', 'otherView', 'c6', '') + # Check there is a new display and check view. + displays = cfg.getDisplays() + self.assertEqual(2, len(displays)) + self.assertEqual('sRGB', next(displays)) + self.assertEqual('otherDisplay', next(displays)) + views = cfg.getViews('otherDisplay') + self.assertEqual(1, len(views)) + self.assertEqual('otherView', next(views)) + # Parameter case does not matter. + views = cfg.getViews('oTHerdISplay') + self.assertEqual(1, len(views)) + # Add a shared view to the new display. + cfg.addDisplaySharedView('otherDisplay', 'SView_a') + views = cfg.getViews('otherDisplay') + self.assertEqual(2, len(views)) + self.assertEqual('otherView', next(views)) + self.assertEqual('SView_a', next(views)) + # Remove the views (and the display). + cfg.removeDisplayView('otherDisplay', 'otherView') + displays = cfg.getDisplays() + self.assertEqual(2, len(displays)) + cfg.removeDisplayView('otherDisplay', 'SView_a') + displays = cfg.getDisplays() + self.assertEqual(1, len(displays)) - def setUp(self): - - osx_hack = '' - if osname=="Darwin": - osx_hack = """ -// OSX segfault work-around: Force a no-op sampling of the 3D LUT. -texture3D(lut3d, 0.96875 * out_pixel.rgb + 0.015625).rgb;""" - - self.GLSLResult = """ -// Generated by OpenColorIO - -vec4 pytestocio(in vec4 inPixel, - const sampler3D lut3d) -{ -vec4 out_pixel = inPixel; -out_pixel = out_pixel * mat4(1.0874889, -0.079466686, -0.0080222245, 0., -0.023622228, 1.0316445, -0.0080222245, 0., -0.023622226, -0.079466686, 1.1030889, 0., 0., 0., 0., 1.); -out_pixel = pow(max(out_pixel, vec4(0., 0., 0., 0.)), vec4(0.90909088, 0.90909088, 0.90909088, 1.)); -out_pixel = out_pixel * mat4(1.1111112, -2., -3., -4., 0., 1., 0., 0., 0., 0., 1., 0., 0., 0., 0., 1.); -out_pixel = vec4(4.688889, -2.3, -0.40000001, -0.) + out_pixel; -out_pixel = pow(max(out_pixel, vec4(0., 0., 0., 0.)), vec4(0.45454544, 0.45454544, 0.45454544, 1.));""" \ - + osx_hack + \ -""" -return out_pixel; -} + # Check shared views defined by config. + views = cfg.getSharedViews() + self.assertEqual(5, len(views)) + self.assertEqual('SView_a', next(views)) + self.assertEqual('SView_b', next(views)) + self.assertEqual('SView_c', next(views)) + self.assertEqual('SView_d', next(views)) + self.assertEqual('SView_e', next(views)) -""" + # Check views for sRGB display. + views = cfg.getViews('sRGB') + self.assertEqual(12, len(views)) + + # Active views are taken into account for getViews. + cfg.setActiveViews('View_a, View_b, SView_a, SView_b') + views = cfg.getViews('sRGB') + self.assertEqual(4, len(views)) + cfg.setActiveViews('') + + # Views filtered by viewing rules. + views = cfg.getViews('sRGB', 'c3') + self.assertEqual(8, len(views)) + # View_b rule is Rule_2 that lists c3. + self.assertEqual('View_b', next(views)) + # View_c rule is Rule_2 that lists c3. + self.assertEqual('View_c', next(views)) + # View_d rule is Rule_3 that lists c3. + self.assertEqual('View_d', next(views)) + #/ View_e rule is Rule_4 that lists c3. + self.assertEqual('View_e', next(views)) + # View_h has no rule. + self.assertEqual('View_h', next(views)) + # SView_a has rule Rule_2 that lists c3. + self.assertEqual('SView_a', next(views)) + # SView_b has rule Rule_3 that lists c3. + self.assertEqual('SView_b', next(views)) + # SView_e has no rule. + self.assertEqual('SView_e', next(views)) + + views = cfg.getViews('sRGB', 'c4') + self.assertEqual(6, len(views)) + # View_e rule is Rule_4 that lists c4. + self.assertEqual('View_e', next(views)) + # View_f rule is Rule_5 that lists encoding log, c4 has encoding log. + self.assertEqual('View_f', next(views)) + # View_g rule is Rule_6 that lists encoding log, c4 has encoding log. + self.assertEqual('View_g', next(views)) + # View_h has no rule. + self.assertEqual('View_h', next(views)) + # SView_d rule is Rule_5 that lists encoding log, c4 has encoding log. + self.assertEqual('SView_d', next(views)) + # SView_e has no rule. + self.assertEqual('SView_e', next(views)) + + views = cfg.getViews('sRGB', 'c6') + self.assertEqual(3, len(views)) + # View_g rule is Rule_6 that lists encoding video, c6 has encoding video. + self.assertEqual('View_g', next(views)) + # View_h has no rule. + self.assertEqual('View_h', next(views)) + # SView_e has no rule. + self.assertEqual('SView_e', next(views)) - def test_is_editable(self): - - cfg = OCIO.Config().CreateFromStream(self.SIMPLE_PROFILE) - self.assertEqual(cfg.isEditable(), False) - cfg = cfg.createEditableCopy() - self.assertEqual(cfg.isEditable(), True) - ctx = cfg.getCurrentContext() - self.assertEqual(ctx.isEditable(), False) - ctx = ctx.createEditableCopy() - self.assertEqual(ctx.isEditable(), True) - ctx.setEnvironmentMode(OCIO.ENV_ENVIRONMENT_LOAD_ALL) - - def test_interface(self): - - _cfge = OCIO.Config().CreateFromStream(self.SIMPLE_PROFILE) - _cfge.clearEnvironmentVars() - self.assertEqual(0, _cfge.getNumEnvironmentVars()) - _cfge.addEnvironmentVar("FOO", "test1") - _cfge.addEnvironmentVar("FOO2", "test2${FOO}") - self.assertEqual(2, _cfge.getNumEnvironmentVars()) - self.assertEqual("FOO", _cfge.getEnvironmentVarNameByIndex(0)) - self.assertEqual("FOO2", _cfge.getEnvironmentVarNameByIndex(1)) - self.assertEqual("test1", _cfge.getEnvironmentVarDefault("FOO")) - self.assertEqual("test2${FOO}", _cfge.getEnvironmentVarDefault("FOO2")) - self.assertEqual("test2test1", _cfge.getCurrentContext().resolveStringVar("${FOO2}")) - self.assertEqual({'FOO': 'test1', 'FOO2': 'test2${FOO}'}, _cfge.getEnvironmentVarDefaults()) - _cfge.clearEnvironmentVars() - self.assertEqual(0, _cfge.getNumEnvironmentVars()) - self.assertEqual("luts", _cfge.getSearchPath()) - _cfge.setSearchPath("otherdir") - self.assertEqual("otherdir", _cfge.getSearchPath()) - _cfge.sanityCheck() - _cfge.setDescription("testdesc") - self.assertEqual("testdesc", _cfge.getDescription()) - self.assertEqual(self.SIMPLE_PROFILE, _cfg.serialize()) - #self.assertEqual("$07d1fb1509eeae1837825fd4242f8a69:$885ad1683add38a11f7bbe34e8bf9ac0", - # _cfg.getCacheID()) - con = _cfge.getCurrentContext() - self.assertNotEqual(0, con.getNumStringVars()) - _cfge.setWorkingDir("/foobar") - self.assertEqual("/foobar", _cfge.getWorkingDir()) - self.assertEqual(3, _cfge.getNumColorSpaces()) - self.assertEqual("lnh", _cfge.getColorSpaceNameByIndex(1)) - lnh = _cfge.getColorSpace("lnh") - self.assertEqual("ln", lnh.getFamily()) - self.assertEqual(-1, _cfge.getIndexForColorSpace("foobar")) - cs = OCIO.ColorSpace() - cs.setName("blah") - _cfge.addColorSpace(cs) - self.assertEqual(3, _cfge.getIndexForColorSpace("blah")) - #_cfge.clearColorSpaces() - #_cfge.parseColorSpaceFromString("foo") - self.assertEqual(False, _cfg.isStrictParsingEnabled()) - _cfge.setStrictParsingEnabled(True) - self.assertEqual(True, _cfge.isStrictParsingEnabled()) - self.assertEqual(2, _cfge.getNumRoles()) - self.assertEqual(False, _cfg.hasRole("foo")) - _cfge.setRole("foo", "vd8") - self.assertEqual(3, _cfge.getNumRoles()) - self.assertEqual(True, _cfge.hasRole("foo")) - self.assertEqual("foo", _cfge.getRoleName(1)) - self.assertEqual("sRGB", _cfge.getDefaultDisplay()) - self.assertEqual(1, _cfge.getNumDisplays()) - self.assertEqual("sRGB", _cfge.getDisplay(0)) - self.assertEqual("Film1D", _cfge.getDefaultView("sRGB")) - self.assertEqual(2, _cfge.getNumViews("sRGB")) - self.assertEqual("Raw", _cfge.getView("sRGB", 1)) - self.assertEqual("vd8", _cfge.getDisplayColorSpaceName("sRGB", "Film1D")) - self.assertEqual("", _cfg.getDisplayLooks("sRGB", "Film1D")) - _cfge.addDisplay("foo", "bar", "foo", "wee") - _cfge.clearDisplays() - _cfge.setActiveDisplays("sRGB") - self.assertEqual("sRGB", _cfge.getActiveDisplays()) - _cfge.setActiveViews("Film1D") - self.assertEqual("Film1D", _cfge.getActiveViews()) - luma = _cfge.getDefaultLumaCoefs() - self.assertAlmostEqual(0.2126, luma[0], delta=1e-8) - _cfge.setDefaultLumaCoefs([0.1, 0.2, 0.3]) - tnewluma = _cfge.getDefaultLumaCoefs() - self.assertAlmostEqual(0.1, tnewluma[0], delta=1e-8) - self.assertEqual(0, _cfge.getNumLooks()) - lk = OCIO.Look() - lk.setName("coollook") - lk.setProcessSpace("somespace") - et = OCIO.ExponentTransform() - et.setValue([0.1, 0.2, 0.3, 0.4]) - lk.setTransform(et) - iet = OCIO.ExponentTransform() - iet.setValue([-0.1, -0.2, -0.3, -0.4]) - lk.setInverseTransform(iet) - _cfge.addLook(lk) - self.assertEqual(1, _cfge.getNumLooks()) - self.assertEqual("coollook", _cfge.getLookNameByIndex(0)) - glk = _cfge.getLook("coollook") - self.assertEqual("somespace", glk.getProcessSpace()) - _cfge.clearLooks() - self.assertEqual(0, _cfge.getNumLooks()) - - #getProcessor(context, srcColorSpace, dstColorSpace) - #getProcessor(context, srcName,dstName); - #getProcessor(transform); - #getProcessor(transform, direction); - #getProcessor(context, transform, direction); - - _proc = _cfg.getProcessor("lnh", "vd8") - self.assertEqual(False, _proc.isNoOp()) - self.assertEqual(True, _proc.hasChannelCrosstalk()) - - #float packedpix[] = new float[]{0.48f, 0.18f, 0.9f, 1.0f, - # 0.48f, 0.18f, 0.18f, 1.0f, - # 0.48f, 0.18f, 0.18f, 1.0f, - # 0.48f, 0.18f, 0.18f, 1.0f }; - #FloatBuffer buf = ByteBuffer.allocateDirect(2 * 2 * 4 * Float.SIZE / 8).asFloatBuffer(); - #buf.put(packedpix); - #PackedImageDesc foo = new PackedImageDesc(buf, 2, 2, 4); - #_proc.apply(foo); - #FloatBuffer wee = foo.getData(); - #self.assertEqual(-2.4307251581696764E-35f, wee.get(2), 1e-8); - - # TODO: these should work in-place - rgbfoo = _proc.applyRGB([0.48, 0.18, 0.18]) - self.assertAlmostEqual(1.9351077, rgbfoo[0], delta=1e-7); - # TODO: these should work in-place - rgbafoo = _proc.applyRGBA([0.48, 0.18, 0.18, 1.0]) - self.assertAlmostEqual(1.0, rgbafoo[3], delta=1e-8) - #self.assertEqual("$a92ef63abd9edf61ad5a7855da064648", _proc.getCpuCacheID()) - - _cfge.clearSearchPaths() - self.assertEqual(0, _cfge.getNumSearchPaths()) - _cfge.addSearchPath("First/ Path") - self.assertEqual(1, _cfge.getNumSearchPaths()) - _cfge.addSearchPath("D:\\Second\\Path\\") - self.assertEqual(2, _cfge.getNumSearchPaths()) - self.assertEqual("First/ Path", _cfge.getSearchPathByIndex(0)) - self.assertEqual("D:\\Second\\Path\\", _cfge.getSearchPathByIndex(1)) - - del _cfge - del _cfg diff --git a/tests/python/DisplayViewTransformTest.py b/tests/python/DisplayViewTransformTest.py new file mode 100644 index 0000000000..e5af7244c4 --- /dev/null +++ b/tests/python/DisplayViewTransformTest.py @@ -0,0 +1,222 @@ +# SPDX-License-Identifier: BSD-3-Clause +# Copyright Contributors to the OpenColorIO Project. + +import unittest +import os +import sys + +import PyOpenColorIO as OCIO +from UnitTestUtils import TEST_DATAFILES_DIR, TEST_NAMES, TEST_DESCS + + +class DisplayViewTransformTest(unittest.TestCase): + + TEST_SRC = ['abc', 'raw', '$test'] + TEST_DISPLAY = ['display1', 'display2'] + TEST_VIEW = ['view1', 'view2', 'film'] + + def setUp(self): + self.dv_tr = OCIO.DisplayViewTransform() + + def tearDown(self): + self.dv_tr = None + + def test_src(self): + """ + Test the setSrc() and getSrc() methods. + """ + + # Default initialized src value is "". + self.assertEqual('', self.dv_tr.getSrc()) + + # Test src setter and getter. + for src in self.TEST_SRC: + self.dv_tr.setSrc(src) + self.assertEqual(src, self.dv_tr.getSrc()) + + def test_display(self): + """ + Test the setDisplay() and getDisplay() methods. + """ + + # Default initialized display value is "" + self.assertEqual('', self.dv_tr.getDisplay()) + + # Test display setter and getter. + for display in self.TEST_DISPLAY: + self.dv_tr.setDisplay(display) + self.assertEqual(display, self.dv_tr.getDisplay()) + + def test_view(self): + """ + Test the setView() and getView() methods. + """ + + # Default initialized view value is "". + self.assertEqual('', self.dv_tr.getView()) + + # Test view setter and getter. + for view in self.TEST_VIEW: + self.dv_tr.setView(view) + self.assertEqual(view, self.dv_tr.getView()) + + def test_looksBypass(self): + """ + Test the setLooksBypass() and getLooksBypass() methods. + """ + + # Default initialized lookBypass value is False. + self.assertEqual(False, self.dv_tr.getLooksBypass()) + + # Test lookBypass setter and getter. + self.dv_tr.setLooksBypass(True) + self.assertEqual(True, self.dv_tr.getLooksBypass()) + self.dv_tr.setLooksBypass(False) + self.assertEqual(False, self.dv_tr.getLooksBypass()) + + def test_dataBypass(self): + """ + Test the setDataBypass() and getDataBypass() methods. + """ + + # Default initialized dataBypass value is True. + self.assertEqual(True, self.dv_tr.getDataBypass()) + + # Test dataBypass setter and getter. + self.dv_tr.setDataBypass(False) + self.assertEqual(False, self.dv_tr.getDataBypass()) + self.dv_tr.setDataBypass(True) + self.assertEqual(True, self.dv_tr.getDataBypass()) + + + def test_direction(self): + """ + Test the setDirection() and getDirection() methods. + """ + + # Default initialized direction is forward. + self.assertEqual(OCIO.TRANSFORM_DIR_FORWARD, self.dv_tr.getDirection()) + + for direction in OCIO.TransformDirection.__members__.values(): + # Setting the unknown direction preserves the current direction. + if direction != OCIO.TRANSFORM_DIR_UNKNOWN: + self.dv_tr.setDirection(direction) + self.assertEqual(direction, self.dv_tr.getDirection()) + + def test_validate_src(self): + """ + Test the validate() method for src value. Value must not be empty. + """ + + self.dv_tr.setSrc('source') + self.dv_tr.setDisplay('display') + self.dv_tr.setView('view') + self.assertIsNone(self.dv_tr.validate()) + + # Exception validation test. + self.dv_tr.setSrc('') + with self.assertRaises(OCIO.Exception): + self.dv_tr.validate() + + def test_validate_display(self): + """ + Test the validate() method for display value. Value must not be empty. + """ + + self.dv_tr.setSrc('source') + self.dv_tr.setDisplay('display') + self.dv_tr.setView('view') + self.assertIsNone(self.dv_tr.validate()) + + # Exception validation test. + self.dv_tr.setDisplay('') + with self.assertRaises(OCIO.Exception): + self.dv_tr.validate() + + def test_validate_view(self): + """ + Test the validate() method for view value. Value must not be empty. + """ + + self.dv_tr.setSrc('source') + self.dv_tr.setDisplay('display') + self.dv_tr.setView('view') + self.assertIsNone(self.dv_tr.validate()) + + # Exception validation test. + self.dv_tr.setView('') + with self.assertRaises(OCIO.Exception): + self.dv_tr.validate() + + + def test_validate_direction(self): + """ + Test the validate() method for direction. + Direction must be forward or inverse. + """ + + self.dv_tr.setSrc('source') + self.dv_tr.setDisplay('display') + self.dv_tr.setView('view') + + for direction in OCIO.TransformDirection.__members__.values(): + self.dv_tr.setDirection(direction) + if direction != OCIO.TRANSFORM_DIR_UNKNOWN: + self.assertIsNone(self.dv_tr.validate()) + else: + with self.assertRaises(OCIO.Exception): + self.dv_tr.validate() + + def test_constructor_with_keyword(self): + """ + Test DisplayViewTransform constructor with keywords and validate its values. + """ + + # With keywords in their proper order. + dv_tr = OCIO.DisplayViewTransform(src=self.TEST_SRC[0], + display=self.TEST_DISPLAY[0], + view=self.TEST_VIEW[0], + looksBypass=True, + dataBypass=False, + dir=OCIO.TRANSFORM_DIR_INVERSE) + + self.assertEqual(self.TEST_SRC[0], dv_tr.getSrc()) + self.assertEqual(self.TEST_DISPLAY[0], dv_tr.getDisplay()) + self.assertEqual(self.TEST_VIEW[0], dv_tr.getView()) + self.assertEqual(True, dv_tr.getLooksBypass()) + self.assertEqual(False, dv_tr.getDataBypass()) + self.assertEqual(OCIO.TRANSFORM_DIR_INVERSE, dv_tr.getDirection()) + + # With keyword not in their proper order. + dv_tr2 = OCIO.DisplayViewTransform(dir=OCIO.TRANSFORM_DIR_FORWARD, + view=self.TEST_VIEW[1], + src=self.TEST_SRC[1], + looksBypass=True, + display=self.TEST_DISPLAY[1], + dataBypass=True) + + self.assertEqual(self.TEST_SRC[1], dv_tr2.getSrc()) + self.assertEqual(self.TEST_DISPLAY[1], dv_tr2.getDisplay()) + self.assertEqual(self.TEST_VIEW[1], dv_tr2.getView()) + self.assertEqual(True, dv_tr2.getLooksBypass()) + self.assertEqual(True, dv_tr2.getDataBypass()) + self.assertEqual(OCIO.TRANSFORM_DIR_FORWARD, dv_tr2.getDirection()) + + def test_constructor_without_keyword(self): + """ + Test DisplayViewTransform constructor without keywords and validate its values. + """ + + dv_tr = OCIO.DisplayViewTransform(self.TEST_SRC[0], + self.TEST_DISPLAY[0], + self.TEST_VIEW[0], + True, + False, + OCIO.TRANSFORM_DIR_INVERSE) + + self.assertEqual(self.TEST_SRC[0], dv_tr.getSrc()) + self.assertEqual(self.TEST_DISPLAY[0], dv_tr.getDisplay()) + self.assertEqual(self.TEST_VIEW[0], dv_tr.getView()) + self.assertEqual(True, dv_tr.getLooksBypass()) + self.assertEqual(False, dv_tr.getDataBypass()) + self.assertEqual(OCIO.TRANSFORM_DIR_INVERSE, dv_tr.getDirection()) diff --git a/tests/python/OpenColorIOTestSuite.py b/tests/python/OpenColorIOTestSuite.py index b93ccb9de9..f3fb3e9184 100755 --- a/tests/python/OpenColorIOTestSuite.py +++ b/tests/python/OpenColorIOTestSuite.py @@ -34,7 +34,12 @@ import BuiltinTransformRegistryTest import BuiltinTransformTest import CDLTransformTest +import ColorSpaceTest +import ColorSpaceTransformTest +import ConfigTest +import DisplayViewTransformTest import LookTest +import ViewingRulesTest #from MainTest import * #from ConstantsTest import * #from ConfigTest import * @@ -55,11 +60,15 @@ def suite(): suite = unittest.TestSuite() loader = unittest.TestLoader() - suite.addTest(loader.loadTestsFromModule(ColorSpaceTest)) suite.addTest(loader.loadTestsFromModule(BuiltinTransformRegistryTest)) suite.addTest(loader.loadTestsFromModule(BuiltinTransformTest)) suite.addTest(loader.loadTestsFromModule(CDLTransformTest)) + suite.addTest(loader.loadTestsFromModule(ColorSpaceTest)) + suite.addTest(loader.loadTestsFromModule(ColorSpaceTransformTest)) + suite.addTest(loader.loadTestsFromModule(ConfigTest)) + suite.addTest(loader.loadTestsFromModule(DisplayViewTransformTest)) suite.addTest(loader.loadTestsFromModule(LookTest)) + suite.addTest(loader.loadTestsFromModule(ViewingRulesTest)) #suite.addTest(MainTest("test_interface")) #suite.addTest(ConstantsTest("test_interface")) #suite.addTest(ConfigTest("test_interface")) diff --git a/tests/python/TransformsTest.py b/tests/python/TransformsTest.py index a1b80fb75a..85e031e187 100644 --- a/tests/python/TransformsTest.py +++ b/tests/python/TransformsTest.py @@ -151,8 +151,8 @@ def test_interface(self): ct.setDst("bar") self.assertEqual("bar", ct.getDst()) - ### DisplayTransform ### - dt = OCIO.DisplayTransform() + ### DisplayViewTransform ### + dt = OCIO.DisplayViewTransform() dt.setInputColorSpaceName("lin18") self.assertEqual("lin18", dt.getInputColorSpaceName()) dt.setLinearCC(ct) @@ -174,16 +174,16 @@ def test_interface(self): dt.setLooksOverrideEnabled(True) self.assertEqual(True, dt.getLooksOverrideEnabled()) - dt2 = OCIO.DisplayTransform("lin18", "sRGB", "foobar", - OCIO.TRANSFORM_DIR_INVERSE) + dt2 = OCIO.DisplayViewTransform("lin18", "sRGB", "foobar", + OCIO.TRANSFORM_DIR_INVERSE) self.assertEqual("lin18", dt2.getInputColorSpaceName()) self.assertEqual("sRGB", dt2.getDisplay()) self.assertEqual("foobar", dt2.getView()) self.assertEqual(OCIO.TRANSFORM_DIR_INVERSE, dt2.getDirection()) - dt3 = OCIO.DisplayTransform(inputColorSpaceName="lin18", - display="sRGB", view="foobar", - direction=OCIO.TRANSFORM_DIR_INVERSE) + dt3 = OCIO.DisplayViewTransform(inputColorSpaceName="lin18", + display="sRGB", view="foobar", + direction=OCIO.TRANSFORM_DIR_INVERSE) self.assertEqual("lin18", dt3.getInputColorSpaceName()) self.assertEqual("sRGB", dt3.getDisplay()) self.assertEqual("foobar", dt3.getView()) diff --git a/tests/python/UnitTestUtils.py b/tests/python/UnitTestUtils.py index 91be0876bf..42ed7cc50e 100644 --- a/tests/python/UnitTestUtils.py +++ b/tests/python/UnitTestUtils.py @@ -32,7 +32,7 @@ TEST_CATEGORIES = ['linear', 'rendering', 'log', '123', 'a1b.'] -SIMPLE_CONFIG = """ocio_profile_version: 1 +SIMPLE_CONFIG = """ocio_profile_version: 2 search_path: luts strictparsing: false @@ -42,6 +42,12 @@ default: raw scene_linear: lnh +viewing_rules: + - ! {name: Rule_1, colorspaces: c1, custom: {key0: value0, key1: value1}} + - ! {name: Rule_2, colorspaces: [c2, c3]} + - ! {name: Rule_3, encodings: log} + - ! {name: Rule_4, encodings: [log, scene-linear], custom: {key1: value2, key2: value0}} + displays: sRGB: - ! {name: Film1D, colorspace: vd8} @@ -91,4 +97,14 @@ - ! {value: [2.2, 2.2, 2.2, 1]} - ! {matrix: [1, 2, 3, 4, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1], offset: [1, 2, 0, 0]} - ! {slope: [0.9, 1, 1], offset: [0.1, 0.3, 0.4], power: [1.1, 1.1, 1.1], sat: 0.9} + + - ! + name: c1 + encoding: scene-linear + + - ! + name: c2 + + - ! + name: c3 """ diff --git a/tests/python/ViewingRulesTest.py b/tests/python/ViewingRulesTest.py new file mode 100644 index 0000000000..3c4cbb66de --- /dev/null +++ b/tests/python/ViewingRulesTest.py @@ -0,0 +1,242 @@ +# SPDX-License-Identifier: BSD-3-Clause +# Copyright Contributors to the OpenColorIO Project. + +import unittest +import os +import sys + +import PyOpenColorIO as OCIO +from UnitTestUtils import SIMPLE_CONFIG, TEST_NAMES + + +class ViewingRulesTest(unittest.TestCase): + def setUp(self): + self.rules = OCIO.ViewingRules() + + def tearDown(self): + self.rule = None + + def test_insert_remove(self): + """ + Test the insertRule(), removeRule(), getNumEntrie(), getIndexForRule(), getName() methods. + """ + + # Empty object. + self.assertEqual(0, self.rules.getNumEntries()) + + # Add some rules. + rule1 = "rule1" + rule2 = "rule2" + self.rules.insertRule(0, rule1) + self.rules.insertRule(1, rule2) + + self.assertEqual(2, self.rules.getNumEntries()) + self.assertEqual(rule1, self.rules.getName(0)) + self.assertEqual(rule2, self.rules.getName(1)) + + self.assertEqual(0, self.rules.getIndexForRule(rule1)) + self.assertEqual(1, self.rules.getIndexForRule(rule2)) + + # Remove a rule. + self.rules.removeRule(0) + self.assertEqual(1, self.rules.getNumEntries()) + self.assertEqual(rule2, self.rules.getName(0)) + self.rules.insertRule(0, rule1) + self.assertEqual(2, self.rules.getNumEntries()) + self.assertEqual(rule1, self.rules.getName(0)) + self.assertEqual(rule2, self.rules.getName(1)) + + + # Index has to be valid. + rule3 = "rule3" + with self.assertRaises(OCIO.Exception): + self.rules.insertRule(4, rule3) + + # Rule has to be present. + with self.assertRaises(OCIO.Exception): + self.rules.getIndexForRule(rule3) + + # Index has to be valid. + with self.assertRaises(OCIO.Exception): + self.rules.getName(3) + + # Index has to be valid. + with self.assertRaises(OCIO.Exception): + self.rules.removeRule(3) + + # Rule name must be unique. + with self.assertRaises(OCIO.Exception): + self.rules.insertRule(0, rule2) + + def test_color_spaces(self): + """ + Test the getColorSpaces(), addColorSpace() and removeColorSpace() methods. + """ + + # Add new rule. + ruleCS = "rule_cs" + self.rules.insertRule(0, ruleCS) + + # Test empty color space list. + self.assertEqual(0, len(self.rules.getColorSpaces(0))) + with self.assertRaises(IndexError): + self.rules.getColorSpaces(0)[0] + + # Test with defined TEST_NAMES. + for i, y in enumerate(TEST_NAMES): + self.rules.addColorSpace(0, y) + self.assertEqual(i + 1, len(self.rules.getColorSpaces(0))) + + iterator = self.rules.getColorSpaces(0) + for a in TEST_NAMES: + self.assertEqual(a, next(iterator)) + + # Test the length of color spaces is zero after removing all color spaces. + for i in range(len(TEST_NAMES)): + self.rules.removeColorSpace(0, 0) + self.assertEqual(0, len(self.rules.getColorSpaces(0))) + + # Testing individually adding and removing a color space. + self.rules.addColorSpace(0, TEST_NAMES[0]) + self.assertEqual(1, len(self.rules.getColorSpaces(0))) + self.rules.addColorSpace(0, TEST_NAMES[1]) + self.assertEqual(2, len(self.rules.getColorSpaces(0))) + self.rules.removeColorSpace(0, 1) + self.assertEqual(1, len(self.rules.getColorSpaces(0))) + + # Index has to be valid. + with self.assertRaises(OCIO.Exception): + self.rules.removeColorSpace(0, 1) + + # Can't add encoding if there are color spaces. + with self.assertRaises(OCIO.Exception): + self.rules.addEncoding(0, "NoMix") + + def test_encodings(self): + """ + Test the getEncodings(), addEncoding() and removeEncoding() methods. + """ + + # Add new rule. + ruleEnc = "rule_enc" + self.rules.insertRule(0, ruleEnc) + + # Test empty encodings list. + self.assertEqual(0, len(self.rules.getEncodings(0))) + with self.assertRaises(IndexError): + self.rules.getEncodings(0)[0] + + # Test with defined TEST_NAMES. + for i, y in enumerate(TEST_NAMES): + self.rules.addEncoding(0, y) + self.assertEqual(i + 1, len(self.rules.getEncodings(0))) + + iterator = self.rules.getEncodings(0) + for a in TEST_NAMES: + self.assertEqual(a, next(iterator)) + + # Test the length of encodings is zero after removing all encodings. + for i in range(len(TEST_NAMES)): + self.rules.removeEncoding(0, 0) + self.assertEqual(0, len(self.rules.getEncodings(0))) + + # Testing individually adding and removing an encoding. + self.rules.addEncoding(0, TEST_NAMES[0]) + self.assertEqual(1, len(self.rules.getEncodings(0))) + self.rules.addEncoding(0, TEST_NAMES[1]) + self.assertEqual(2, len(self.rules.getEncodings(0))) + self.rules.removeEncoding(0, 1) + self.assertEqual(1, len(self.rules.getEncodings(0))) + + # Index has to be valid. + with self.assertRaises(OCIO.Exception): + self.rules.removeEncoding(0, 1) + + # Can't add color space if there are encodings. + with self.assertRaises(OCIO.Exception): + self.rules.addColorSpace(0, "NoMix") + + def test_custom_keys(self): + """ + Test the getNumCustomKeys(), getCustomKeyName(), getCustomKeyValue() and setCustomKey() methods. + """ + # Add new rule. + rule = "rule" + self.rules.insertRule(0, rule) + + # Set keys and values and verify they are set. + self.assertEqual(0, self.rules.getNumCustomKeys(0)) + self.rules.setCustomKey(0, "key1", "value1") + self.rules.setCustomKey(0, "key2", "value2") + self.assertEqual(2, self.rules.getNumCustomKeys(0)) + self.assertEqual("key1", self.rules.getCustomKeyName(0, 0)) + self.assertEqual("value1", self.rules.getCustomKeyValue(0, 0)) + self.assertEqual("key2", self.rules.getCustomKeyName(0, 1)) + self.assertEqual("value2", self.rules.getCustomKeyValue(0, 1)) + # Replace a value. + self.rules.setCustomKey(0, "key2", "value3") + self.assertEqual(2, self.rules.getNumCustomKeys(0)) + self.assertEqual("value3", self.rules.getCustomKeyValue(0, 1)) + # Remove a key. + self.rules.setCustomKey(0, "key1", "") + self.assertEqual(1, self.rules.getNumCustomKeys(0)) + self.assertEqual("key2", self.rules.getCustomKeyName(0, 0)) + + # Index has to be valid. + with self.assertRaises(OCIO.Exception): + self.rules.setCustomKey(42, "wrong", "") + # Key name has to be non-empty. + with self.assertRaises(OCIO.Exception): + self.rules.setCustomKey(0, "", "") + # Index has to be valid. + with self.assertRaises(OCIO.Exception): + self.rules.getCustomKeyName(0, 42) + + def test_config(self): + """ + Test the viewing rules object from an OCIO config. + """ + + # Get simple config file from UnitTestUtils.py + cfg = OCIO.Config().CreateFromStream(SIMPLE_CONFIG) + + # Test ViewingRules class object getters from config + rules = cfg.getViewingRules() + self.assertEqual(4, rules.getNumEntries()) + + iterator = rules.getColorSpaces(0) + self.assertEqual(1, len(iterator)) + self.assertEqual("c1", next(iterator)) + self.assertEqual(2, rules.getNumCustomKeys(0)) + self.assertEqual("key0", rules.getCustomKeyName(0, 0)) + self.assertEqual("value0", rules.getCustomKeyValue(0, 0)) + self.assertEqual("key1", rules.getCustomKeyName(0, 1)) + self.assertEqual("value1", rules.getCustomKeyValue(0, 1)) + iterator = rules.getColorSpaces(1) + self.assertEqual(2, len(iterator)) + self.assertEqual("c2", next(iterator)) + self.assertEqual("c3", next(iterator)) + self.assertEqual(0, rules.getNumCustomKeys(1)) + iterator = rules.getEncodings(2) + self.assertEqual(1, len(iterator)) + self.assertEqual("log", next(iterator)) + self.assertEqual(0, rules.getNumCustomKeys(2)) + iterator = rules.getEncodings(3) + self.assertEqual(2, len(iterator)) + self.assertEqual("log", next(iterator)) + self.assertEqual("scene-linear", next(iterator)) + self.assertEqual(2, rules.getNumCustomKeys(3)) + self.assertEqual("key1", rules.getCustomKeyName(3, 0)) + self.assertEqual("value2", rules.getCustomKeyValue(3, 0)) + self.assertEqual("key2", rules.getCustomKeyName(3, 1)) + self.assertEqual("value0", rules.getCustomKeyValue(3, 1)) + + # Add a new rule. + rules.insertRule(0, 'newRule') + rules.addEncoding(0, 'log') + rules.addEncoding(0, 'scene-linear') + + # Set the modified rules, get them back and verify there are now 5 rules. + cfg.setViewingRules(rules) + rules = cfg.getViewingRules() + self.assertEqual(5, rules.getNumEntries()) From d06821b2729258bb935500b24c3363e5fd9c4201 Mon Sep 17 00:00:00 2001 From: Patrick Hodoul Date: Mon, 29 Jun 2020 12:00:46 -0400 Subject: [PATCH 26/33] Adsk Contrib - Various fixes and improvements (#1048) Signed-off-by: Patrick Hodoul --- include/OpenColorIO/OpenColorIO.h | 28 +++++++++++- src/OpenColorIO/ColorSpace.cpp | 9 ++-- src/OpenColorIO/Mutex.h | 15 ++++--- src/OpenColorIO/ParseUtils.cpp | 25 ++++++----- src/OpenColorIO/Platform.cpp | 42 ++++++++++++++++-- src/OpenColorIO/Platform.h | 7 ++- src/OpenColorIO/Transform.cpp | 2 +- .../transforms/AllocationTransform.cpp | 9 ++-- .../transforms/ExponentTransform.cpp | 7 +-- .../ExponentWithLinearTransform.cpp | 6 +-- tests/cpu/Config_tests.cpp | 34 +++++++++++--- tests/cpu/Platform_tests.cpp | 44 ++++++++++++++----- tests/cpu/UnitTestLogUtils.cpp | 8 +++- tests/cpu/UnitTestLogUtils.h | 4 +- 14 files changed, 175 insertions(+), 65 deletions(-) diff --git a/include/OpenColorIO/OpenColorIO.h b/include/OpenColorIO/OpenColorIO.h index 5812f95b50..a414d4a37d 100644 --- a/include/OpenColorIO/OpenColorIO.h +++ b/include/OpenColorIO/OpenColorIO.h @@ -154,7 +154,8 @@ extern OCIOEXPORT void LogMessage(LoggingLevel level, const char * message); extern OCIOEXPORT const char * GetEnvVariable(const char * name); //!cpp:function:: extern OCIOEXPORT void SetEnvVariable(const char * name, const char * value); - +//!cpp:function:: +extern OCIOEXPORT void UnsetEnvVariable(const char * name); /////////////////////////////////////////////////////////////////////////// //!rst:: @@ -1657,7 +1658,18 @@ class OCIOEXPORT Processor static const char * getFormatExtensionByIndex(int index); // TODO: Revisit the dynamic property access. - //!cpp:function:: + //!cpp:function:: Access to dynamic properties. + // + // .. note:: The dynamic properties are a convenient way to change on-the-fly values without + // generating again and again a CPU or GPU processor instance. Any color transformation can + // contain dynamic properties from a :cpp:class:`ExposureContrastTransform` for example. So, + // :cpp:class:`Processor`, :cpp:class:`CPUProcessor` and :cpp:class:`GPUProcessor` all have + // ways to manage dynamic properties. However, the transform dynamic properties are decoupled + // between the types of processor instances so that the same :cpp:class:`Processor` can + // generate several independent CPU and/or GPU processor instances i.e. changing the value + // of the exposure dynamic property from a CPU processor instance does not affect the + // corresponding GPU processor instance. + // DynamicPropertyRcPtr getDynamicProperty(DynamicPropertyType type) const; bool hasDynamicProperty(DynamicPropertyType type) const; @@ -2638,6 +2650,18 @@ class OCIOEXPORT GpuShaderDesc : public GpuShaderCreator GpuShaderCreatorRcPtr clone() const override; //!cpp:function:: Dynamic Property related methods. + // + // .. note:: The dynamic properties are a convenient way to change on-the-fly values without + // generating again and again the fragment shader program (i.e. dynamic properties map to + // uniforms in GLSL). So, the same color transformation could be used several times for DCCs + // supporting multiple viewports for example. It allows customizations + // (using :cpp:class:`GpuShaderDesc`) of the generated fragment shader program mainly to avoid + // resource conflicts. It also decouples dynamic properties to avoid having a change on one + // viewport affect the others. + // Hence, a dynamic property value change must use the corresponding :cpp:class:`GpuShaderDesc` + // instance to do it -- the :cpp:class:`GPUProcessor` dynamic property values only represent + // the original values. + // virtual unsigned getNumUniforms() const noexcept = 0; virtual void getUniform(unsigned index, const char *& name, DynamicPropertyRcPtr & value) const = 0; diff --git a/src/OpenColorIO/ColorSpace.cpp b/src/OpenColorIO/ColorSpace.cpp index 19c42f2c11..6baf41e7ca 100644 --- a/src/OpenColorIO/ColorSpace.cpp +++ b/src/OpenColorIO/ColorSpace.cpp @@ -287,9 +287,12 @@ void ColorSpace::setTransform(const ConstTransformRcPtr & transform, std::ostream & operator<< (std::ostream & os, const ColorSpace & cs) { - int numVars(cs.getAllocationNumVars()); + const int numVars(cs.getAllocationNumVars()); std::vector vars(numVars); - cs.getAllocationVars(&vars[0]); + if (numVars > 0) + { + cs.getAllocationVars(&vars[0]); + } os << " buffer(size); GetEnvironmentVariable(name, buffer.data(), size); value = std::string(buffer.data()); + return true; } else { value.clear(); + return false; } #else - const char* val = ::getenv(name); + const char * val = ::getenv(name); value = (val && *val) ? val : ""; + return val; // Returns true if the env. variable exists but empty. #endif } -void Setenv (const char * name, const std::string & value) +void Setenv(const char * name, const std::string & value) { + if (!name || !*name) + { + return; + } + + // Note that the Windows _putenv_s() removes the env. variable if the value is empty. But + // the Linux ::setenv() sets the env. variable to empty if the value is empty i.e. it still + // exists. To avoid the ambiguity, use Unsetenv() when the env. variable removal if needed. + #ifdef _WIN32 _putenv_s(name, value.c_str()); #else @@ -61,6 +82,21 @@ void Setenv (const char * name, const std::string & value) #endif } +void Unsetenv(const char * name) +{ + if (!name || !*name) + { + return; + } + +#ifdef _WIN32 + // Note that the Windows _putenv_s() removes the env. variable if the value is empty. + _putenv_s(name, ""); +#else + ::unsetenv(name); +#endif +} + int Strcasecmp(const char * str1, const char * str2) { #ifdef _WIN32 diff --git a/src/OpenColorIO/Platform.h b/src/OpenColorIO/Platform.h index 1c9df19992..2656b52463 100644 --- a/src/OpenColorIO/Platform.h +++ b/src/OpenColorIO/Platform.h @@ -41,10 +41,15 @@ namespace OCIO_NAMESPACE namespace Platform { -void Getenv(const char * name, std::string & value); +// Return true if the environment variable exists. +bool Getenv(const char * name, std::string & value); +// Set a new value to a new or existing environment variable. void Setenv(const char * name, const std::string & value); +// Remove the environment variable. +void Unsetenv(const char * name); + // Case insensitive string comparison int Strcasecmp(const char * str1, const char * str2); diff --git a/src/OpenColorIO/Transform.cpp b/src/OpenColorIO/Transform.cpp index 6bf5e6ceb0..b979d285df 100755 --- a/src/OpenColorIO/Transform.cpp +++ b/src/OpenColorIO/Transform.cpp @@ -160,7 +160,7 @@ std::ostream& operator<< (std::ostream & os, const Transform & transform) { os << *allocationTransform; } - if(const BuiltinTransform * builtInTransform = \ + else if(const BuiltinTransform * builtInTransform = \ dynamic_cast(t)) { os << *builtInTransform; diff --git a/src/OpenColorIO/transforms/AllocationTransform.cpp b/src/OpenColorIO/transforms/AllocationTransform.cpp index c89ed1c4cf..a9148f4112 100755 --- a/src/OpenColorIO/transforms/AllocationTransform.cpp +++ b/src/OpenColorIO/transforms/AllocationTransform.cpp @@ -146,13 +146,16 @@ void AllocationTransform::setVars(int numvars, const float * vars) std::ostream& operator<< (std::ostream& os, const AllocationTransform& t) { Allocation allocation(t.getAllocation()); - int numVars(t.getNumVars()); + const int numVars(t.getNumVars()); std::vector vars(numVars); - t.getVars(&vars[0]); + if (numVars > 0) + { + t.getVars(&vars[0]); + } os << ""; return os; } diff --git a/src/OpenColorIO/transforms/ExponentWithLinearTransform.cpp b/src/OpenColorIO/transforms/ExponentWithLinearTransform.cpp index 6b1066b6e5..53c4ca480b 100644 --- a/src/OpenColorIO/transforms/ExponentWithLinearTransform.cpp +++ b/src/OpenColorIO/transforms/ExponentWithLinearTransform.cpp @@ -160,11 +160,7 @@ std::ostream & operator<< (std::ostream & os, const ExponentWithLinearTransform os << " " << offset[i]; } - auto style = t.getNegativeStyle(); - if (style == NEGATIVE_MIRROR) - { - os << ", style=" << NegativeStyleToString(style); - } + os << ", style=" << NegativeStyleToString(t.getNegativeStyle()); os << ">"; return os; } diff --git a/tests/cpu/Config_tests.cpp b/tests/cpu/Config_tests.cpp index 248ff05f30..99fed675b6 100644 --- a/tests/cpu/Config_tests.cpp +++ b/tests/cpu/Config_tests.cpp @@ -589,8 +589,19 @@ OCIO_ADD_TEST(Config, env_check) " - ! {name: Raw, colorspace: raw}\n" "\n"; - OCIO::Platform::Setenv("SHOW", "bar"); - OCIO::Platform::Setenv("TASK", "lighting"); + struct Guard + { + Guard() + { + OCIO::Platform::Setenv("SHOW", "bar"); + OCIO::Platform::Setenv("TASK", "lighting"); + } + ~Guard() + { + OCIO::Platform::Unsetenv("SHOW"); + OCIO::Platform::Unsetenv("TASK"); + } + } guard; std::istringstream is; is.str(SIMPLE_PROFILE); @@ -653,6 +664,16 @@ OCIO_ADD_TEST(Config, role_without_colorspace) OCIO_ADD_TEST(Config, env_colorspace_name) { + // Guard to automatically unset the env. variable. + struct Guard + { + Guard() = default; + ~Guard() + { + OCIO::Platform::Unsetenv("OCIO_TEST"); + } + } guard; + const std::string MY_OCIO_CONFIG = "ocio_profile_version: 1\n" "\n" @@ -1712,13 +1733,12 @@ OCIO_ADD_TEST(Config, categories) OCIO_ADD_TEST(Config, display) { // Guard to automatically unset the env. variable. - class Guard + struct Guard { - public: Guard() = default; ~Guard() { - OCIO::Platform::Setenv(OCIO::OCIO_ACTIVE_DISPLAYS_ENVVAR, ""); + OCIO::Platform::Unsetenv(OCIO::OCIO_ACTIVE_DISPLAYS_ENVVAR); } } guard; @@ -2020,7 +2040,7 @@ OCIO_ADD_TEST(Config, view) Guard() = default; ~Guard() { - OCIO::Platform::Setenv(OCIO::OCIO_ACTIVE_VIEWS_ENVVAR, ""); + OCIO::Platform::Unsetenv(OCIO::OCIO_ACTIVE_VIEWS_ENVVAR); } } guard; @@ -3187,7 +3207,7 @@ class InactiveCSGuard } ~InactiveCSGuard() { - OCIO::Platform::Setenv(OCIO::OCIO_INACTIVE_COLORSPACES_ENVVAR, ""); + OCIO::Platform::Unsetenv(OCIO::OCIO_INACTIVE_COLORSPACES_ENVVAR); } }; diff --git a/tests/cpu/Platform_tests.cpp b/tests/cpu/Platform_tests.cpp index 441faae767..66ec329275 100644 --- a/tests/cpu/Platform_tests.cpp +++ b/tests/cpu/Platform_tests.cpp @@ -25,7 +25,7 @@ OCIO_ADD_TEST(Platform, envVariable) OCIO_CHECK_ASSERT(value && *value); OCIO_CHECK_EQUAL(std::string(value), "SomeValue"); - OCIO::SetEnvVariable("MY_DUMMY_ENV", ""); + OCIO::UnsetEnvVariable("MY_DUMMY_ENV"); value = OCIO::GetEnvVariable("MY_DUMMY_ENV"); OCIO_CHECK_ASSERT(!value || !*value); } @@ -33,25 +33,36 @@ OCIO_ADD_TEST(Platform, envVariable) OCIO_ADD_TEST(Platform, getenv) { std::string env; - OCIO::Platform::Getenv("NotExistingEnvVariable", env); + OCIO_CHECK_ASSERT(!OCIO::Platform::Getenv("NotExistingEnvVariable", env)); OCIO_CHECK_ASSERT(env.empty()); - OCIO::Platform::Getenv("PATH", env); + OCIO_CHECK_ASSERT(OCIO::Platform::Getenv("PATH", env)); OCIO_CHECK_ASSERT(!env.empty()); - OCIO::Platform::Getenv("NotExistingEnvVariable", env); + OCIO_CHECK_ASSERT(!OCIO::Platform::Getenv("NotExistingEnvVariable", env)); OCIO_CHECK_ASSERT(env.empty()); - OCIO::Platform::Getenv("PATH", env); + OCIO_CHECK_ASSERT(OCIO::Platform::Getenv("PATH", env)); OCIO_CHECK_ASSERT(!env.empty()); } OCIO_ADD_TEST(Platform, setenv) { + // Guard to automatically unset the env. variable. + struct Guard + { + Guard() = default; + ~Guard() + { + OCIO::Platform::Unsetenv("MY_DUMMY_ENV"); + OCIO::Platform::Unsetenv("MY_WINDOWS_DUMMY_ENV"); + } + } guard; + { OCIO::Platform::Setenv("MY_DUMMY_ENV", "SomeValue"); std::string env; - OCIO::Platform::Getenv("MY_DUMMY_ENV", env); + OCIO_CHECK_ASSERT(OCIO::Platform::Getenv("MY_DUMMY_ENV", env)); OCIO_CHECK_ASSERT(!env.empty()); OCIO_CHECK_ASSERT(0==std::strcmp("SomeValue", env.c_str())); @@ -60,35 +71,44 @@ OCIO_ADD_TEST(Platform, setenv) { OCIO::Platform::Setenv("MY_DUMMY_ENV", " "); std::string env; - OCIO::Platform::Getenv("MY_DUMMY_ENV", env); + OCIO_CHECK_ASSERT(OCIO::Platform::Getenv("MY_DUMMY_ENV", env)); OCIO_CHECK_ASSERT(!env.empty()); OCIO_CHECK_ASSERT(0==std::strcmp(" ", env.c_str())); OCIO_CHECK_EQUAL(std::strlen(" "), env.size()); } { - OCIO::Platform::Setenv("MY_DUMMY_ENV", ""); + OCIO::Platform::Unsetenv("MY_DUMMY_ENV"); std::string env; - OCIO::Platform::Getenv("MY_DUMMY_ENV", env); + OCIO_CHECK_ASSERT(!OCIO::Platform::Getenv("MY_DUMMY_ENV", env)); OCIO_CHECK_ASSERT(env.empty()); } #ifdef _WIN32 { SetEnvironmentVariable("MY_WINDOWS_DUMMY_ENV", "1"); std::string env; - OCIO::Platform::Getenv("MY_WINDOWS_DUMMY_ENV", env); + OCIO_CHECK_ASSERT(OCIO::Platform::Getenv("MY_WINDOWS_DUMMY_ENV", env)); OCIO_CHECK_EQUAL(env, std::string("1")); } { SetEnvironmentVariable("MY_WINDOWS_DUMMY_ENV", " "); std::string env; - OCIO::Platform::Getenv("MY_WINDOWS_DUMMY_ENV", env); + OCIO_CHECK_ASSERT(OCIO::Platform::Getenv("MY_WINDOWS_DUMMY_ENV", env)); OCIO_CHECK_EQUAL(env, std::string(" ")); } { + // Windows SetEnvironmentVariable() sets the env. variable to empty like + // the Linux ::setenv() in contradiction with the Windows _putenv_s(). + SetEnvironmentVariable("MY_WINDOWS_DUMMY_ENV", ""); std::string env; - OCIO::Platform::Getenv("MY_WINDOWS_DUMMY_ENV", env); + OCIO_CHECK_ASSERT(OCIO::Platform::Getenv("MY_WINDOWS_DUMMY_ENV", env)); + OCIO_CHECK_ASSERT(env.empty()); + } + { + SetEnvironmentVariable("MY_WINDOWS_DUMMY_ENV", nullptr); + std::string env; + OCIO_CHECK_ASSERT(!OCIO::Platform::Getenv("MY_WINDOWS_DUMMY_ENV", env)); OCIO_CHECK_ASSERT(env.empty()); } #endif diff --git a/tests/cpu/UnitTestLogUtils.cpp b/tests/cpu/UnitTestLogUtils.cpp index 7c91bc0049..4fb45f0389 100644 --- a/tests/cpu/UnitTestLogUtils.cpp +++ b/tests/cpu/UnitTestLogUtils.cpp @@ -55,9 +55,13 @@ bool LogGuard::empty() const } MuteLogging::MuteLogging() - : LogGuard() { - SetLoggingFunction(MuteLoggingFunction); + SetLoggingFunction(&MuteLoggingFunction); +} + +MuteLogging::~MuteLogging() +{ + ResetToDefaultLoggingFunction(); } } // namespace OCIO_NAMESPACE diff --git a/tests/cpu/UnitTestLogUtils.h b/tests/cpu/UnitTestLogUtils.h index 6a5a7771b3..aa961ba4a6 100644 --- a/tests/cpu/UnitTestLogUtils.h +++ b/tests/cpu/UnitTestLogUtils.h @@ -30,11 +30,11 @@ class LogGuard }; // Utility to mute the logging mechanism so the unit test output is clean. -class MuteLogging : public LogGuard +class MuteLogging { public: MuteLogging(); - virtual ~MuteLogging() = default; + ~MuteLogging(); }; } // namespace OCIO_NAMESPACE From 85be19f6378bef240fd0db7bb0943ad2c99070d7 Mon Sep 17 00:00:00 2001 From: Michael Dolan Date: Wed, 1 Jul 2020 09:45:50 -0400 Subject: [PATCH 27/33] PyOCIO: Fix AllocationTransform __str__, cleanup params (#1042) * Add defStr to transform classes, cleanup param names Signed-off-by: Michael Dolan * Update unit test params Signed-off-by: Michael Dolan * Update param name in DisplayViewTransform test Signed-off-by: Michael Dolan --- src/bindings/python/PyAllocationTransform.cpp | 16 ++++---- src/bindings/python/PyBaker.cpp | 4 +- src/bindings/python/PyBuiltinTransform.cpp | 10 +++-- src/bindings/python/PyCDLTransform.cpp | 18 +++++---- src/bindings/python/PyColorSpace.cpp | 4 +- src/bindings/python/PyColorSpaceSet.cpp | 8 ++-- src/bindings/python/PyColorSpaceTransform.cpp | 8 ++-- src/bindings/python/PyConfig.cpp | 6 +-- src/bindings/python/PyContext.cpp | 6 +-- .../python/PyDisplayViewTransform.cpp | 10 +++-- src/bindings/python/PyExponentTransform.cpp | 18 +++++---- .../python/PyExponentWithLinearTransform.cpp | 10 +++-- .../python/PyExposureContrastTransform.cpp | 10 +++-- src/bindings/python/PyFileTransform.cpp | 12 +++--- .../python/PyFixedFunctionTransform.cpp | 10 +++-- src/bindings/python/PyGpuShaderCreator.cpp | 4 +- src/bindings/python/PyGpuShaderDesc.cpp | 10 ++--- src/bindings/python/PyGroupTransform.cpp | 4 +- src/bindings/python/PyLogAffineTransform.cpp | 10 +++-- src/bindings/python/PyLogCameraTransform.cpp | 10 +++-- src/bindings/python/PyLogTransform.cpp | 12 +++--- src/bindings/python/PyLookTransform.cpp | 14 ++++--- src/bindings/python/PyLut1DTransform.cpp | 20 +++++----- src/bindings/python/PyLut3DTransform.cpp | 12 +++--- src/bindings/python/PyMatrixTransform.cpp | 40 ++++++++++--------- src/bindings/python/PyProcessorMetadata.cpp | 2 +- src/bindings/python/PyRangeTransform.cpp | 18 +++++---- src/bindings/python/PyTransform.cpp | 2 +- src/bindings/python/PyTypes.cpp | 40 +++++++++---------- src/bindings/python/PyUtils.h | 6 +-- src/bindings/python/PyViewTransform.cpp | 4 +- tests/python/BuiltinTransformTest.py | 4 +- tests/python/CDLTransformTest.py | 4 +- tests/python/ColorSpaceTest.py | 3 +- tests/python/DisplayViewTransformTest.py | 4 +- 35 files changed, 205 insertions(+), 168 deletions(-) diff --git a/src/bindings/python/PyAllocationTransform.cpp b/src/bindings/python/PyAllocationTransform.cpp index 9e1e9c1d0e..6ae1998db5 100644 --- a/src/bindings/python/PyAllocationTransform.cpp +++ b/src/bindings/python/PyAllocationTransform.cpp @@ -16,7 +16,7 @@ std::vector getVarsStdVec(const AllocationTransformRcPtr & p) return vars; } -void setVars(const AllocationTransformRcPtr & p, const std::vector & vars) +void setVars(AllocationTransformRcPtr & p, const std::vector & vars) { if (vars.size() < 2 || vars.size() > 3) { @@ -31,9 +31,9 @@ void bindPyAllocationTransform(py::module & m) { AllocationTransformRcPtr DEFAULT = AllocationTransform::Create(); - py::class_(m, "AllocationTransform") + auto cls = py::class_(m, "AllocationTransform") .def(py::init(&AllocationTransform::Create)) .def(py::init([](Allocation allocation, const std::vector & vars, @@ -41,18 +41,18 @@ void bindPyAllocationTransform(py::module & m) { AllocationTransformRcPtr p = AllocationTransform::Create(); p->setAllocation(allocation); - setVars(p, vars); + if (!vars.empty()) { setVars(p, vars); } p->setDirection(dir); p->validate(); return p; }), "allocation"_a = DEFAULT->getAllocation(), "vars"_a = getVarsStdVec(DEFAULT), - "dir"_a = DEFAULT->getDirection()) + "direction"_a = DEFAULT->getDirection()) .def("getAllocation", &AllocationTransform::getAllocation) .def("setAllocation", &AllocationTransform::setAllocation, "allocation"_a) - .def("getVars", [](AllocationTransformRcPtr & self) + .def("getVars", [](AllocationTransformRcPtr self) { return getVarsStdVec(self); }) @@ -61,6 +61,8 @@ void bindPyAllocationTransform(py::module & m) setVars(self, vars); }, "vars"_a); + + defStr(cls); } } // namespace OCIO_NAMESPACE diff --git a/src/bindings/python/PyBaker.cpp b/src/bindings/python/PyBaker.cpp index 8b1cb539db..227e48fcae 100644 --- a/src/bindings/python/PyBaker.cpp +++ b/src/bindings/python/PyBaker.cpp @@ -78,9 +78,9 @@ void bindPyBaker(py::module & m) .def("getTargetSpace", &Baker::getTargetSpace) .def("setTargetSpace", &Baker::setTargetSpace, "targetSpace"_a) .def("getShaperSize", &Baker::getShaperSize) - .def("setShaperSize", &Baker::setShaperSize, "shapersize"_a) + .def("setShaperSize", &Baker::setShaperSize, "shaperSize"_a) .def("getCubeSize", &Baker::getCubeSize) - .def("setCubeSize", &Baker::setCubeSize, "cubesize"_a) + .def("setCubeSize", &Baker::setCubeSize, "cubeSize"_a) .def("bake", [](BakerRcPtr & self, const std::string & fileName) { std::ofstream f(fileName.c_str()); diff --git a/src/bindings/python/PyBuiltinTransform.cpp b/src/bindings/python/PyBuiltinTransform.cpp index e69b6ac148..186d76696e 100644 --- a/src/bindings/python/PyBuiltinTransform.cpp +++ b/src/bindings/python/PyBuiltinTransform.cpp @@ -10,9 +10,9 @@ void bindPyBuiltinTransform(py::module & m) { BuiltinTransformRcPtr DEFAULT = BuiltinTransform::Create(); - py::class_(m, "BuiltinTransform") + auto cls = py::class_(m, "BuiltinTransform") .def(py::init(&BuiltinTransform::Create)) .def(py::init([](const std::string & style, TransformDirection dir) { @@ -23,11 +23,13 @@ void bindPyBuiltinTransform(py::module & m) return p; }), "style"_a = DEFAULT->getStyle(), - "dir"_a = DEFAULT->getDirection()) + "direction"_a = DEFAULT->getDirection()) .def("setStyle", &BuiltinTransform::setStyle, "style"_a.none(false)) .def("getStyle", &BuiltinTransform::getStyle) .def("getDescription", &BuiltinTransform::getDescription); + + defStr(cls); } } // namespace OCIO_NAMESPACE diff --git a/src/bindings/python/PyCDLTransform.cpp b/src/bindings/python/PyCDLTransform.cpp index 4e7bdfa638..801ae24ef2 100644 --- a/src/bindings/python/PyCDLTransform.cpp +++ b/src/bindings/python/PyCDLTransform.cpp @@ -19,9 +19,9 @@ void bindPyCDLTransform(py::module & m) std::array DEFAULT_POWER; DEFAULT->getPower(DEFAULT_POWER.data()); - py::class_(m, "CDLTransform") + auto cls = py::class_(m, "CDLTransform") .def(py::init(&CDLTransform::Create)) .def(py::init([](const std::string & xml, TransformDirection dir) { @@ -32,7 +32,7 @@ void bindPyCDLTransform(py::module & m) return p; }), "xml"_a, - "dir"_a = DEFAULT->getDirection()) + "direction"_a = DEFAULT->getDirection()) .def(py::init([](const std::array & slope, const std::array & offset, const std::array & power, @@ -57,10 +57,10 @@ void bindPyCDLTransform(py::module & m) "power"_a = DEFAULT_POWER, "sat"_a = DEFAULT->getSat(), "id"_a = DEFAULT->getID(), - "desc"_a = DEFAULT->getDescription(), - "dir"_a = DEFAULT->getDirection()) + "description"_a = DEFAULT->getDescription(), + "direction"_a = DEFAULT->getDirection()) - .def_static("CreateFromFile", &CDLTransform::CreateFromFile, "src"_a, "cccid"_a) + .def_static("CreateFromFile", &CDLTransform::CreateFromFile, "src"_a, "id"_a) .def("getFormatMetadata", (FormatMetadata & (CDLTransform::*)()) &CDLTransform::getFormatMetadata, @@ -129,7 +129,9 @@ void bindPyCDLTransform(py::module & m) .def("getID", &CDLTransform::getID) .def("setID", &CDLTransform::setID, "id"_a) .def("getDescription", &CDLTransform::getDescription) - .def("setDescription", &CDLTransform::setDescription, "desc"_a); + .def("setDescription", &CDLTransform::setDescription, "description"_a); + + defStr(cls); } } // namespace OCIO_NAMESPACE diff --git a/src/bindings/python/PyColorSpace.cpp b/src/bindings/python/PyColorSpace.cpp index cc20c0d191..38a4e0ebf1 100644 --- a/src/bindings/python/PyColorSpace.cpp +++ b/src/bindings/python/PyColorSpace.cpp @@ -155,8 +155,8 @@ void bindPyColorSpace(py::module & m) "vars"_a) // Transform - .def("getTransform", &ColorSpace::getTransform, "dir"_a) - .def("setTransform", &ColorSpace::setTransform, "transform"_a, "dir"_a); + .def("getTransform", &ColorSpace::getTransform, "direction"_a) + .def("setTransform", &ColorSpace::setTransform, "transform"_a, "direction"_a); defStr(cls); diff --git a/src/bindings/python/PyColorSpaceSet.cpp b/src/bindings/python/PyColorSpaceSet.cpp index 4fa33a3f7c..6cb2443db4 100644 --- a/src/bindings/python/PyColorSpaceSet.cpp +++ b/src/bindings/python/PyColorSpaceSet.cpp @@ -55,10 +55,10 @@ void bindPyColorSpaceSet(py::module & m) return ColorSpaceIterator(self); }) .def("getColorSpace", &ColorSpaceSet::getColorSpace, "name"_a) - .def("addColorSpace", &ColorSpaceSet::addColorSpace, "cs"_a) - .def("addColorSpaces", &ColorSpaceSet::addColorSpaces, "cs"_a) - .def("removeColorSpace", &ColorSpaceSet::removeColorSpace, "cs"_a) - .def("removeColorSpaces", &ColorSpaceSet::removeColorSpaces, "cs"_a) + .def("addColorSpace", &ColorSpaceSet::addColorSpace, "colorSpace"_a) + .def("addColorSpaces", &ColorSpaceSet::addColorSpaces, "colorSpace"_a) + .def("removeColorSpace", &ColorSpaceSet::removeColorSpace, "colorSpace"_a) + .def("removeColorSpaces", &ColorSpaceSet::removeColorSpaces, "colorSpace"_a) .def("clearColorSpaces", &ColorSpaceSet::clearColorSpaces); py::class_(cls, "ColorSpaceNameIterator") diff --git a/src/bindings/python/PyColorSpaceTransform.cpp b/src/bindings/python/PyColorSpaceTransform.cpp index 9dfd81e201..352b94ed2f 100644 --- a/src/bindings/python/PyColorSpaceTransform.cpp +++ b/src/bindings/python/PyColorSpaceTransform.cpp @@ -10,9 +10,9 @@ void bindPyColorSpaceTransform(py::module & m) { ColorSpaceTransformRcPtr DEFAULT = ColorSpaceTransform::Create(); - py::class_(m, "ColorSpaceTransform") + auto cls = py::class_(m, "ColorSpaceTransform") .def(py::init(&ColorSpaceTransform::Create)) .def(py::init([](const std::string & src, const std::string & dst, @@ -38,6 +38,8 @@ void bindPyColorSpaceTransform(py::module & m) .def("setDst", &ColorSpaceTransform::setDst, "dst"_a) .def("getDataBypass", &ColorSpaceTransform::getDataBypass) .def("setDataBypass", &ColorSpaceTransform::setDataBypass, "dataBypass"_a); + + defStr(cls); } } // namespace OCIO_NAMESPACE diff --git a/src/bindings/python/PyConfig.cpp b/src/bindings/python/PyConfig.cpp index c64ba1f017..bd69942e50 100644 --- a/src/bindings/python/PyConfig.cpp +++ b/src/bindings/python/PyConfig.cpp @@ -65,7 +65,7 @@ void bindPyConfig(py::module & m) .def_static("CreateRaw", &Config::CreateRaw) .def_static("CreateFromEnv", &Config::CreateFromEnv) - .def_static("CreateFromFile", &Config::CreateFromFile, "filename"_a) + .def_static("CreateFromFile", &Config::CreateFromFile, "fileName"_a) .def_static("CreateFromStream", [](const std::string & str) { std::istringstream is(str); @@ -119,7 +119,7 @@ void bindPyConfig(py::module & m) .def("clearSearchPaths", &Config::clearSearchPaths) .def("addSearchPath", &Config::addSearchPath, "path"_a) .def("getWorkingDir", &Config::getWorkingDir) - .def("setWorkingDir", &Config::setWorkingDir, "dirname"_a) + .def("setWorkingDir", &Config::setWorkingDir, "dirName"_a) // ColorSpaces .def("getColorSpaces", &Config::getColorSpaces, "category"_a) @@ -146,7 +146,7 @@ void bindPyConfig(py::module & m) { return ActiveColorSpaceIterator(self); }) - .def("addColorSpace", &Config::addColorSpace, "cs"_a) + .def("addColorSpace", &Config::addColorSpace, "colorSpace"_a) .def("removeColorSpace", &Config::removeColorSpace, "name"_a) .def("isColorSpaceUsed", &Config::isColorSpaceUsed, "name"_a) .def("clearColorSpaces", &Config::clearColorSpaces) diff --git a/src/bindings/python/PyContext.cpp b/src/bindings/python/PyContext.cpp index 6adc6c6d07..74eff5e1f4 100644 --- a/src/bindings/python/PyContext.cpp +++ b/src/bindings/python/PyContext.cpp @@ -123,14 +123,14 @@ void bindPyContext(py::module & m) .def("clearSearchPaths", &Context::clearSearchPaths) .def("addSearchPath", &Context::addSearchPath, "path"_a) .def("getWorkingDir", &Context::getWorkingDir) - .def("setWorkingDir", &Context::setWorkingDir, "dirname"_a) + .def("setWorkingDir", &Context::setWorkingDir, "dirName"_a) .def("getStringVars", [](ContextRcPtr & self) { return StringVarIterator(self); }) .def("clearStringVars", &Context::clearStringVars) .def("getEnvironmentMode", &Context::getEnvironmentMode) .def("setEnvironmentMode", &Context::setEnvironmentMode, "mode"_a) .def("loadEnvironment", &Context::loadEnvironment) - .def("resolveStringVar", &Context::resolveStringVar, "val"_a) - .def("resolveFileLocation", &Context::resolveFileLocation, "filename"_a); + .def("resolveStringVar", &Context::resolveStringVar, "value"_a) + .def("resolveFileLocation", &Context::resolveFileLocation, "fileName"_a); defStr(cls); diff --git a/src/bindings/python/PyDisplayViewTransform.cpp b/src/bindings/python/PyDisplayViewTransform.cpp index c75021c459..2c2af6485c 100644 --- a/src/bindings/python/PyDisplayViewTransform.cpp +++ b/src/bindings/python/PyDisplayViewTransform.cpp @@ -10,9 +10,9 @@ void bindPyDisplayViewTransform(py::module & m) { DisplayViewTransformRcPtr DEFAULT = DisplayViewTransform::Create(); - py::class_(m, "DisplayViewTransform") + auto cls = py::class_(m, "DisplayViewTransform") .def(py::init(&DisplayViewTransform::Create)) .def(py::init([](const std::string & src, const std::string & display, @@ -36,7 +36,7 @@ void bindPyDisplayViewTransform(py::module & m) "view"_a = DEFAULT->getView(), "looksBypass"_a = DEFAULT->getLooksBypass(), "dataBypass"_a = DEFAULT->getDataBypass(), - "dir"_a = DEFAULT->getDirection()) + "direction"_a = DEFAULT->getDirection()) .def("getSrc", &DisplayViewTransform::getSrc) .def("setSrc", &DisplayViewTransform::setSrc, "src"_a) @@ -48,6 +48,8 @@ void bindPyDisplayViewTransform(py::module & m) .def("setLooksBypass", &DisplayViewTransform::setLooksBypass, "looksBypass"_a) .def("getDataBypass", &DisplayViewTransform::getDataBypass) .def("setDataBypass", &DisplayViewTransform::setDataBypass, "dataBypass"_a); + + defStr(cls); } } // namespace OCIO_NAMESPACE diff --git a/src/bindings/python/PyExponentTransform.cpp b/src/bindings/python/PyExponentTransform.cpp index 940deab3af..b9127a0541 100644 --- a/src/bindings/python/PyExponentTransform.cpp +++ b/src/bindings/python/PyExponentTransform.cpp @@ -10,12 +10,12 @@ void bindPyExponentTransform(py::module & m) { ExponentTransformRcPtr DEFAULT = ExponentTransform::Create(); - std::array DEFAULT_VEC4; - DEFAULT->getValue(*reinterpret_cast(DEFAULT_VEC4.data())); + std::array DEFAULT_VALUE; + DEFAULT->getValue(*reinterpret_cast(DEFAULT_VALUE.data())); - py::class_(m, "ExponentTransform") + auto cls = py::class_(m, "ExponentTransform") .def(py::init(&ExponentTransform::Create)) .def(py::init([](const std::array & vec4, NegativeStyle negativeStyle, @@ -28,9 +28,9 @@ void bindPyExponentTransform(py::module & m) p->validate(); return p; }), - "vec4"_a = DEFAULT_VEC4, + "value"_a = DEFAULT_VALUE, "negativeStyle"_a = DEFAULT->getNegativeStyle(), - "dir"_a = DEFAULT->getDirection()) + "direction"_a = DEFAULT->getDirection()) .def("getFormatMetadata", (FormatMetadata & (ExponentTransform::*)()) &ExponentTransform::getFormatMetadata, @@ -50,9 +50,11 @@ void bindPyExponentTransform(py::module & m) { self->setValue(*reinterpret_cast(vec4.data())); }, - "vec4"_a) + "value"_a) .def("getNegativeStyle", &ExponentTransform::getNegativeStyle) .def("setNegativeStyle", &ExponentTransform::setNegativeStyle, "style"_a); + + defStr(cls); } } // namespace OCIO_NAMESPACE diff --git a/src/bindings/python/PyExponentWithLinearTransform.cpp b/src/bindings/python/PyExponentWithLinearTransform.cpp index 1d7ab4240a..3e587e3889 100644 --- a/src/bindings/python/PyExponentWithLinearTransform.cpp +++ b/src/bindings/python/PyExponentWithLinearTransform.cpp @@ -16,9 +16,9 @@ void bindPyExponentWithLinearTransform(py::module & m) std::array DEFAULT_OFFSET; DEFAULT->getOffset(*reinterpret_cast(DEFAULT_OFFSET.data())); - py::class_(m, "ExponentWithLinearTransform") + auto cls = py::class_(m, "ExponentWithLinearTransform") .def(py::init(&ExponentWithLinearTransform::Create)) .def(py::init([](const std::array & gamma, const std::array & offset, @@ -36,7 +36,7 @@ void bindPyExponentWithLinearTransform(py::module & m) "gamma"_a = DEFAULT_GAMMA, "offset"_a = DEFAULT_OFFSET, "negativeStyle"_a = DEFAULT->getNegativeStyle(), - "dir"_a = DEFAULT->getDirection()) + "direction"_a = DEFAULT->getDirection()) .def("getFormatMetadata", (FormatMetadata & (ExponentWithLinearTransform::*)()) @@ -73,6 +73,8 @@ void bindPyExponentWithLinearTransform(py::module & m) "values"_a) .def("getNegativeStyle", &ExponentWithLinearTransform::getNegativeStyle) .def("setNegativeStyle", &ExponentWithLinearTransform::setNegativeStyle, "style"_a); + + defStr(cls); } } // namespace OCIO_NAMESPACE diff --git a/src/bindings/python/PyExposureContrastTransform.cpp b/src/bindings/python/PyExposureContrastTransform.cpp index 57fca2fcb4..716088f224 100644 --- a/src/bindings/python/PyExposureContrastTransform.cpp +++ b/src/bindings/python/PyExposureContrastTransform.cpp @@ -10,9 +10,9 @@ void bindPyExposureContrastTransform(py::module & m) { ExposureContrastTransformRcPtr DEFAULT = ExposureContrastTransform::Create(); - py::class_(m, "ExposureContrastTransform") + auto cls = py::class_(m, "ExposureContrastTransform") .def(py::init(&ExposureContrastTransform::Create)) .def(py::init([](ExposureContrastStyle style, double exposure, @@ -50,7 +50,7 @@ void bindPyExposureContrastTransform(py::module & m) "dynamicExposure"_a = DEFAULT->isExposureDynamic(), "dynamicContrast"_a = DEFAULT->isContrastDynamic(), "dynamicGamma"_a = DEFAULT->isGammaDynamic(), - "dir"_a = DEFAULT->getDirection()) + "direction"_a = DEFAULT->getDirection()) .def("getFormatMetadata", (FormatMetadata & (ExposureContrastTransform::*)()) @@ -82,6 +82,8 @@ void bindPyExposureContrastTransform(py::module & m) "logExposureStep"_a) .def("getLogMidGray", &ExposureContrastTransform::getLogMidGray) .def("setLogMidGray", &ExposureContrastTransform::setLogMidGray, "logMidGray"_a); + + defStr(cls); } } // namespace OCIO_NAMESPACE diff --git a/src/bindings/python/PyFileTransform.cpp b/src/bindings/python/PyFileTransform.cpp index a1e7709079..b6987fdfd1 100644 --- a/src/bindings/python/PyFileTransform.cpp +++ b/src/bindings/python/PyFileTransform.cpp @@ -40,20 +40,22 @@ void bindPyFileTransform(py::module & m) return p; }), "src"_a = DEFAULT->getSrc(), - "id"_a = DEFAULT->getCCCId(), - "interp"_a = DEFAULT->getInterpolation(), - "dir"_a = DEFAULT->getDirection()) + "cccId"_a = DEFAULT->getCCCId(), + "interpolation"_a = DEFAULT->getInterpolation(), + "direction"_a = DEFAULT->getDirection()) .def_static("getFormats", []() { return FormatIterator(nullptr); }) .def("getSrc", &FileTransform::getSrc) .def("setSrc", &FileTransform::setSrc, "src"_a) .def("getCCCId", &FileTransform::getCCCId) - .def("setCCCId", &FileTransform::setCCCId, "id"_a) + .def("setCCCId", &FileTransform::setCCCId, "cccId"_a) .def("getCDLStyle", &FileTransform::getCDLStyle) .def("setCDLStyle", &FileTransform::setCDLStyle, "style"_a) .def("getInterpolation", &FileTransform::getInterpolation) - .def("setInterpolation", &FileTransform::setInterpolation, "interp"_a); + .def("setInterpolation", &FileTransform::setInterpolation, "interpolation"_a); + + defStr(cls); py::class_(cls, "FormatIterator") .def("__len__", [](FormatIterator & it) { return FileTransform::getNumFormats(); }) diff --git a/src/bindings/python/PyFixedFunctionTransform.cpp b/src/bindings/python/PyFixedFunctionTransform.cpp index 242da2ef7a..62aac86fea 100644 --- a/src/bindings/python/PyFixedFunctionTransform.cpp +++ b/src/bindings/python/PyFixedFunctionTransform.cpp @@ -19,9 +19,9 @@ void bindPyFixedFunctionTransform(py::module & m) { FixedFunctionTransformRcPtr DEFAULT = FixedFunctionTransform::Create(); - py::class_(m, "FixedFunctionTransform") + auto cls = py::class_(m, "FixedFunctionTransform") .def(py::init(&FixedFunctionTransform::Create)) .def(py::init([](FixedFunctionStyle style, const std::vector & params, @@ -36,7 +36,7 @@ void bindPyFixedFunctionTransform(py::module & m) }), "style"_a = DEFAULT->getStyle(), "params"_a = getParamsStdVec(DEFAULT), - "dir"_a = DEFAULT->getDirection()) + "direction"_a = DEFAULT->getDirection()) .def("getFormatMetadata", (FormatMetadata & (FixedFunctionTransform::*)()) @@ -58,6 +58,8 @@ void bindPyFixedFunctionTransform(py::module & m) self->setParams(params.data(), params.size()); }, "params"_a); + + defStr(cls); } } // namespace OCIO_NAMESPACE diff --git a/src/bindings/python/PyGpuShaderCreator.cpp b/src/bindings/python/PyGpuShaderCreator.cpp index 98cffc79ea..9dff22332c 100644 --- a/src/bindings/python/PyGpuShaderCreator.cpp +++ b/src/bindings/python/PyGpuShaderCreator.cpp @@ -150,7 +150,7 @@ void bindPyGpuShaderCreator(py::module & m) .def("getUniqueID", &GpuShaderCreator::getUniqueID) .def("setUniqueID", &GpuShaderCreator::setUniqueID, "uid"_a) .def("getLanguage", &GpuShaderCreator::getUniqueID) - .def("setLanguage", &GpuShaderCreator::setUniqueID, "lang"_a) + .def("setLanguage", &GpuShaderCreator::setUniqueID, "language"_a) .def("getFunctionName", &GpuShaderCreator::getFunctionName) .def("setFunctionName", &GpuShaderCreator::setFunctionName, "name"_a) .def("getPixelName", &GpuShaderCreator::getPixelName) @@ -168,7 +168,7 @@ void bindPyGpuShaderCreator(py::module & m) "textureName"_a, "samplerName"_a, "uid"_a, "width"_a, "height"_a, "channel"_a, "interpolation"_a, "values"_a) .def("add3DTexture", &GpuShaderCreator::add3DTexture, - "textureName"_a, "samplerName"_a, "uid"_a, "edgelen"_a, "interpolation"_a, "values"_a) + "textureName"_a, "samplerName"_a, "uid"_a, "edgeLen"_a, "interpolation"_a, "values"_a) // Methods to specialize parts of a OCIO shader program .def("addToDeclareShaderCode", &GpuShaderCreator::addToDeclareShaderCode, "shaderCode"_a) diff --git a/src/bindings/python/PyGpuShaderDesc.cpp b/src/bindings/python/PyGpuShaderDesc.cpp index 31a3deb0d0..619d41d754 100644 --- a/src/bindings/python/PyGpuShaderDesc.cpp +++ b/src/bindings/python/PyGpuShaderDesc.cpp @@ -64,8 +64,8 @@ void bindPyGpuShaderDesc(py::module & m) if (!uid.empty()) { p->setUniqueID(uid.c_str()); } return p; }, - "edgelen"_a, - "lang"_a = DEFAULT->getLanguage(), + "edgeLen"_a, + "language"_a = DEFAULT->getLanguage(), "functionName"_a = DEFAULT->getFunctionName(), "pixelName"_a = DEFAULT->getPixelName(), "resourcePrefix"_a = DEFAULT->getResourcePrefix(), @@ -84,7 +84,7 @@ void bindPyGpuShaderDesc(py::module & m) if (!uid.empty()) { p->setUniqueID(uid.c_str()); } return p; }, - "lang"_a = DEFAULT->getLanguage(), + "language"_a = DEFAULT->getLanguage(), "functionName"_a = DEFAULT->getFunctionName(), "pixelName"_a = DEFAULT->getPixelName(), "resourcePrefix"_a = DEFAULT->getResourcePrefix(), @@ -204,7 +204,7 @@ void bindPyGpuShaderDesc(py::module & m) interpolation, static_cast(info.ptr)); }, - "textureName"_a, "samplerName"_a, "uid"_a, "edgelen"_a, "interpolation"_a, "values"_a) + "textureName"_a, "samplerName"_a, "uid"_a, "edgeLen"_a, "interpolation"_a, "values"_a) .def("get3DTextures", [](GpuShaderDescRcPtr & self) { return Texture3DIterator(self); @@ -301,7 +301,7 @@ void bindPyGpuShaderDesc(py::module & m) .def_readonly("textureName", &Texture3D::textureName) .def_readonly("samplerName", &Texture3D::samplerName) .def_readonly("uid", &Texture3D::uid) - .def_readonly("edgelen", &Texture3D::edgelen) + .def_readonly("edgeLen", &Texture3D::edgelen) .def_readonly("interpolation", &Texture3D::interpolation); py::class_(cls, "Texture3DIterator") diff --git a/src/bindings/python/PyGroupTransform.cpp b/src/bindings/python/PyGroupTransform.cpp index 8c07e790b6..4c49ca4901 100644 --- a/src/bindings/python/PyGroupTransform.cpp +++ b/src/bindings/python/PyGroupTransform.cpp @@ -38,7 +38,7 @@ void bindPyGroupTransform(py::module & m) return p; }), "transforms"_a = std::vector{}, - "dir"_a = DEFAULT->getDirection()) + "direction"_a = DEFAULT->getDirection()) .def("__iter__", [](GroupTransformRcPtr & self) { return TransformIterator(self); }) .def("__len__", &GroupTransform::getNumTransforms) @@ -59,6 +59,8 @@ void bindPyGroupTransform(py::module & m) .def("appendTransform", &GroupTransform::appendTransform, "transform"_a) .def("prependTransform", &GroupTransform::prependTransform, "transform"_a); + defStr(cls); + py::class_(cls, "TransformIterator") .def("__len__", [](TransformIterator & it) { return it.m_obj->getNumTransforms(); }) .def("__getitem__", [](TransformIterator & it, int i) diff --git a/src/bindings/python/PyLogAffineTransform.cpp b/src/bindings/python/PyLogAffineTransform.cpp index ac1888b1fb..782bf9b0f3 100644 --- a/src/bindings/python/PyLogAffineTransform.cpp +++ b/src/bindings/python/PyLogAffineTransform.cpp @@ -22,9 +22,9 @@ void bindPyLogAffineTransform(py::module & m) std::array DEFAULT_LIN_SIDE_OFFSET; DEFAULT->getLinSideOffsetValue(*reinterpret_cast(DEFAULT_LIN_SIDE_OFFSET.data())); - py::class_(m, "LogAffineTransform") + auto cls = py::class_(m, "LogAffineTransform") .def(py::init(&LogAffineTransform::Create)) .def(py::init([](const std::array & logSideSlope, const std::array & logSideOffset, @@ -45,7 +45,7 @@ void bindPyLogAffineTransform(py::module & m) "logSideOffset"_a = DEFAULT_LOG_SIDE_OFFSET, "linSideSlope"_a = DEFAULT_LIN_SIDE_SLOPE, "linSideOffset"_a = DEFAULT_LIN_SIDE_OFFSET, - "dir"_a = DEFAULT->getDirection()) + "direction"_a = DEFAULT->getDirection()) .def("getFormatMetadata", (FormatMetadata & (LogAffineTransform::*)()) &LogAffineTransform::getFormatMetadata, @@ -105,6 +105,8 @@ void bindPyLogAffineTransform(py::module & m) self->setLinSideOffsetValue(*reinterpret_cast(values.data())); }, "values"_a); + + defStr(cls); } } // namespace OCIO_NAMESPACE diff --git a/src/bindings/python/PyLogCameraTransform.cpp b/src/bindings/python/PyLogCameraTransform.cpp index c8f92bc4a6..da19739212 100644 --- a/src/bindings/python/PyLogCameraTransform.cpp +++ b/src/bindings/python/PyLogCameraTransform.cpp @@ -27,9 +27,9 @@ void bindPyLogCameraTransform(py::module & m) std::array DEFAULT_LIN_SIDE_OFFSET; DEFAULT->getLinSideOffsetValue(*reinterpret_cast(DEFAULT_LIN_SIDE_OFFSET.data())); - py::class_(m, "LogCameraTransform") + auto cls = py::class_(m, "LogCameraTransform") .def(py::init(&LogCameraTransform::Create)) .def(py::init([](const std::array & linSideBreak, const std::array & logSideSlope, @@ -53,7 +53,7 @@ void bindPyLogCameraTransform(py::module & m) "logSideOffset"_a = DEFAULT_LOG_SIDE_OFFSET, "linSideSlope"_a = DEFAULT_LIN_SIDE_SLOPE, "linSideOffset"_a = DEFAULT_LIN_SIDE_OFFSET, - "dir"_a = DEFAULT->getDirection()) + "direction"_a = DEFAULT->getDirection()) .def("getFormatMetadata", (FormatMetadata & (LogCameraTransform::*)()) &LogCameraTransform::getFormatMetadata, @@ -138,6 +138,8 @@ void bindPyLogCameraTransform(py::module & m) }, "values"_a) .def("unsetLinearSlopeValue", &LogCameraTransform::unsetLinearSlopeValue); + + defStr(cls); } } // namespace OCIO_NAMESPACE diff --git a/src/bindings/python/PyLogTransform.cpp b/src/bindings/python/PyLogTransform.cpp index c017cca769..ee24a4d19c 100644 --- a/src/bindings/python/PyLogTransform.cpp +++ b/src/bindings/python/PyLogTransform.cpp @@ -10,9 +10,9 @@ void bindPyLogTransform(py::module & m) { LogTransformRcPtr DEFAULT = LogTransform::Create(); - py::class_(m, "LogTransform") + auto cls = py::class_(m, "LogTransform") .def(py::init(&LogTransform::Create)) .def(py::init([](double base, TransformDirection dir) @@ -24,7 +24,7 @@ void bindPyLogTransform(py::module & m) return p; }), "base"_a = DEFAULT->getBase(), - "dir"_a = DEFAULT->getDirection()) + "direction"_a = DEFAULT->getDirection()) .def("getFormatMetadata", (FormatMetadata & (LogTransform::*)()) &LogTransform::getFormatMetadata, @@ -34,7 +34,9 @@ void bindPyLogTransform(py::module & m) py::return_value_policy::reference_internal) .def("equals", &LogTransform::equals, "other"_a) .def("getBase", &LogTransform::getBase) - .def("setBase", &LogTransform::setBase, "val"_a); + .def("setBase", &LogTransform::setBase, "base"_a); + + defStr(cls); } } // namespace OCIO_NAMESPACE diff --git a/src/bindings/python/PyLookTransform.cpp b/src/bindings/python/PyLookTransform.cpp index 275a322e49..a239eb2460 100644 --- a/src/bindings/python/PyLookTransform.cpp +++ b/src/bindings/python/PyLookTransform.cpp @@ -10,9 +10,9 @@ void bindPyLookTransform(py::module & m) { LookTransformRcPtr DEFAULT = LookTransform::Create(); - py::class_(m, "LookTransform") + auto cls = py::class_(m, "LookTransform") .def(py::init(&LookTransform::Create)) .def(py::init([](const std::string & src, const std::string & dst, @@ -29,10 +29,10 @@ void bindPyLookTransform(py::module & m) p->validate(); return p; }), - "src"_a = DEFAULT->getSrc(), - "dst"_a = DEFAULT->getDst(), + "src"_a = DEFAULT->getSrc(), + "dst"_a = DEFAULT->getDst(), "looks"_a = DEFAULT->getLooks(), - "dir"_a = DEFAULT->getDirection(), + "direction"_a = DEFAULT->getDirection(), "skipColorSpaceConversion"_a = DEFAULT->getSkipColorSpaceConversion()) .def("getSrc", &LookTransform::getSrc) @@ -44,6 +44,8 @@ void bindPyLookTransform(py::module & m) .def("getSkipColorSpaceConversion", &LookTransform::getSkipColorSpaceConversion) .def("setSkipColorSpaceConversion", &LookTransform::setSkipColorSpaceConversion, "skipColorSpaceConversion"_a); + + defStr(cls); } } // namespace OCIO_NAMESPACE diff --git a/src/bindings/python/PyLut1DTransform.cpp b/src/bindings/python/PyLut1DTransform.cpp index 463c0394ab..dd9468b144 100644 --- a/src/bindings/python/PyLut1DTransform.cpp +++ b/src/bindings/python/PyLut1DTransform.cpp @@ -10,15 +10,15 @@ void bindPyLut1DTransform(py::module & m) { Lut1DTransformRcPtr DEFAULT = Lut1DTransform::Create(); - py::class_(m, "Lut1DTransform") + auto cls = py::class_(m, "Lut1DTransform") .def(py::init([]() { return Lut1DTransform::Create(); })) .def(py::init([](unsigned long length, bool isHalfDomain) { return Lut1DTransform::Create(length, isHalfDomain); }), - "length"_a, "isHalfDomain"_a) + "length"_a, "inputHalfDomain"_a) .def(py::init([](unsigned long length, bool isHalfDomain, bool isRawHalfs, @@ -37,12 +37,12 @@ void bindPyLut1DTransform(py::module & m) return p; }), "length"_a = DEFAULT->getLength(), - "isHalfDomain"_a = DEFAULT->getInputHalfDomain(), - "isRawHalfs"_a = DEFAULT->getOutputRawHalfs(), + "inputHalfDomain"_a = DEFAULT->getInputHalfDomain(), + "outputRawHalfs"_a = DEFAULT->getOutputRawHalfs(), "fileOutputBitDepth"_a = DEFAULT->getFileOutputBitDepth(), "hueAdjust"_a = DEFAULT->getHueAdjust(), "interpolation"_a = DEFAULT->getInterpolation(), - "dir"_a = DEFAULT->getDirection()) + "direction"_a = DEFAULT->getDirection()) .def("getFileOutputBitDepth", &Lut1DTransform::getFileOutputBitDepth) .def("setFileOutputBitDepth", &Lut1DTransform::setFileOutputBitDepth, "bitDepth"_a) @@ -111,9 +111,11 @@ void bindPyLut1DTransform(py::module & m) .def("getOutputRawHalfs", &Lut1DTransform::getOutputRawHalfs) .def("setOutputRawHalfs", &Lut1DTransform::setOutputRawHalfs, "isRawHalfs"_a) .def("getHueAdjust", &Lut1DTransform::getHueAdjust) - .def("setHueAdjust", &Lut1DTransform::setHueAdjust, "algo"_a) + .def("setHueAdjust", &Lut1DTransform::setHueAdjust, "hueAdjust"_a) .def("getInterpolation", &Lut1DTransform::getInterpolation) - .def("setInterpolation", &Lut1DTransform::setInterpolation, "algo"_a); + .def("setInterpolation", &Lut1DTransform::setInterpolation, "interpolation"_a); + + defStr(cls); } } // namespace OCIO_NAMESPACE diff --git a/src/bindings/python/PyLut3DTransform.cpp b/src/bindings/python/PyLut3DTransform.cpp index 0dbbab0cba..bbce1a221c 100644 --- a/src/bindings/python/PyLut3DTransform.cpp +++ b/src/bindings/python/PyLut3DTransform.cpp @@ -12,9 +12,9 @@ void bindPyLut3DTransform(py::module & m) { Lut3DTransformRcPtr DEFAULT = Lut3DTransform::Create(); - py::class_(m, "Lut3DTransform") + auto cls = py::class_(m, "Lut3DTransform") .def(py::init([]() { return Lut3DTransform::Create(); })) .def(py::init([](unsigned long gridSize) { @@ -36,7 +36,7 @@ void bindPyLut3DTransform(py::module & m) "gridSize"_a = DEFAULT->getGridSize(), "fileOutputBitDepth"_a = DEFAULT->getFileOutputBitDepth(), "interpolation"_a = DEFAULT->getInterpolation(), - "dir"_a = DEFAULT->getDirection()) + "direction"_a = DEFAULT->getDirection()) .def("getFileOutputBitDepth", &Lut3DTransform::getFileOutputBitDepth) .def("setFileOutputBitDepth", &Lut3DTransform::setFileOutputBitDepth, "bitDepth"_a) @@ -122,7 +122,9 @@ void bindPyLut3DTransform(py::module & m) values.data()); }) .def("getInterpolation", &Lut3DTransform::getInterpolation) - .def("setInterpolation", &Lut3DTransform::setInterpolation, "algo"_a); + .def("setInterpolation", &Lut3DTransform::setInterpolation, "interpolation"_a); + + defStr(cls); } } // namespace OCIO_NAMESPACE diff --git a/src/bindings/python/PyMatrixTransform.cpp b/src/bindings/python/PyMatrixTransform.cpp index 2c63733462..48057b7be7 100644 --- a/src/bindings/python/PyMatrixTransform.cpp +++ b/src/bindings/python/PyMatrixTransform.cpp @@ -10,15 +10,15 @@ void bindPyMatrixTransform(py::module & m) { MatrixTransformRcPtr DEFAULT = MatrixTransform::Create(); - std::array DEFAULT_M44; - DEFAULT->getMatrix(DEFAULT_M44.data()); + std::array DEFAULT_MATRIX; + DEFAULT->getMatrix(DEFAULT_MATRIX.data()); - std::array DEFAULT_OFFSET4; - DEFAULT->getOffset(DEFAULT_OFFSET4.data()); + std::array DEFAULT_OFFSET; + DEFAULT->getOffset(DEFAULT_OFFSET.data()); - py::class_(m, "MatrixTransform") + auto cls = py::class_(m, "MatrixTransform") .def(py::init(&MatrixTransform::Create)) .def(py::init([](const std::array & m44, const std::array & offset4, @@ -31,9 +31,9 @@ void bindPyMatrixTransform(py::module & m) p->validate(); return p; }), - "m44"_a = DEFAULT_M44, - "offset4"_a = DEFAULT_OFFSET4, - "dir"_a = DEFAULT->getDirection()) + "matrix"_a = DEFAULT_MATRIX, + "offset"_a = DEFAULT_OFFSET, + "direction"_a = DEFAULT->getDirection()) // TODO: Update static convenience functions to construct a MatrixTransform in C++ .def_static("Fit", [](const std::array & oldmin4, @@ -52,10 +52,10 @@ void bindPyMatrixTransform(py::module & m) p->validate(); return p; }, - "oldmin4"_a = std::array{ 0.0, 0.0, 0.0, 0.0 }, - "oldmax4"_a = std::array{ 1.0, 1.0, 1.0, 1.0 }, - "newmin4"_a = std::array{ 0.0, 0.0, 0.0, 0.0 }, - "newmax4"_a = std::array{ 1.0, 1.0, 1.0, 1.0 }) + "oldMin"_a = std::array{ 0.0, 0.0, 0.0, 0.0 }, + "oldMax"_a = std::array{ 1.0, 1.0, 1.0, 1.0 }, + "newMin"_a = std::array{ 0.0, 0.0, 0.0, 0.0 }, + "newMax"_a = std::array{ 1.0, 1.0, 1.0, 1.0 }) .def_static("Identity", []() { double m44[16]; @@ -78,7 +78,7 @@ void bindPyMatrixTransform(py::module & m) p->validate(); return p; }, - "sat"_a, "lumaCoef3"_a) + "sat"_a, "lumaCoef"_a) .def_static("Scale", [](const std::array & scale4) { double m44[16]; @@ -90,7 +90,7 @@ void bindPyMatrixTransform(py::module & m) p->validate(); return p; }, - "scale4"_a) + "scale"_a) .def_static("View", [](std::array & channelHot4, const std::array & lumaCoef3) { @@ -103,7 +103,7 @@ void bindPyMatrixTransform(py::module & m) p->validate(); return p; }, - "channelHot4"_a, "scale4"_a) + "channelHot"_a, "lumaCoef"_a) .def("getFormatMetadata", (FormatMetadata & (MatrixTransform::*)()) &MatrixTransform::getFormatMetadata, @@ -123,7 +123,7 @@ void bindPyMatrixTransform(py::module & m) { self->setMatrix(m44.data()); }, - "m44"_a) + "matrix"_a) .def("getOffset", [](MatrixTransformRcPtr self) { std::array offset4; @@ -134,11 +134,13 @@ void bindPyMatrixTransform(py::module & m) { self->setOffset(offset4.data()); }, - "offset4"_a) + "offset"_a) .def("getFileInputBitDepth", &MatrixTransform::getFileInputBitDepth) .def("setFileInputBitDepth", &MatrixTransform::setFileInputBitDepth, "bitDepth"_a) .def("getFileOutputBitDepth", &MatrixTransform::getFileOutputBitDepth) .def("setFileOutputBitDepth", &MatrixTransform::setFileOutputBitDepth, "bitDepth"_a); + + defStr(cls); } } // namespace OCIO_NAMESPACE diff --git a/src/bindings/python/PyProcessorMetadata.cpp b/src/bindings/python/PyProcessorMetadata.cpp index 8889f6713a..ea801d510e 100644 --- a/src/bindings/python/PyProcessorMetadata.cpp +++ b/src/bindings/python/PyProcessorMetadata.cpp @@ -30,7 +30,7 @@ void bindPyProcessorMetadata(py::module & m) .def("getFiles", [](ProcessorMetadataRcPtr & self) { return FileIterator(self); }) .def("getLooks", [](ProcessorMetadataRcPtr & self) { return LookIterator(self); }) - .def("addFile", &ProcessorMetadata::addFile, "fname"_a) + .def("addFile", &ProcessorMetadata::addFile, "fileName"_a) .def("addLook", &ProcessorMetadata::addLook, "look"_a); py::class_(cls, "FileIterator") diff --git a/src/bindings/python/PyRangeTransform.cpp b/src/bindings/python/PyRangeTransform.cpp index 9af8775f73..47eb058999 100644 --- a/src/bindings/python/PyRangeTransform.cpp +++ b/src/bindings/python/PyRangeTransform.cpp @@ -10,9 +10,9 @@ void bindPyRangeTransform(py::module & m) { RangeTransformRcPtr DEFAULT = RangeTransform::Create(); - py::class_(m, "RangeTransform") + auto cls = py::class_(m, "RangeTransform") .def(py::init(&RangeTransform::Create)) .def(py::init([](double minInValue, double maxInValue, @@ -33,7 +33,7 @@ void bindPyRangeTransform(py::module & m) "maxInValue"_a = DEFAULT->getMaxInValue(), "minOutValue"_a = DEFAULT->getMinOutValue(), "maxOutValue"_a = DEFAULT->getMaxOutValue(), - "dir"_a = DEFAULT->getDirection()) + "direction"_a = DEFAULT->getDirection()) .def("getStyle", &RangeTransform::getStyle) .def("setStyle", &RangeTransform::setStyle, "style"_a) @@ -50,21 +50,23 @@ void bindPyRangeTransform(py::module & m) .def("getFileOutputBitDepth", &RangeTransform::getFileOutputBitDepth) .def("setFileOutputBitDepth", &RangeTransform::setFileOutputBitDepth, "bitDepth"_a) .def("getMinInValue", &RangeTransform::getMinInValue) - .def("setMinInValue", &RangeTransform::setMinInValue, "val"_a) + .def("setMinInValue", &RangeTransform::setMinInValue, "value"_a) .def("hasMinInValue", &RangeTransform::hasMinInValue) .def("unsetMinInValue", &RangeTransform::unsetMinInValue) .def("getMaxInValue", &RangeTransform::getMaxInValue) - .def("setMaxInValue", &RangeTransform::setMaxInValue, "val"_a) + .def("setMaxInValue", &RangeTransform::setMaxInValue, "value"_a) .def("hasMaxInValue", &RangeTransform::hasMaxInValue) .def("unsetMaxOutValue", &RangeTransform::unsetMaxOutValue) .def("getMinOutValue", &RangeTransform::getMinOutValue) - .def("setMinOutValue", &RangeTransform::setMinOutValue, "val"_a) + .def("setMinOutValue", &RangeTransform::setMinOutValue, "value"_a) .def("hasMinOutValue", &RangeTransform::hasMinOutValue) .def("unsetMinOutValue", &RangeTransform::unsetMinOutValue) .def("getMaxOutValue", &RangeTransform::getMaxOutValue) - .def("setMaxOutValue", &RangeTransform::setMaxOutValue, "val"_a) + .def("setMaxOutValue", &RangeTransform::setMaxOutValue, "value"_a) .def("hasMaxOutValue", &RangeTransform::hasMaxOutValue) .def("unsetMaxOutValue", &RangeTransform::unsetMaxOutValue); + + defStr(cls); } } // namespace OCIO_NAMESPACE diff --git a/src/bindings/python/PyTransform.cpp b/src/bindings/python/PyTransform.cpp index 09b2244295..1cef1f2e7d 100644 --- a/src/bindings/python/PyTransform.cpp +++ b/src/bindings/python/PyTransform.cpp @@ -11,7 +11,7 @@ void bindPyTransform(py::module & m) auto cls = py::class_(m, "Transform") .def("validate", &Transform::validate) .def("getDirection", &Transform::getDirection) - .def("setDirection", &Transform::setDirection, "dir"_a); + .def("setDirection", &Transform::setDirection, "direction"_a); defStr(cls); diff --git a/src/bindings/python/PyTypes.cpp b/src/bindings/python/PyTypes.cpp index 7152d56df5..d88f2e7412 100644 --- a/src/bindings/python/PyTypes.cpp +++ b/src/bindings/python/PyTypes.cpp @@ -185,52 +185,52 @@ void bindPyTypes(py::module & m) .export_values(); // Conversion - m.def("BoolToString", &BoolToString, "val"_a); - m.def("BoolFromString", &BoolFromString, "s"_a); + m.def("BoolToString", &BoolToString, "value"_a); + m.def("BoolFromString", &BoolFromString, "str"_a); m.def("LoggingLevelToString", &LoggingLevelToString, "level"_a); - m.def("LoggingLevelFromString", &LoggingLevelFromString, "s"_a); + m.def("LoggingLevelFromString", &LoggingLevelFromString, "str"_a); - m.def("TransformDirectionToString", &TransformDirectionToString, "dir"_a); - m.def("TransformDirectionFromString", &TransformDirectionFromString, "s"_a); + m.def("TransformDirectionToString", &TransformDirectionToString, "direction"_a); + m.def("TransformDirectionFromString", &TransformDirectionFromString, "str"_a); - m.def("GetInverseTransformDirection", &GetInverseTransformDirection, "dir"_a); - m.def("CombineTransformDirections", &CombineTransformDirections, "d1"_a, "d2"_a); + m.def("GetInverseTransformDirection", &GetInverseTransformDirection, "direction"_a); + m.def("CombineTransformDirections", &CombineTransformDirections, "direction1"_a, "direction2"_a); - m.def("ColorSpaceDirectionToString", &ColorSpaceDirectionToString, "dir"_a); - m.def("ColorSpaceDirectionFromString", &ColorSpaceDirectionFromString, "s"_a); + m.def("ColorSpaceDirectionToString", &ColorSpaceDirectionToString, "direction"_a); + m.def("ColorSpaceDirectionFromString", &ColorSpaceDirectionFromString, "str"_a); m.def("BitDepthToString", &BitDepthToString, "bitDepth"_a); - m.def("BitDepthFromString", &BitDepthFromString, "s"_a); + m.def("BitDepthFromString", &BitDepthFromString, "str"_a); m.def("BitDepthIsFloat", &BitDepthIsFloat, "bitDepth"_a); m.def("BitDepthToInt", &BitDepthToInt, "bitDepth"_a); m.def("AllocationToString", &AllocationToString, "allocation"_a); - m.def("AllocationFromString", &AllocationFromString, "s"_a); + m.def("AllocationFromString", &AllocationFromString, "str"_a); - m.def("InterpolationToString", &InterpolationToString, "interp"_a); - m.def("InterpolationFromString", &InterpolationFromString, "s"_a); + m.def("InterpolationToString", &InterpolationToString, "interpolation"_a); + m.def("InterpolationFromString", &InterpolationFromString, "str"_a); m.def("GpuLanguageToString", &GpuLanguageToString, "language"_a); - m.def("GpuLanguageFromString", &GpuLanguageFromString, "s"_a); + m.def("GpuLanguageFromString", &GpuLanguageFromString, "str"_a); m.def("EnvironmentModeToString", &EnvironmentModeToString, "mode"_a); - m.def("EnvironmentModeFromString", &EnvironmentModeFromString, "s"_a); + m.def("EnvironmentModeFromString", &EnvironmentModeFromString, "str"_a); m.def("CDLStyleToString", &CDLStyleToString, "style"_a); - m.def("CDLStyleFromString", &CDLStyleFromString, "s"_a); + m.def("CDLStyleFromString", &CDLStyleFromString, "str"_a); m.def("RangeStyleToString", &RangeStyleToString, "style"_a); - m.def("RangeStyleFromString", &RangeStyleFromString, "s"_a); + m.def("RangeStyleFromString", &RangeStyleFromString, "str"_a); m.def("FixedFunctionStyleToString", &FixedFunctionStyleToString, "style"_a); - m.def("FixedFunctionStyleFromString", &FixedFunctionStyleFromString, "s"_a); + m.def("FixedFunctionStyleFromString", &FixedFunctionStyleFromString, "str"_a); m.def("ExposureContrastStyleToString", &ExposureContrastStyleToString, "style"_a); - m.def("ExposureContrastStyleFromString", &ExposureContrastStyleFromString, "s"_a); + m.def("ExposureContrastStyleFromString", &ExposureContrastStyleFromString, "str"_a); m.def("NegativeStyleToString", &NegativeStyleToString, "style"_a); - m.def("NegativeStyleFromString", &NegativeStyleFromString, "s"_a); + m.def("NegativeStyleFromString", &NegativeStyleFromString, "str"_a); // Envar m.attr("OCIO_CONFIG_ENVVAR") = OCIO_CONFIG_ENVVAR; diff --git a/src/bindings/python/PyUtils.h b/src/bindings/python/PyUtils.h index dfb933c38a..46cb7c64ad 100644 --- a/src/bindings/python/PyUtils.h +++ b/src/bindings/python/PyUtils.h @@ -14,10 +14,10 @@ namespace OCIO_NAMESPACE { // Define __str__ implementation compatible with *most* OCIO classes -template -void defStr(py::class_> & cls) +template +void defStr(py::class_, EXTRA ...> & cls) { - cls.def("__str__", [](OCIO_SHARED_PTR & self) + cls.def("__str__", [](OCIO_SHARED_PTR self) { std::ostringstream os; os << (*self); diff --git a/src/bindings/python/PyViewTransform.cpp b/src/bindings/python/PyViewTransform.cpp index 47c7f42f8a..c7122f3858 100644 --- a/src/bindings/python/PyViewTransform.cpp +++ b/src/bindings/python/PyViewTransform.cpp @@ -92,8 +92,8 @@ void bindPyViewTransform(py::module & m) }) .def("clearCategories", &ViewTransform::clearCategories) .def("getReferenceSpaceType", &ViewTransform::getReferenceSpaceType) - .def("getTransform", &ViewTransform::getTransform, "dir"_a) - .def("setTransform", &ViewTransform::setTransform, "transform"_a, "dir"_a); + .def("getTransform", &ViewTransform::getTransform, "direction"_a) + .def("setTransform", &ViewTransform::setTransform, "transform"_a, "direction"_a); defStr(cls); diff --git a/tests/python/BuiltinTransformTest.py b/tests/python/BuiltinTransformTest.py index 5cfa7b7c1a..7142a03dda 100644 --- a/tests/python/BuiltinTransformTest.py +++ b/tests/python/BuiltinTransformTest.py @@ -69,7 +69,7 @@ def test_direction(self): def test_constructor_keyword(self): # Keyword args in order builtin_tr1 = OCIO.BuiltinTransform(style=self.EXAMPLE_STYLE, - dir=OCIO.TRANSFORM_DIR_FORWARD) + direction=OCIO.TRANSFORM_DIR_FORWARD) self.assertEqual(builtin_tr1.getStyle(), self.EXAMPLE_STYLE) self.assertEqual(builtin_tr1.getDescription(), self.EXAMPLE_DESC) @@ -77,7 +77,7 @@ def test_constructor_keyword(self): OCIO.TRANSFORM_DIR_FORWARD) # Keyword args out of order - builtin_tr2 = OCIO.BuiltinTransform(dir=OCIO.TRANSFORM_DIR_FORWARD, + builtin_tr2 = OCIO.BuiltinTransform(direction=OCIO.TRANSFORM_DIR_FORWARD, style=self.EXAMPLE_STYLE) self.assertEqual(builtin_tr2.getStyle(), self.EXAMPLE_STYLE) diff --git a/tests/python/CDLTransformTest.py b/tests/python/CDLTransformTest.py index 8729038912..d1709a6dbe 100644 --- a/tests/python/CDLTransformTest.py +++ b/tests/python/CDLTransformTest.py @@ -331,7 +331,7 @@ def test_constructor_with_keyword(self): power=self.TEST_CDL_POWER, sat=self.TEST_CDL_SAT, id=self.TEST_CDL_ID, - desc=self.TEST_CDL_DESC) + description=self.TEST_CDL_DESC) self.assertEqual(self.TEST_CDL_ID, cdl_tr.getID()) self.assertEqual(self.TEST_CDL_DESC, cdl_tr.getDescription()) @@ -343,7 +343,7 @@ def test_constructor_with_keyword(self): # With keyword not in their proper order. cdl_tr2 = OCIO.CDLTransform(id=self.TEST_CDL_ID, - desc=self.TEST_CDL_DESC, + description=self.TEST_CDL_DESC, slope=self.TEST_CDL_SLOPE, offset=self.TEST_CDL_OFFSET, power=self.TEST_CDL_POWER, diff --git a/tests/python/ColorSpaceTest.py b/tests/python/ColorSpaceTest.py index 11fe23c626..209311f2df 100644 --- a/tests/python/ColorSpaceTest.py +++ b/tests/python/ColorSpaceTest.py @@ -178,8 +178,7 @@ def test_constructor_with_keyword(self): description='This is a test colourspace!', equalityGroup='My_Equality', encoding='scene-linear', - bitDepth=OCIO.BIT_DEPTH_F32, - ) + bitDepth=OCIO.BIT_DEPTH_F32) self.assertEqual(cs2.getName(), 'test') self.assertEqual(cs2.getFamily(), 'ocio family') diff --git a/tests/python/DisplayViewTransformTest.py b/tests/python/DisplayViewTransformTest.py index e5af7244c4..f29ca0bf6e 100644 --- a/tests/python/DisplayViewTransformTest.py +++ b/tests/python/DisplayViewTransformTest.py @@ -178,7 +178,7 @@ def test_constructor_with_keyword(self): view=self.TEST_VIEW[0], looksBypass=True, dataBypass=False, - dir=OCIO.TRANSFORM_DIR_INVERSE) + direction=OCIO.TRANSFORM_DIR_INVERSE) self.assertEqual(self.TEST_SRC[0], dv_tr.getSrc()) self.assertEqual(self.TEST_DISPLAY[0], dv_tr.getDisplay()) @@ -188,7 +188,7 @@ def test_constructor_with_keyword(self): self.assertEqual(OCIO.TRANSFORM_DIR_INVERSE, dv_tr.getDirection()) # With keyword not in their proper order. - dv_tr2 = OCIO.DisplayViewTransform(dir=OCIO.TRANSFORM_DIR_FORWARD, + dv_tr2 = OCIO.DisplayViewTransform(direction=OCIO.TRANSFORM_DIR_FORWARD, view=self.TEST_VIEW[1], src=self.TEST_SRC[1], looksBypass=True, From edbce351f1497d3d4b94fc5408de9645dd1fbf83 Mon Sep 17 00:00:00 2001 From: Michael Dolan Date: Thu, 2 Jul 2020 01:38:40 -0400 Subject: [PATCH 28/33] Add documentation working group notes from 06-12-2020, 06-19-2020 (#1037) * Add documentation working group notes from 06-12-2020 Signed-off-by: Michael Dolan * Correct section title Signed-off-by: Michael Dolan * Fix typo Signed-off-by: Michael Dolan * Fix typo, add notes from 06-18-2020 meeting Signed-off-by: Michael Dolan --- .../documentation/2020-06-12.md | 243 ++++++++++++++++++ .../documentation/2020-06-19.md | 152 +++++++++++ 2 files changed, 395 insertions(+) create mode 100644 docs/tsc/working_groups/documentation/2020-06-12.md create mode 100644 docs/tsc/working_groups/documentation/2020-06-19.md diff --git a/docs/tsc/working_groups/documentation/2020-06-12.md b/docs/tsc/working_groups/documentation/2020-06-12.md new file mode 100644 index 0000000000..84d1a67242 --- /dev/null +++ b/docs/tsc/working_groups/documentation/2020-06-12.md @@ -0,0 +1,243 @@ + + + +June 12, 2020 + +Host: Carol Payne + +Rotating Secretary: Michael Dolan + +Attendees: + * [X] Sean Cooper (_TSC ACES TAC Rep_) - DNEG + * [X] Michael Dolan (_TSC Chair_) - Epic Games + * [X] Carol Payne (_TSC_) - Netflix + * [X] Doug Walker (_TSC Chief Architect_) - Autodesk + * [x] Alexa Zalipyatskikh - Autodesk + * [x] Troy Sobotka + * [x] Matthias Scharfenberg - ILM + +# **OCIO Documentation Working Group Meeting Notes** + +* Overview (Carol): + - We've been discussing in TSC that OCIO v2 needs to launch with + documentation, to help people get familiar with what's changed, and how + to implement. It's one thing to have a feature complete v2, but another + to know how to use it. + - The plan is to completely revamp documentation. Sean is leading the API + doc revamp. + - Want to discuss OCIO website user stories. What does the user journey + look like? How do we help people of different expertise and backgrounds + navigate OCIO docs. Typically docs are written with a specific person in + mind, but we need to consider many. + - The how and what can be discussed later. Need to discuss overall + organization structure first. + +* Documentation structure: + - [Google Doc](https://docs.google.com/document/d/17IQR2tRYxqGXkExOLvP9S_dMkOkOID-NIIAGXGfyxNk/edit) + - Summary of three proposed structures: + - Structure 1: + - Organize docs around artists, studio config maintainers, TDs, DCC + maintainers, and OCIO contributors. + - Put relevant info in terms of who is looking at it. + - Challenge would be how to deal with duplicate info, since some + topics will affect multiple roles. + - Structure 2: + - Similar to what's there now, with some clean up and reorganization. + - Doesn't deal well with different types of users finding info. + Doesn't contextualize user stories. + - Where do we put workflow examples and tutorials to be accessible? + - Structure 3: + - Combo of 1 and 2 (see doc) + - Breaking out site into sections like config, tools, API, and within + each make point to break out subsections for intended audiences, + following a general overview. Notes would be added for specific + roles to read about relevant topics. + - Michael: Structure 3 seems like a good balance. + - Alexa: Have written lots of docs. Customizing docs for specific roles is + hard to maintain; a lot of work to keep up with different groups. + Recommend checking out RabbitMQ docs. Takes you through a progression of + easy to hard, slowly introducing topics. Combo structure good for gradual + introduction to technical info. Gives relevant info at the right time. + - This quadrant doc structure is really helpful: + [The documentation system](https://documentation.divio.com/) + - 4 quadrants of documentation: tutorials (from 0 to examples, holding + hand), how to guides (more specific, how do I do A, B, etc. Walks + through how to get something done), explanation, reference (API + docs). + - Carol: Should we show users how to use OCIO in DCCs (like Nuke) on the + website, or just show how to set env vars so that Nuke can pick OCIO up? + - Alexa: Better to link to DCC vendors own guides. + - Michael: There is some of that on the site now in the Compatible Software + page, which was updated recently: + [Compatible Software](https://github.com/AcademySoftwareFoundation/OpenColorIO/blob/master/docs/CompatibleSoftware.rst) + - Carol: Tricky to know which vendors to include tutorials for. + - Alexa: Could be better to explain the config, and what each part means. + It's difficult to find everything right now. + - Carol: If there's no objections, suggest moving forward with structure 3. + It allows us to first write docs like in example 2 - traditional tree, + broken up nicely - and then take those components and add coverage for + user cases and make specific call outs for specific groups; artists, TDs, + etc. + - Alexa: Good for developers to update docs as new work is contributed, but + how do users update docs? + - Doug: We have talked about that and discussed different approaches. Would + be good to avoid contributors having to deal with Sphinx if possible. + - Alexa: Sphinx is great, but it does make it hard to update docs for those + not familiar. + - Carol: I included some references in the Google doc on what other + projects have done to improve this. Many have big notes at the top or + bottom of pages encouraging contribution. Usually includes a link to take + users to open GitHub issue. Suggest easier structure if possible, but + it's harder to engineer. My first thought was to use a wiki, and keep it + separate from API generated docs, editable in the website. The more I + investigated though, the wiki didn't seem to give us much more, compared to + a static site with markdown. If the overhead is links to report issues + around docs, and encourage users to contribute fixes, that barrier is not + too high. Hopefully most people will follow through with that. Someone + with GH knowledge can do the work. + - Doug: So someone would create an issue, but someone else would do the + update. It's not a huge barrier to entry, since they can submit an edit + without a PR. + - Carol: If someone is comfortable they can submit a PR - need to have CLA + signed, etc. I no longer think the wiki is worth it. + - Doug: Can you discuss structure 3 a bit? How would it be broken down? + - Carol: The doc is not complete, but general thought is to have cut and + dry components, but with added categories and references with different + use cases for different roles. Easy to hard progression, but not labeled + as such. Start with "what is it?", an overview, and go from there to + underlying details of sub-components with examples and how they fit + together. Then user guide for steps to implement, and then a section for + DCC implementors (what do they need to know to use and test; how to know + it's working, etc.). + - Matthias: Where are docs about individual transforms? API or config + structure? What transforms exist and how do they go together to make a + color space. + - Carol: Could be part of config author section, following structure and + overview. Transforms could follow how to implement color spaces. TDs + wouldn't need to know that low level. + - Doug: Alexa discussed taxonomy of four types of documentation. Is this a + way of thinking about docs? Are we talking about the reference section. + - Carol: Combo of bottom two quadrants: explanation and reference. + - Doug: Is first section example and second section reference? + - Carol: Could go different ways. Don't want to tie us into writing + examples for everything. Won't be needed for every component. Should be + woven into reference as we see fit. Reference docs will be first step for + writing docs. Then we look at for different roles; what needs to be + explained more? + - Alexa: Need to have recommendations in there and gotchas. + - Doug: Yes, need to steer people in the right direction. Trying to do that + with code, apphelpers and code examples, but equally important is best + practices for config authoring. + - Troy: Stepping through building config is big deal. Is there a current + API call to build a bare minimum config skeleton? + - Doug: There is a call to give you a minimal config, but not much. + - Sean: what would that include? + - Troy: It would have all the things needed for a config to pass a sanity + check. May be possible to combine "how to guide" with reference. Could + link them, to step by step build up. + - Carol: Would be great to be able to generate reference config. + - Michael: Could possibly reference the ACES config. + - Alexa: we get a lot of questions for people trying to setup OCIO configs. + Good to cover that. + - Carol: There's a lot of space to build on docs. Add tutorial for + authoring config from ground up. It could sit in docs, but under + tutorials and reference back to sections of documentation. If base + structure covers basis, it becomes easier to write tutorials. + - Sean: The builtin/bundled apps are code examples. The docs can point to + configs repo, other docs, API, code examples, etc. Sphinx and reST will + help with that a lot. Feature called intersphinx that can pull Sphinx + docs from other projects; could possibly be utilized. + +* API docs discussion (Sean): + - Using pybind11/mitsuba2 method (makedoc) that pulls docstrings from + header as long as the header is formatted in doxygen style. + - Spits out header file with string literals which a Python script then + pulls data from. + - Only need to write docs in C++ headers. CMake will pull those. Docstrings + get compiled into bindings and then docstrings match between C++ and + Python. Using autodoc and Breathe, can build docs. + - Have ganged Python and C++ tabs through API docs to see both on same + page, with shared descriptions. + - Handles listing parameters. + - Doug: How do you handle spots where C++ and python differ? + - Sean: May need to write docstring in Python bindings to explain the + differences. + - Michael: Having to document differences in Python binding docstrings + could help call out where the APIs differ in the code, as a benefit. + - Sean: VuePress has some style issues that need to be resolved. + - Michael: Might be able to fix signature of PyIterator base class. + - Sean: Also need to get rid of redundant 'self' param. + +* API and website combined or separate? + - Sean: Sphinx/RTD could just generate reference section of docs (in four + quadrant diagram). And use a static site for everything else? + - Carol: If we separate them, can we still link between them easily? + - Sean: Code references could get messy if they are kept separate. + - Michael: Could reach out to LF creative services for help with design, + branding etc. Front end stuff. + - Carol: If we kept it together all docs would be in reST. Would generate + everything. + - Alexa: RTD has simpler markdown, but not tried for C++ - referring to + RTD service. + - Michael: Might use Sphinx in background and just hide it a bit. + - Alexa: Markdown is easier to migrate than reST. + - Sean: Could keep the two upper quadrants in markdown. RTD also has an + "edit in github" link to ease fixing errors. + - Michael: Need to find a way to sign-off commits via GH interface. + - Sean: Can do GH issue templates; not sure about commits. + - Michael: Can document commit instructions. + - Sean: We can add that to CONTRIBUTORS.md. + - Sean: Need to decide if we should do the dual system? Or use Sphinx for + everything? + - Michael: keeping them separate could be problematic since some parts + would be versioned and others not. Easy to drift. + - Carol: Bottom line is we want good up to date maintainable documentation. + More important than the prettiness of the site. Code snippets getting + updated without tracking would be a big benefit. Could have a nice static + splash page still, which can be manually updated separate from + documentation. + - Alexa: Django docs do this well. Good example. Landing page explaining + how docs are organized, with "getting started" links. + - Sean: Could have www/ subdirectory in repo for the static site portion, + hosted in GH pages. + - Michael: GH pages is nice for that. Just commit to that branch and its + live. + - Sean: If we have a page to layout general descriptions, we'll see what + areas are better for a website and can evolve naturally. + - Carol: Keeping in mind the desire to keep everything tied together for + ease of updating. As long as we keep that in mind. + - Sean: Django layout is good since the site could point to multiple GH + repos and projects, configs, etc. + - Carol: Next step is to do big picture and break up work. + - Michael: GH Projects kanban board. Create issue per section and add to + that project. + - Carol: Can do comprehensive overview of what needs to be done, and create + issues. Should we separate API from the rest of it? Is that done? + - Sean: Plenty of methods for documentation. Should we have another repo? + - Michael: Maybe orphaned branch instead of another repo? + - Sean: Thinking of a new directory structure, etc. + - Carol: Like the idea of having something separate that doesn't tie into + OCIO build system. + - Troy: Could do work in GH wiki to start. Accessible from git and can do + push. + - All: Good idea. + - Alexa: Want to have place to do brain dump up front and organize later. + - Troy: Wiki image upload can utilize images from GH issues as a shortcut. + - **TODO**: Sean and Alexa will work on Google doc to flesh out content + more. + - Sean: Do we care about the theme? Or just use RTD? + - Carol: Like how sphinx-press looks, but could get frontend assistance + from LF. + - **TODO**: Michael to ask Emily about LF resources for frontend style + work. + - Alexa: Also need to keep color blindness in mind. + - Sean: Could possibly use VuePress for site too, to keep things together. + - **TODO**: Sean to continue working on API docs. + - Doug: We have been conforming header docs to existing style. + - Sean: Will do one big push with new header doc syntax. + - Doug: Existing solution is difficult, to get html and pdf both looking + good. + - Michael: RTD can generate PDF, so don't need the 'pdf' target anymore. + - Sean: Need to think about header docs more generically, since it goes to + C++ and Python. + - Doug: If clarity in docs is needed, we can help. diff --git a/docs/tsc/working_groups/documentation/2020-06-19.md b/docs/tsc/working_groups/documentation/2020-06-19.md new file mode 100644 index 0000000000..fe29c2cb45 --- /dev/null +++ b/docs/tsc/working_groups/documentation/2020-06-19.md @@ -0,0 +1,152 @@ + + + +June 19, 2020 + +Host: Carol Payne + +Rotating Secretary: Michael Dolan + +Attendees: + * [X] Sean Cooper (_TSC ACES TAC Rep_) - DNEG + * [X] Michael Dolan (_TSC Chair_) - Epic Games + * [X] Carol Payne (_TSC_) - Netflix + * [X] Doug Walker (_TSC Chief Architect_) - Autodesk + * [X] Alexa Zalipyatskikh - Autodesk + * [X] Troy Sobotka + +# **OCIO Documentation Working Group Meeting Notes** + +* Config documentation: + - Carol: A lot of the ACES config content is going to change while being + developed. Should docs utilize that work? Does it makes sense to tackle + other things first? + - Michael: Config will be generated so may not be able to directly + reference in documentation. Could document the core config functionality + which is stable. + - Doug: May want to generate test configs purely for example purposes. The + SPI configs were nice and simple, but don't use v2 features, and even + don't use some v1 features, so could create a config for purposed of + demonstration. + - Sean: Agree. Nice to have a config where you don't start pulling in + general color science issues. If you start bringing in rendering + transforms, etc, it could be confusing to people. Examples that could + start at baby steps, bare minimum, and build into something larger. + Specific use cases: need per shot CDL, etc. + - Michael: Unit tests contain a lot of good resources for helping document + new config features. + - Sean: Also good to have doc specific configs to use line numbers while + describing configs. A stable config that won't change. + - Michael: Config docs are likely going to be the basis for all + documentation, since it ties everything together. + - Carol: Would like to start with config docs. + - Sean: As you start working with it, it will help reveal holes in docs. + - Carol: Command-line tools are another good thing to document. + - Michael: Command-line tools have decent usage docs builtin for reference + too. + - Doug: Also good to focus on overall structure of things that need to be + written so contributors can pick topics to work on and distribute the + work. We need to break it down to help them find something to work on. + - Sean: Fairly fine grained outline of what we expect is a good place to + start. Could be done in Wiki. + - Carol: And can then break that down into trackable GH issues. + +* Overall approach and structure: + - Doug: Still struggling with previously shown four quadrant diagram and + where things fit into that. The existing user guide, where config is + currently explained, and then the SPI use case explained (describing + color management workflow). Where do those two things fit? Trying to get + the big picture of how we could assign different parts of the quadrants. + Discussed approach mixes these together. + - Carol: At the base it would be a reference structure, and then within + that would be examples, and lead to user guides, etc. Or do we split + everything up, different section per topic and reader. Can approach + authoring in more structured ways, but present it together. + - Doug: Seems like an approach to a text book, to teach someone and mix + different items into one narrative. From point of view of collaboration, + that makes it difficult to maintain an editorial voice throughout. Easier + to contribute by targeting specific item, in a more isolated fashion. + How do we merge tutorials with reference? + - Carol: Will need to be stepping stones. Not sure we should write user + guide until reference docs done. Think we should write reference docs + first, and then base user guides on that reference. Will help break up + the work, but will need someone (Carol and Sean) to help with consistent + voice. + - Sean: Another added complexity is that there's almost a four quadrant + structure per user. An artist and a developer are going to be looking for + very different things. The mixed structure is a bit like a textbook, with + a general narrative, but with side-margin details and reference. + - Carol: From an artist perspective, they will likely mostly be looking for + how OCIO is implemented in DCCs. Think the biggest part of the narrative + will be for config authors. If we approach it from that perspective, we + can expand on it. By making config authoring more approachable we can + reach out from there. + - Doug: Starting reference first sounds good. It's concrete and can be + outlined. Can precisely describe what we're looking for so people can + jump in and help. Start with reference quadrant, which is needed to start + looking at v2, and work out from there. + - Alexa: There's already decent config docs, so could start from that. Hard + part is not just OCIO, but general lack of knowledge of color. + - Sean: That's where small toy configs will help. Introduce features + without going too deep into color science concepts. Original intent of + docs and website was to be educational. + - Alexa: Cinematic color would be good to reference. Have sections for + learning about general color science topics. fxphd is another resource. + - Sean: New cinematic color paper still being worked on. Quite large. + - Alexa: Would be good to also get some good reference images for examples. + + * Next steps: + - Carol: Next steps, look at overall structure, and look at mini configs + for building up config docs. + - Doug: Would help to understand the different pieces and deliverables from + this. A specification for the documentation, as if we're developing a + product. Description of deliverables, which people can then work off of - + the written part of it. The other part is the infrastructure part - + tools, Sphinx, etc. + - **TODO**: Sean to get infrastructure working. + - Doug: Where will static site be hosted? Same as today? + - Sean: Still to be determined. GH pages and RTD are options. + - Doug: Have also discussed seeing what other ASWF projects have done for + homepage. + - Carol: Depends how tied together the docs are to the homepage. Is the + homepage generated with docs? Or separate? Where is each part hosted. + These things are flexible as long as doc generation works. Last week it + was determined to keep API and user guides tied together and generated + the same way. Just not sure about the fancy homepage. + - Sean: Thinking all the docs will be generated by RTD, versioned, and the + website should just be non-version-specific stuff. Static, for + presentation. Could potentially host blog posts for interested + contributors, usage examples, etc. + - Alexa: Do the forums fill that role? + - Sean: Yes, but could be nicer for presentation vs. digging into mail list + threads. Since OCIO is super configurable, there are a lot of corner + cases, and users can contribute those case studies rather than us trying + to think of them all up front. Production-driven solutions that could be + shared. The website could host content like that. The site should exist + in GH, but not be married to generated docs. Could have ``www/`` subdirectory + in git for site. + - Alexa: Can also have more static forum posts for that. + - Michael: Could link ASWF lists site to the website, embedded to a link to + open a new tab. + - Sean: Embedding it could be nice, via an iframe maybe, to get the lists + functionality for free. Should we start with bullet points in Google docs + before moving to GH issues? + - Carol: Yes, wait to put it into an actionable state until we have an + outline. Google docs could use some cleanup to keep it organized. + - **TODO**: Carol will reorganize Google docs for planning documentation. + Will notify group when it's ready for further additions. + - Sean: Would be great to have a organized structure by next week if + possible. + - Doug: We (Autodesk) can fill in reference details. Looking for help with + how to make it look; the overall flow of where things will live. If you + were writing the v1 user guide, that top level tree, with brief + explanations, of what that should contain is enough for us to fill in. + What are the sections? How does a section compare to the v1 docs? What is + the structure of each section. Want to make sure everyone has expressed + their opinion on solving the v1 problems. Don't worry about the details + of individual features. + - Sean: Would be good to use the OCIO mission statement as a guiding + mentality for how to approach the docs. + - Carol: Good opportunity for democratization of concepts that have been + out of peoples reach. Nobody's creative ability should be limited by not + understanding the technical details. From a92006c247ab4c41a4ed1149fcaa05a494d3599d Mon Sep 17 00:00:00 2001 From: Michael Dolan Date: Thu, 2 Jul 2020 02:50:30 -0400 Subject: [PATCH 29/33] Add Config working group notes 06-16-2020 (#1040) Signed-off-by: Michael Dolan --- docs/tsc/working_groups/configs/2020-06-16.md | 232 ++++++++++++++++++ 1 file changed, 232 insertions(+) create mode 100644 docs/tsc/working_groups/configs/2020-06-16.md diff --git a/docs/tsc/working_groups/configs/2020-06-16.md b/docs/tsc/working_groups/configs/2020-06-16.md new file mode 100644 index 0000000000..6b54c7cd11 --- /dev/null +++ b/docs/tsc/working_groups/configs/2020-06-16.md @@ -0,0 +1,232 @@ + + + +June 16, 2020 + +Host: Michael Dolan + +Rotating Secretary: Michael Dolan + +Attendees: + * [X] Mark Boorer (_TSC_) - Industrial Light & Magic + * [X] Sean Cooper (_TSC ACES TAC Rep_) - DNEG + * [X] Michael Dolan (_TSC Chair_) - Epic Games + * [X] Carol Payne (_TSC_) - Netflix + * [X] Doug Walker (_TSC Chief Architect_) - Autodesk + * [X] Kevin Wheatley (_TSC_) - Framestore + * [X] Matthias Scharfenberg - Industrial Light & Magic + * [X] Dennis Adams - Sony + * [X] Thomas Mansencal - Weta Digital + * [X] Michael Parsons - MPC + * [X] Chris Clark - Netflix + * [X] Rémi Achard - DNEG + * [X] Troy Sobotka + +# **OCIO Configs Working Group Meeting Notes** + +* Working group direction: + - Michael: Goal of group could be to design and develop the next gen ACES + config, but also to maintain it long-term. Do we want to make it a formal + working group with dedicated leadership? + - Thomas: Good to formalize the group. Current ACES config work is done + when there is time. There's not a good commitment which can lead to + delays. Group would be good for prioritizing work. + - Sean: Should it be distinct from OCIO TSC, or a subgroup? + - Mark: Division of power is better. There's some overlap, but the OCIO TSC + is more dev centric. This is more user centric. + - Michael: There could be a formal chair, or co-chairs, but without a + formalized group. + - Sean: The TSC has the benefit of governance structure. + - ACES will likely be involved to support the work, but the goal from our + previous meeting was for OCIO to own the ACES config. + - Carol: We just need to make sure the OCIO TSC is represented in the + group. + - Michael: Studios will become highly dependent on this config, so it + will be important work. + - Mark: Software vendors (i.e. Foundry) will also be dependent on it. + - Thomas: Vendors are already asking about it. + - Michael: Anyone interested in leading the group? + - Sean and Matthias will co-chair. + +* Config structure: + - ACES reference config, studio in a box, or both: + - Michael: As discussed, could potentially have one code base which can + create an ACES reference config (minimal), and the big "studio in a + box" config. + - Mark: If nobody is using the reference config, there's no point in + duplicating efforts. + - Thomas: The smaller config is a subset of the bigger one. May not + need everything depending on what you are using. A base. + - Kevin: We will often take a stock config and strip out stuff not + needed. Depends on distribution. How we generate it could lead to + module configuration. + - Doug: Does seem like build settings to select options would be good. + Pure ACES model is good for OCIO as an ACES product partner, to + submit the implementation to the ACES logo program. + - Carol: Something to be said for ACES transforms being builtin to OCIO + v2. Not needing external files is nice. + - Mark: If you have multiple things to release, people have to make a + choice of what they use. People who want the studio in the box will + be upset depending on what DCCs choose as default. Lose benefit of + consistency. If we up front have minimal ACES only, that has some + value. We should be clear about what we’re giving out. + - Matthias: Will the config be OCIO v2 only? Is it backwards + compatible. + - Sean: Needs to be backwards compatible. We’re probably the wrong + people to answer this question. Should ask community what they want, + rather than deciding on something. + - Thomas: Breaking backwards compatibility makes migration hard. + - Carol: We might get polarizing opinions. + - Mark: Almost feel whole idea of giant config is atypical of how OCIO + works. People are supposed to have their own configs. May as well + build everything into the library at that point. + - Carol: Some just use whatever config ships with an application. + - Michael: Think it is useful to support ACES-only reference for + checking against ACES, etc. + - Thomas: ACES would like this config to be “the” config, to make + exchange between studios easier. Something ready to use out of the + box seems to be desired. + - Doug: Some projects, Like MaterialX, want to make this config their + default. + - Thomas: That could be done for USD as well. +- Utilizing OCIO v2 BuiltinTransform, and CLF where needed: + - Michael: The implementation could focus on utilizing BuiltinTransform, + and CLF where external files are needed, since CLF is the ACES format. + - Doug: If Academy publishes transforms in CLF as well as CTL, would be + interesting. + - Mark: Doesn't hurt to use it. + - Doug: CLF also supports metadata. + - Thomas: We currently ship ICC profiles, for things like Adobe tools. Need + those for wider support. We could provide scripts to help people generate + ICC profiles. Would result in simpler package. + - Mark: ICC profiles generated with ociobakelut often need to have + additional stuff injected into them from an external script. Cant just + use ociobakelut directly necessarily. + - Kevin: Repo should mostly be Python code, and generated artifacts. + +* Repository: + - Python code base + - Store generated config in repo? Or only as build artifact? + - Mark: Nothing in repo but code. + - Michael: We discussed previously if we should include the generated + config in the repo for reference. + - Thomas: Need everything to go with config. Would be missing LUTs, + etc. We need to get past that old issue. + - Matthias: Might be some vendor LUTs that are needed, where it is just + a curve. Would potentially need to be in version control then. + - Mark: if the only source is only a LUT. + - Michael: Thoughts on pulling dependent data from upstream? + - Mark: Prefer to store it in repo if it's ASCII. + - Kevin: Need to be careful relying on vendor storage. May not always + be available. + - Config repo will only contain config generation code, and text data + resources where absolutely necessary (i.e. LUT data where no + BuiltinTransform is available) + - Compound versioning (OCIO, ACES, semver): + - Michael: People need to know what they are getting. Sean proposed a + compound versioning structure previously, to include OCIO version, + ACES version, and a config release version. + - Carol: Yes, users need to know what is being used. + - Mark: Version structure like: + `__` + - Kevin: Recommend incremental build #. + - Michael: Could also use metadata to associate with ACES version. + - Mark: Can reset build number counter at new ACES version or OCIO + version, etc. + - Doug: Could be comment in config file that shows what you have. + Printed out nicely with different components. + - Mark: There could also just be a text file with the config. + - **TODO**: Determine how and where to differentiate the config release + versions. + +* CI/CD: + - Build configs/LUTs for download + - Use CI to build complete config packages for release and easy + download. + - Mark: In releases tab should be multiple entries at a time. Can + generate: ACES reference config, ACES full config etc. Any variations + are present for download independently. + - Validate config results against ground truth (ACES images, CTL) + - Michael: Proposing (and volunteering) to setup CI system, via GH + Actions, to validate config transforms against ground truth CLF + and/or ACES images. + - Thomas: There is facilities like that now, in the current ACES + config. Optional utility. Generator is slow. + - Michael: GH Actions supports 20 concurrent jobs, so can be sped up a + bit there. + +* Config contents: + - Color space, alias naming + - Michael: Do we keep names consistent with existing config? A question + was raised in ocio-dev regarding underscores in alias names. Without + underscores, many color space names become problematic. + - Thomas: Make configurable delimiter for future version. + - Stick with existing names? + - Thomas: Can change names, but need easy way to migrate. People are + building pipelines around this to do conversion. If we break + everything, people will be sad. + - Kevin: Is there anything wrong with existing names? Or just opinions? + - Thomas: The later. + - Kevin: For OCIO v2 we had discussed being able to deprecate color + space names but maintain backwards compatibility. + - Doug: The new inactive color space feature supports this, yes. + Deprecated spaces would work in color space transforms, but not + discoverable in menus. + - Kevin: Need survey monkey to get feedback on general opinions of + naming, etc. + - Displays, views, reference spaces, looks. + - Michael: Should displays and views be restructured to use OCIO v2 + features like display reference space and view transform. Might be + good to organize views by actual display instead of grouping under + one ACES display. + - Doug: Current config was setup to avoid display use. Needs to be + revisited. To what extent do we want to use v2 features. They are + optional, but would help with working. + - Mark: Make it v2 as much as possible, and if someone complains, + make a backwards compatible config off the tail-end of the project. + Good opportunity to force DCCs to do the right thing. Incentive. + - Carol: v2 makes things easier to implement. Will want config that + works and takes advantage of new features. + - Doug: Good opportunity to ask vendors to improve things. Could put + together list of minimum expectations: support displays, views, + looks, etc. + - Sean: Agree on using displays properly. + - Matthias: Maintain family names (which group color spaces in some + DCCs, like Nuke)? Want to keep name similar to aid migration, but + might want to fix family names. + - Doug: v2 has option to build hierarchical menus from family. + - Sean: I think the ACES config families were a reaction to the size + of the config. + - Thomas: Worth pinging vendors, to have more people on the table + discussing that. + - Sean: Can't blame vendors in previous version. We didn't tell them + what we were looking for. + - Kevin: Think the idea of roles appearing in menus was an annoyance. + Roles should be a Pipeline detail. + - Michael: The new categories don't work with roles right? + - Doug: Categories are for reducing color spaces in menus based on use. + +* New code base: + - Doug: Where did we land on whether old code could brought over? + - Michael: I don't think it can with the current license. + - Thomas: Would be better to start fresh. + - Sean: Also thinking to start from scratch. To make it work well for CI + too. + - Doug: Agree. + - Michael: When should we target completion for this project? + - Doug: OCIO v2 stabilization period over second half of year. Vendors will + work on incorporating, and find bugs, etc. Want people to start using it + before that. + - Thomas: Are builtin transforms being shipped at that point? + - Doug: ACES transforms are there now. Over stabilization period we could + increase number of builtin transforms. Not changing API. Just adding stuff. + - Michael: Can we have something functional by end of year? + - Sean: Good to have unit test config at feature complete time. Need + something to get right impression at start. + - Mark: There will be a long period of requiring v1 configs, until every + DCC at studios is updated. Might be period where this config can't be + used. + - Carol: Some people might not use OCIO v2 until there's a config. + - Goal is to target reference config at feature complete time, and + end of year for "studio in a box". This working group will meet at the + same day and time every other week, for now. From 16fcc947a62d8fe6801bd9dc63fd647fafa61fb3 Mon Sep 17 00:00:00 2001 From: Michael Dolan Date: Tue, 7 Jul 2020 10:36:40 -0400 Subject: [PATCH 30/33] Add TSC meeting notes for 06-29-2020 (#1049) Signed-off-by: Michael Dolan Co-authored-by: Patrick Hodoul --- docs/tsc/meetings/2020-06-29.md | 90 +++++++++++++++++++++++++++++++++ 1 file changed, 90 insertions(+) create mode 100644 docs/tsc/meetings/2020-06-29.md diff --git a/docs/tsc/meetings/2020-06-29.md b/docs/tsc/meetings/2020-06-29.md new file mode 100644 index 0000000000..a002f050d0 --- /dev/null +++ b/docs/tsc/meetings/2020-06-29.md @@ -0,0 +1,90 @@ + + + +June 29, 2020 + +Host: Michael Dolan + +Rotating Secretary: Michael Dolan + +Attendees: + * [X] Mark Boorer (_TSC_) - Industrial Light & Magic + * [X] Mei Chu (_TSC_) - Sony Pictures Imageworks + * [X] Sean Cooper (_TSC ACES TAC Rep_) - DNEG + * [X] Michael Dolan (_TSC Chair_) - Epic Games + * [X] Patrick Hodoul (_TSC_) - Autodesk + * [ ] John Mertic - Academy Software Foundation / Linux Foundation + * [X] Carol Payne (_TSC_) - Netflix + * [X] Mark Titchener (_TSC_) - Foundry + * [ ] Carl Rand (_TSC_) - Weta Digital + * [X] Doug Walker (_TSC Chief Architect_) - Autodesk + * [X] Kevin Wheatley (_TSC_) - Framestore + * [X] Bernard Lefebvre - Autodesk + * [X] Troy Sobotka + +Apologies: + NONE + +# **OCIO TSC Meeting Notes** + +* Open source day, DigiPro, SIGGRAPH plans: + - Michael: Plans not final yet for Open Source Day, but between these + events, how do we want to announce and present the OCIO v2 release. + - Both DigiPro and OSD are 25 minute presentations. + - Patrick: These are not enough time for all of v2. + - Doug: Main thing at SIGGRAPH is to get the word out, get it on people's + radar. SIGGRAPH will be a busy time with many zoom meetings over those + weeks. We'll probably want to do something longer after. + - Patrick: Would the audience be the same as with the v2 working group? + - Doug: Would be bigger group. We do want to have a presentation more for + developers that want to upgrade their app to use v2. + - Patrick: How do we make sure we have these people? How do we get more + people who are less active in other discussions. + - Carol: If we have a presentation at SIGGRAPH, part of that could be to + bring up when questions can be discussed at a later, less formal, event. + - Michael: Could we do the longer meeting as a Bof? To also leverage the + SIGGRAPH schedule? + - Sean: Will be good to have something on the schedule. Get the initial + discussion, updates, etc. to the general audience, and invite them to + something specific afterwords. May be able to put out word at the VFX + Reference Platform discussion. + - Carol: Can the DigiPro talk be done twice? Once at OSD, once at DigiPro? + - Doug: OSD might require more practical project related topics to cover. + We have a lot of material to cover. Could talk at OSD about case study + of OCIO joining ASWF. + - Patrick: ASWF will provide a forum, but we can decide how to use that + time and what content to cover. + - DigiPro to focus more on technical part of paper; OSD to focus more on + admin aspects of project, and as an invite to longer BoF session; BoF + to provide longer update and discussion forum. The BoF could also be + replaced by a later independent event if needed. + +* Summer vacations: + - Patrick out second half of July. + - Michael out next week. + +* OpenColorIO-Config-ACES meeting tomorrow: + - Continue discussion on initial work to design and build the config. 4pm + EST, 1pm PST. + +* Pending PRs: + - Close to feature complete. Please have a look to keep reviews moving. + - Sean: PRs with multiple contributors are getting complicated. Not now, + but we may want to explore using shared feature branches in main repo for + collaboration. Topic for future discussion. + - Patrick: Student actively working on headless rendering support. Making + great progress, but currently encountering CI failures. Headed in the + right direction. + - Mark: Making progress on OpenColorMath. Currently working on the JIT + evaluator. + +* Slack #helpdesk channel: + - Sean: Added a new #helpdesk channel to Slack to help with general + questions. With self-signup being active that will be a good place to + manage those discussions. + +* V2 Working Group Discussion: + - Kevin: Looks like last v2 update got cut short based on slides. Anything + more to discuss? + - Doug: Will set up another meeting in near future. More to discuss around + caching and context variables. From 03a1650cb1ecbd9e41627850fb095931aaa560fc Mon Sep 17 00:00:00 2001 From: Chin-Ying Li Date: Thu, 9 Jul 2020 18:33:00 -0400 Subject: [PATCH 31/33] Headless rendering (#1047) * Modified CMakeLists.txt Signed-off-by: ChinYing-Li * Support headless rendering in Linux build with EGL (#1039) Signed-off-by: ChinYing-Li * Fix CMakeLists bugs Made OglApp's destructor virtual Signed-off-by: ChinYing-Li * Remove bugs in app's CMakeLists (#1039) Signed-off-by: ChinYing-Li * Modified CMakeLists and add factory function for OglAppRcPtr (#1039) Signed-off-by: ChinYing-Li * Use imported target to find EGL (#1039) Change the CI workflow to build with headless option Signed-off-by: ChinYing-Li * Modify CMakeLists to properly link EGL (#1039) Remove unused variables (#1039) Include glext.h and debug print (#1039) Check GLEW initialization (#1039) Signed-off-by: ChinYing-Li * Add debug print for HeadlessApp initialization (#1039) Signed-off-by: ChinYing-Li * Modify CMakeLists to accomodate system that support GLVND (#1039) Remove unused variables (#1039) Define GLEW_EGL preprocessor for NVidia implementation (#1039) Signed-off-by: ChinYing-Li * Fix CMakeLists (#1039) Add the factory method for creating OglAppRcPtr Modify CMakeLists (#1039) Signed-off-by: ChinYing-Li * Rename the factory method OglApp::CreateOglApp (#1039) Signed-off-by: ChinYing-Li * Change workflow to check the GL vendor of CI Linux build (#1039) Signed-off-by: ChinYing-Li * Add proper mechanism to detect GLVND support in CmakeLists (#1039) Signed-off-by: ChinYing-Li * Reformat the code (#1039) Signed-off-by: ChinYing-Li * Turn off GPU unit test in CI (#1039) Signed-off-by: ChinYing-Li --- .github/workflows/ci_workflow.yml | 49 +++++- CMakeLists.txt | 62 +++++-- src/apps/ociochecklut/main.cpp | 3 +- src/apps/ocioconvert/CMakeLists.txt | 1 - src/apps/ocioconvert/main.cpp | 5 +- src/apps/ociodisplay/main.cpp | 2 +- src/libutils/oglapphelpers/CMakeLists.txt | 51 +++++- src/libutils/oglapphelpers/oglapp.cpp | 191 +++++++++++++++++----- src/libutils/oglapphelpers/oglapp.h | 100 ++++++++--- tests/gpu/GPUUnitTest.cpp | 28 ++-- 10 files changed, 390 insertions(+), 102 deletions(-) diff --git a/.github/workflows/ci_workflow.yml b/.github/workflows/ci_workflow.yml index 50ee62fd8e..6412f0d43b 100644 --- a/.github/workflows/ci_workflow.yml +++ b/.github/workflows/ci_workflow.yml @@ -65,6 +65,8 @@ jobs: build-type: Release build-shared: 'ON' build-docs: 'ON' + build-gpu: 'OFF' + use-headless: 'OFF' use-sse: 'ON' cxx-standard: 11 cxx-compiler: g++ @@ -76,6 +78,8 @@ jobs: build-type: Debug build-shared: 'ON' build-docs: 'OFF' + build-gpu: 'OFF' + use-headless: 'OFF' use-sse: 'ON' cxx-standard: 11 cxx-compiler: g++ @@ -87,6 +91,8 @@ jobs: build-type: Release build-shared: 'ON' build-docs: 'OFF' + build-gpu: 'OFF' + use-headless: 'OFF' use-sse: 'ON' cxx-standard: 14 cxx-compiler: g++ @@ -98,6 +104,8 @@ jobs: build-type: Release build-shared: 'OFF' build-docs: 'OFF' + build-gpu: 'OFF' + use-headless: 'OFF' use-sse: 'OFF' cxx-standard: 11 cxx-compiler: g++ @@ -112,6 +120,8 @@ jobs: build-type: Release build-shared: 'ON' build-docs: 'ON' + build-gpu: 'OFF' + use-headless: 'OFF' use-sse: 'ON' cxx-standard: 11 cxx-compiler: g++ @@ -126,6 +136,8 @@ jobs: build-type: Release build-shared: 'ON' build-docs: 'ON' + build-gpu: 'OFF' + use-headless: 'OFF' use-sse: 'ON' cxx-standard: 11 cxx-compiler: clang++ @@ -137,6 +149,8 @@ jobs: build-type: Debug build-shared: 'ON' build-docs: 'OFF' + build-gpu: 'OFF' + build-headless: 'OFF' use-sse: 'ON' cxx-standard: 11 cxx-compiler: clang++ @@ -148,6 +162,8 @@ jobs: build-type: Release build-shared: 'ON' build-docs: 'OFF' + build-gpu: 'OFF' + use-headless: 'OFF' use-sse: 'ON' cxx-standard: 14 cxx-compiler: clang++ @@ -159,6 +175,8 @@ jobs: build-type: Release build-shared: 'OFF' build-docs: 'OFF' + build-gpu: 'OFF' + use-headless: 'OFF' use-sse: 'OFF' cxx-standard: 11 cxx-compiler: clang++ @@ -173,6 +191,8 @@ jobs: build-type: Release build-shared: 'ON' build-docs: 'ON' + build-gpu: 'OFF' + use-headless: 'OFF' use-sse: 'ON' cxx-standard: 11 cxx-compiler: clang++ @@ -202,7 +222,8 @@ jobs: -DCMAKE_CXX_STANDARD=${{ matrix.cxx-standard }} \ -DBUILD_SHARED_LIBS=${{ matrix.build-shared }} \ -DOCIO_BUILD_DOCS=${{ matrix.build-docs }} \ - -DOCIO_BUILD_GPU_TESTS=OFF \ + -DOCIO_BUILD_GPU_TESTS=${{ matrix.build-gpu }} \ + -DOCIO_USE_HEADLESS=${{ matrix.use-headless }} \ -DOCIO_USE_SSE=${{ matrix.use-sse }} \ -DOCIO_INSTALL_EXT_PACKAGES=ALL \ -DOCIO_WARNING_AS_ERROR=ON \ @@ -242,6 +263,8 @@ jobs: build-type: Release build-shared: 'ON' build-docs: 'ON' + build-gpu: 'OFF' + use-headless: 'OFF' use-sse: 'ON' cxx-standard: 11 python-version: 3.7 @@ -250,6 +273,8 @@ jobs: build-type: Debug build-shared: 'ON' build-docs: 'OFF' + build-gpu: 'OFF' + use-headless: 'OFF' use-sse: 'ON' cxx-standard: 11 python-version: 3.7 @@ -258,6 +283,8 @@ jobs: build-type: Release build-shared: 'ON' build-docs: 'OFF' + build-gpu: 'OFF' + use-headless: 'OFF' use-sse: 'ON' cxx-standard: 14 python-version: 3.7 @@ -266,6 +293,8 @@ jobs: build-type: Release build-shared: 'OFF' build-docs: 'OFF' + build-gpu: 'OFF' + use-headless: 'OFF' use-sse: 'OFF' cxx-standard: 11 python-version: 3.7 @@ -274,6 +303,8 @@ jobs: build-type: Release build-shared: 'ON' build-docs: 'ON' + build-gpu: 'OFF' + use-headless: 'OFF' use-sse: 'ON' cxx-standard: 11 python-version: 2.7 @@ -296,7 +327,8 @@ jobs: -DCMAKE_CXX_STANDARD=${{ matrix.cxx-standard }} \ -DBUILD_SHARED_LIBS=${{ matrix.build-shared }} \ -DOCIO_BUILD_DOCS=${{ matrix.build-docs }} \ - -DOCIO_BUILD_GPU_TESTS=OFF \ + -DOCIO_BUILD_GPU_TESTS=${{ matrix.build-gpu }} \ + -DOCIO_USE_HEADLESS=${{ matrix.use-headless }} \ -DOCIO_USE_SSE=${{ matrix.use-sse }} \ -DOCIO_INSTALL_EXT_PACKAGES=ALL \ -DOCIO_WARNING_AS_ERROR=ON \ @@ -338,6 +370,8 @@ jobs: build-type: Release build-shared: 'ON' build-docs: 'ON' + build-gpu: 'OFF' + use-headless: 'OFF' use-sse: 'ON' cxx-standard: 11 python-version: 3.7 @@ -346,6 +380,8 @@ jobs: build-type: Debug build-shared: 'ON' build-docs: 'OFF' + build-gpu: 'OFF' + use-headless: 'OFF' use-sse: 'ON' cxx-standard: 11 python-version: 3.7 @@ -354,6 +390,8 @@ jobs: build-type: Release build-shared: 'ON' build-docs: 'OFF' + build-gpu: 'OFF' + use-headless: 'OFF' use-sse: 'ON' cxx-standard: 14 python-version: 3.7 @@ -362,6 +400,8 @@ jobs: build-type: Release build-shared: 'OFF' build-docs: 'OFF' + build-gpu: 'OFF' + use-headless: 'OFF' use-sse: 'OFF' cxx-standard: 11 python-version: 3.7 @@ -370,6 +410,8 @@ jobs: build-type: Release build-shared: 'ON' build-docs: 'ON' + build-gpu: 'OFF' + use-headless: 'OFF' use-sse: 'ON' cxx-standard: 11 python-version: 2.7 @@ -394,7 +436,8 @@ jobs: -DCMAKE_GENERATOR_PLATFORM=x64 \ -DBUILD_SHARED_LIBS=${{ matrix.build-shared }} \ -DOCIO_BUILD_DOCS=${{ matrix.build-docs }} \ - -DOCIO_BUILD_GPU_TESTS=OFF \ + -DOCIO_BUILD_GPU_TESTS=${{ matrix.build-gpu }} \ + -DOCIO_USE_HEADLESS=${{ matrix.use-headless }} \ -DOCIO_USE_SSE=${{ matrix.use-sse }} \ -DOCIO_INSTALL_EXT_PACKAGES=ALL \ -DOCIO_WARNING_AS_ERROR=ON \ diff --git a/CMakeLists.txt b/CMakeLists.txt index 99ff3d42e8..89c5379763 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -75,6 +75,7 @@ option(OCIO_BUILD_NUKE "Specify whether to build nuke plugins" OFF) option(OCIO_BUILD_DOCS "Specify whether to build documentation" OFF) option(OCIO_BUILD_TESTS "Specify whether to build unittests" ON) option(OCIO_BUILD_GPU_TESTS "Specify whether to build gpu unittests" ON) +option(OCIO_USE_HEADLESS "Specify whether the GPU rendering is headless" OFF) option(OCIO_BUILD_PYTHON "Specify whether to build python bindings" ON) option(OCIO_BUILD_JAVA "Specify whether to build java bindings" OFF) @@ -87,30 +88,65 @@ option(OCIO_WARNING_AS_ERROR "Set build error level for CI testing" OFF) include(PackageUtils) if(OCIO_BUILD_GPU_TESTS OR OCIO_BUILD_APPS) - set(OCIO_GL_ENABLED ON) - - find_package(OpenGL) - if(NOT OpenGL_FOUND) - package_root_message(OpenGL) + set(OCIO_GL_ENABLED ON) + + find_package(OpenGL REQUIRED COMPONENTS OpenGL) + if(NOT OpenGL_OpenGL_FOUND AND NOT OPENGL_GLU_FOUND) + message(WARNING "OpenGL not found; GPU rendering disabled") set(OCIO_GL_ENABLED OFF) - endif() - - if(NOT APPLE) - find_package(GLEW) + endif() + + # OpenGL_egl_Library is defined iff GLVND is supported (CMake 10+). + if(OPENGL_egl_LIBRARY) + message(STATUS "GLVND supported") + set(OCIO_USE_GLVND ON) + else() + message(STATUS "GLVND not supported; legacy OpenGL libraries used") + set(OCIO_USE_GLVND OFF) + endif() + + if(NOT APPLE) + find_package(GLEW QUIET) if(NOT GLEW_FOUND) - package_root_message(GLEW) + message(WARNING "GLEW not found") set(OCIO_GL_ENABLED OFF) endif() endif() find_package(GLUT) if(NOT GLUT_FOUND) - package_root_message(GLUT) + message(WARNING "GLUT not found") set(OCIO_GL_ENABLED OFF) - endif() - + endif() + + set(OCIO_EGL_HEADLESS OFF) + if(${OCIO_USE_HEADLESS}) + if(CMAKE_SYSTEM_NAME STREQUAL Linux) + if(NOT ${OCIO_USE_GLVND}) + message(STATUS "Can't find EGL without GLVND support; can't render headlessly") + set(OCIO_USE_HEADLESS OFF) + set(OCIO_EGL_HEADLESS OFF) + else() + set(OCIO_EGL_HEADLESS ON) + find_package(OpenGL COMPONENTS EGL) + if(NOT OpenGL_EGL_FOUND) + message(WARNING "EGL component missing; can't render headlessly") + set(OCIO_USE_HEADLESS OFF) + set(OCIO_EGL_HEADLESS OFF) + else() + add_compile_definitions(OCIO_HEADLESS_ENABLED) + endif() + endif() + else() + message(WARNING "OS system is not Linux; can't render headlessly") + set(OCIO_EGL_HEADLESS OFF) + endif() + endif() endif() +message(STATUS "GL enabled " ${OCIO_GL_ENABLED}) +message(STATUS "EGL enabled " ${OCIO_EGL_HEADLESS}) + ############################################################################### # Optimization / internal linking preferences diff --git a/src/apps/ociochecklut/main.cpp b/src/apps/ociochecklut/main.cpp index 3ece52b28f..9175c240e9 100644 --- a/src/apps/ociochecklut/main.cpp +++ b/src/apps/ociochecklut/main.cpp @@ -46,7 +46,8 @@ class ProcessorWrapper { #ifdef OCIO_GPU_ENABLED m_gpu = gpu; - m_oglApp = std::make_shared("ociochecklut", 256, 20); + m_oglApp = OCIO::OglApp::CreateOglApp("ociochecklut", 256, 20); + if (m_verbose) { m_oglApp->printGLInfo(); diff --git a/src/apps/ocioconvert/CMakeLists.txt b/src/apps/ocioconvert/CMakeLists.txt index d1a9d907cd..68a5db17b6 100755 --- a/src/apps/ocioconvert/CMakeLists.txt +++ b/src/apps/ocioconvert/CMakeLists.txt @@ -37,4 +37,3 @@ target_link_libraries(ocioconvert install(TARGETS ocioconvert RUNTIME DESTINATION bin ) - diff --git a/src/apps/ocioconvert/main.cpp b/src/apps/ocioconvert/main.cpp index 0c52dffa69..40ad6e09ed 100644 --- a/src/apps/ocioconvert/main.cpp +++ b/src/apps/ocioconvert/main.cpp @@ -30,7 +30,6 @@ namespace OIIO = OIIO_NAMESPACE; // Array of non OpenColorIO arguments. static std::vector args; - // Fill 'args' array with OpenColorIO arguments. static int parse_end_args(int argc, const char *argv[]) @@ -401,8 +400,8 @@ int main(int argc, const char **argv) #ifdef OCIO_GPU_ENABLED // Initialize GPU. - OCIO::OglAppRcPtr oglApp; + if (usegpu || usegpuLegacy) { OCIO::OglApp::Components comp = OCIO::OglApp::COMPONENTS_RGBA; @@ -422,7 +421,7 @@ int main(int argc, const char **argv) try { - oglApp = std::make_shared("ocioconvert", 256, 20); + oglApp = OCIO::OglApp::CreateOglApp("ocioconvert", 256, 20); } catch (const OCIO::Exception & e) { diff --git a/src/apps/ociodisplay/main.cpp b/src/apps/ociodisplay/main.cpp index 6b4e6d2860..a11d389cbf 100644 --- a/src/apps/ociodisplay/main.cpp +++ b/src/apps/ociodisplay/main.cpp @@ -643,7 +643,7 @@ int main(int argc, char **argv) try { - g_oglApp = std::make_shared("ociodisplay", 512, 512); + g_oglApp = std::make_shared("ociodisplay", 512, 512); } catch (const OCIO::Exception & e) { diff --git a/src/libutils/oglapphelpers/CMakeLists.txt b/src/libutils/oglapphelpers/CMakeLists.txt index 1d61721cdb..2c8f495a11 100644 --- a/src/libutils/oglapphelpers/CMakeLists.txt +++ b/src/libutils/oglapphelpers/CMakeLists.txt @@ -10,7 +10,6 @@ set(SOURCES glsl.cpp oglapp.cpp ) - set(INCLUDES glsl.h oglapp.h @@ -39,13 +38,49 @@ target_include_directories(oglapphelpers ${GLUT_INCLUDE_DIR} ) -target_link_libraries(oglapphelpers - PRIVATE - OpenColorIO - ${OPENGL_LIBRARIES} - ${GLEW_LIBRARIES} - ${GLUT_LIBRARIES} -) + +if(${OCIO_USE_GLVND}) + if(${OCIO_EGL_HEADLESS}) + target_include_directories(oglapphelpers + PRIVATE + ${OPENGL_EGL_INCLUDE_DIRS} + ) + target_link_libraries(oglapphelpers + PRIVATE + OpenColorIO + OpenGL::OpenGL + OpenGL::GLU + ${GLEW_LIBRARIES} + ${GLUT_LIBRARIES} + OpenGL::EGL + ) + else() + target_link_libraries(oglapphelpers + PRIVATE + OpenColorIO + OpenGL::OpenGL + OpenGL::GLU + ${GLEW_LIBRARIES} + ${GLUT_LIBRARIES} + ) + endif() +else() + # if OCIO_USE_GLVND is OFF, OCIO_EGL_HEADLESS is also OFF + target_link_libraries(oglapphelpers + PRIVATE + OpenColorIO + ${OPENGL_LIBRARIES} + ${GLEW_LIBRARIES} + ${GLUT_LIBRARIES} + ) +endif() + +if(${OCIO_EGL_HEADLESS}) + target_include_directories(oglapphelpers + PRIVATE + ${OPENGL_EGL_INCLUDE_DIRS} + ) +endif() install(TARGETS oglapphelpers LIBRARY DESTINATION lib diff --git a/src/libutils/oglapphelpers/oglapp.cpp b/src/libutils/oglapphelpers/oglapp.cpp index 030d33e9c2..644606d01e 100644 --- a/src/libutils/oglapphelpers/oglapp.cpp +++ b/src/libutils/oglapphelpers/oglapp.cpp @@ -27,52 +27,20 @@ #include - #include "oglapp.h" namespace OCIO_NAMESPACE { -OglApp::OglApp(const char * winTitle, int winWidth, int winHeight) +OglApp::OglApp(int winWidth, int winHeight) : m_viewportWidth(winWidth) , m_viewportHeight(winHeight) -{ - int argc = 2; - const char * argv[] = { winTitle, "-glDebug" }; - glutInit(&argc, const_cast(&argv[0])); - - glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE | GLUT_DEPTH); - glutInitWindowSize(m_viewportWidth, m_viewportHeight); - glutInitWindowPosition(0, 0); - - m_mainWin = glutCreateWindow(argv[0]); - -#ifndef __APPLE__ - glewInit(); - if (!glewIsSupported("GL_VERSION_2_0")) - { - throw Exception("OpenGL 2.0 not supported."); - } -#endif - - // Initialize the OpenGL engine. - - glPixelStorei(GL_UNPACK_ALIGNMENT, 4); // 4-byte pixel alignment - -#ifndef __APPLE__ - glClampColor(GL_CLAMP_READ_COLOR, GL_FALSE); // - glClampColor(GL_CLAMP_VERTEX_COLOR, GL_FALSE); // avoid any kind of clamping - glClampColor(GL_CLAMP_FRAGMENT_COLOR, GL_FALSE); // -#endif - - glEnable(GL_TEXTURE_2D); -} +{} OglApp::~OglApp() { m_oglBuilder.reset(); - glutDestroyWindow(m_mainWin); } void OglApp::initImage(int imgWidth, int imgHeight, Components comp, const float * image) @@ -166,8 +134,6 @@ void OglApp::redisplay() glDisable(GL_TEXTURE_2D); - glutSwapBuffers(); - } void OglApp::reshape(int width, int height) @@ -264,5 +230,156 @@ void OglApp::printGLInfo() const noexcept << "GL Version: " << glGetString(GL_VERSION) << std::endl << "GLSL Version: " << glGetString(GL_SHADING_LANGUAGE_VERSION) << std::endl; } -} // namespace OCIO_NAMESPACE +void OglApp::setupCommon() +{ +#ifndef __APPLE__ + glewInit(); + + // TO DO: Find out why glewInit() != GLEW_OK + + if (!glewIsSupported("GL_VERSION_2_0")) + { + throw Exception("OpenGL 2.0 not supported."); + } +#endif + + // Initialize the OpenGL engine. + + glPixelStorei(GL_UNPACK_ALIGNMENT, 4); // 4-byte pixel alignment + +#ifndef __APPLE__ + glClampColor(GL_CLAMP_READ_COLOR, GL_FALSE); // + glClampColor(GL_CLAMP_VERTEX_COLOR, GL_FALSE); // avoid any kind of clamping + glClampColor(GL_CLAMP_FRAGMENT_COLOR, GL_FALSE); // +#endif + + glEnable(GL_TEXTURE_2D); +} + +OglAppRcPtr OglApp::CreateOglApp(const char * winTitle, int winWidth, int winHeight) +{ +#ifdef OCIO_HEADLESS_ENABLED + return std::make_shared(winTitle, winWidth, winHeight); +#else + return std::make_shared(winTitle, winWidth, winHeight); +#endif +} + +ScreenApp::ScreenApp(const char * winTitle, int winWidth, int winHeight): + OglApp(winWidth, winHeight) +{ + int argc = 2; + const char * argv[] = { winTitle, "-glDebug" }; + + glutInit(&argc, const_cast(&argv[0])); + + glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE | GLUT_DEPTH); + glutInitWindowSize(m_viewportWidth, m_viewportHeight); + glutInitWindowPosition(0, 0); + + m_mainWin = glutCreateWindow(argv[0]); + + setupCommon(); +} + +ScreenApp::~ScreenApp() +{ + glutDestroyWindow(m_mainWin); +} + +void ScreenApp::redisplay() +{ + OglApp::redisplay(); + glutSwapBuffers(); +} + +void ScreenApp::printGLInfo() const noexcept +{ + OglApp::printGLInfo(); +} + +#ifdef OCIO_HEADLESS_ENABLED + +HeadlessApp::HeadlessApp(const char * winTitle, int bufWidth, int bufHeight) + : OglApp(bufWidth, bufHeight) + , m_pixBufferWidth(bufWidth) + , m_pixBufferHeight(bufHeight) +{ + m_configAttribs = + { + EGL_SURFACE_TYPE, EGL_PBUFFER_BIT, + EGL_BLUE_SIZE, 8, + EGL_GREEN_SIZE, 8, + EGL_RED_SIZE, 8, + EGL_DEPTH_SIZE, 8, + EGL_RENDERABLE_TYPE, EGL_OPENGL_BIT, + EGL_NONE + }; + + m_pixBufferAttribs = + { + EGL_WIDTH, m_pixBufferWidth, + EGL_HEIGHT, m_pixBufferHeight, + EGL_NONE, + }; + + m_eglDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY); + if(m_eglDisplay == EGL_NO_DISPLAY ) + { + throw Exception("EGL could not be initialized."); + } + + EGLint eglMajor, eglMinor; + if(eglInitialize(m_eglDisplay, &eglMajor, &eglMinor) != EGL_TRUE) + { + throw Exception("EGL display connection couldn't be started."); + } + + // Choose an appropriate configuration. + EGLint numConfigs; + if(eglChooseConfig(m_eglDisplay, &m_configAttribs[0], &m_eglConfig, 1, &numConfigs) != EGL_TRUE) + { + throw Exception("Failed to choose EGL configuration."); + } + + m_eglSurface = eglCreatePbufferSurface(m_eglDisplay, m_eglConfig, &m_pixBufferAttribs[0]); + eglBindAPI(EGL_OPENGL_API); + + // Create a context and make it current. + m_eglContext = eglCreateContext(m_eglDisplay, m_eglConfig, EGL_NO_CONTEXT, NULL); + if(eglMakeCurrent(m_eglDisplay, m_eglSurface, m_eglSurface, m_eglContext) != EGL_TRUE) + { + throw Exception("Could not make EGL context current."); + } + + setupCommon(); +} + +HeadlessApp::~HeadlessApp() +{ + eglTerminate(m_eglDisplay); +} + +void HeadlessApp::printGLInfo() const noexcept +{ + OglApp::printGLInfo(); + printEGLInfo(); +} + +void HeadlessApp::printEGLInfo() const noexcept +{ + std::cout << std::endl + << "EGL Vendor: " << eglQueryString(m_eglDisplay, EGL_VENDOR) << std::endl + << "EGL Version: " << eglQueryString(m_eglDisplay, EGL_VERSION) << std::endl; +} + +void HeadlessApp::redisplay() +{ + OglApp::redisplay(); + eglSwapBuffers(m_eglDisplay, m_eglSurface); +} + +#endif + +} // namespace OCIO_NAMESPACE diff --git a/src/libutils/oglapphelpers/oglapp.h b/src/libutils/oglapphelpers/oglapp.h index f60046d62e..ef1ba96d15 100644 --- a/src/libutils/oglapphelpers/oglapp.h +++ b/src/libutils/oglapphelpers/oglapp.h @@ -22,44 +22,48 @@ namespace OCIO_NAMESPACE // the GPU. /* -// Create and initialize. Unfortunately, even for non-GUI apps we need to create a window that -// will appear in the UI so here you specify the name of the window and its size. For non-GUI -// apps you may want to use a small size (it does not need to match the size of the image being -// processed). -OglApp oglApp("Window Name", windowWidth, windowHeight); +// Create and initialize OglAppRcPtr by creating a shared pointer to ScreenApp. You have to +// specify the name of the window and its size. OglAppRcPtr that points to HeadlessApp object +// can be created and used in the same way. +OglAppRcPtr scrApp = std::make_shared("Window Name", windowWidth, windowHeight); float * imageBuffer = GetImageBuffer(); int imageWidth = GetImageWidth(); int imageHeight = GetImageHeight(); -oglApp.initImage(imagewidth, imageheight, OglApp::COMPONENTS_RGB, imageBuffer); -oglApp.createGLBuffers(); +scrApp->initImage(imagewidth, imageheight, OglApp::COMPONENTS_RGB, imageBuffer); +scrApp->createGLBuffers(); // Set (or change) shader. GpuShaderDescRcPtr shader = GpuShaderDesc::CreateShaderDesc(); processor->getDefaultGPUProcessor()->extractGpuShaderInfo(shader); - -oglApp.setShader(shader); +scrApp->setShader(shader); // Process the image: // - Call reshape to make the window size match the size of the image being processed. (This will // not update the size of the window in the UI.). -oglApp.reshape(imageWidth, imageHeight); +scrApp->reshape(imageWidth, imageHeight); // - Call redisplay to apply the shader. -oglApp.redisplay(); +scrApp->redisplay(); // Read the processed image. std::vector imageBufferOut(3 * imageWidth * imageWidth); -oglApp.readImage(imageBufferOut.data()); +scrApp->readImage(imageBufferOut.data()); */ + +// Forward declaration of OglApp. +class OglApp; +typedef OCIO_SHARED_PTR OglAppRcPtr; + class OglApp { public: OglApp() = delete; // Initialize the app with given window name & client rect size. - OglApp(const char * winTitle, int winWidth, int winHeight); - ~OglApp(); + OglApp(int winWidth, int winHeight); + + virtual ~OglApp(); // When displaying the processed image in a window this needs to be done. // In that case, when image is read, the result will be mirrored on Y. @@ -103,20 +107,20 @@ class OglApp void updateUniforms(); // Process the image. - void redisplay(); + void virtual redisplay(); // Read the image from the rendering buffer. It is not meant to be used by interactive // applications used to display the image. void readImage(float * imageBuffer); // Helper to print GL info. - void printGLInfo() const noexcept; + void virtual printGLInfo() const noexcept; -private: - - // Window identifier returned by glutCreateWindow. - int m_mainWin{ 0 }; + // Return a pointer of either ScreenApp or HeadlessApp depending on the + // OCIO_HEADLESS_ENABLED preprocessor. + static OglAppRcPtr CreateOglApp(const char * winTitle, int winWidth, int winHeight); +protected: // Window or output image size (set using reshape). // When the app is used to process an image this should be equal to the image size so that // when processed image is read from the viewport it matches the size of the original image. @@ -125,6 +129,10 @@ class OglApp int m_viewportWidth{ 0 }; int m_viewportHeight{ 0 }; + // Initialize the OpenGL engine, and set up GLEW if needed. + void setupCommon(); + +private: // Keep track of the original image ratio. float m_imageAspect{ 1.0f }; @@ -141,11 +149,61 @@ class OglApp unsigned int m_imageTexID; OpenGLBuilderRcPtr m_oglBuilder; +}; + +class ScreenApp: public OglApp +{ +public: + ScreenApp() = delete; + ScreenApp(const char * winTitle, int winWidth, int winHeight); + + ~ScreenApp(); + + void redisplay() override; + void printGLInfo() const noexcept override; + +private: + // Window identifier returned by glutCreateWindow. + int m_mainWin{ 0 }; }; -typedef OCIO_SHARED_PTR OglAppRcPtr; +#ifdef OCIO_HEADLESS_ENABLED + +#include + +class HeadlessApp: public OglApp +{ +public: + HeadlessApp() = delete; + + HeadlessApp(const char * winTitle, int bufWidth, int bufHeight); + + ~HeadlessApp(); + + void printGLInfo() const noexcept override; + void redisplay() override; + +protected: + // Helper function to print EGL info. + void printEGLInfo() const noexcept; + +private: + EGLint m_pixBufferWidth{ 0 }; + EGLint m_pixBufferHeight{ 0 }; + std::vector m_pixBufferAttribs; + + EGLDisplay m_eglDisplay; + EGLSurface m_eglSurface; + EGLConfig m_eglConfig; + EGLContext m_eglContext; + + std::vector m_configAttribs; +}; + +#endif } // namespace OCIO_NAMESPACE #endif // INCLUDED_OCIO_OGLAPP_H + diff --git a/tests/gpu/GPUUnitTest.cpp b/tests/gpu/GPUUnitTest.cpp index 8463bde5c5..ca0b587346 100644 --- a/tests/gpu/GPUUnitTest.cpp +++ b/tests/gpu/GPUUnitTest.cpp @@ -198,12 +198,12 @@ namespace static constexpr unsigned g_winHeight = 256; static constexpr unsigned g_components = 4; - void AllocateImageTexture(OCIO::OglApp & app) + void AllocateImageTexture(OCIO::OglAppRcPtr & app) { const unsigned numEntries = g_winWidth * g_winHeight * g_components; OCIOGPUTest::CustomValues::Values image(numEntries, 0.0f); - app.initImage(g_winWidth, g_winHeight, OCIO::OglApp::COMPONENTS_RGBA, &image[0]); + app->initImage(g_winWidth, g_winHeight, OCIO::OglApp::COMPONENTS_RGBA, &image[0]); } void SetTestValue(float * image, float val, unsigned numComponents) @@ -218,7 +218,7 @@ namespace } } - void UpdateImageTexture(OCIO::OglApp & app, OCIOGPUTestRcPtr & test) + void UpdateImageTexture(OCIO::OglAppRcPtr & app, OCIOGPUTestRcPtr & test) { // Note: User-specified custom values are padded out // to the preferred size (g_winWidth x g_winHeight). @@ -320,17 +320,17 @@ namespace throw OCIO::Exception("Missing some expected input values"); } - app.updateImage(&values.m_inputValues[0]); + app->updateImage(&values.m_inputValues[0]); } - void UpdateOCIOGLState(OCIO::OglApp & app, OCIOGPUTestRcPtr & test) + void UpdateOCIOGLState(OCIO::OglAppRcPtr & app, OCIOGPUTestRcPtr & test) { - app.setPrintShader(test->isVerbose()); + app->setPrintShader(test->isVerbose()); OCIO::ConstProcessorRcPtr & processor = test->getProcessor(); OCIO::GpuShaderDescRcPtr & shaderDesc = test->getShaderDesc(); // Collect the shader program information for a specific processor. processor->getDefaultGPUProcessor()->extractGpuShaderInfo(shaderDesc); - app.setShader(shaderDesc); + app->setShader(shaderDesc); } void DiffComponent(const std::vector & cpuImage, @@ -366,7 +366,7 @@ namespace static constexpr size_t invalidIndex = std::numeric_limits::max(); // Validate the GPU processing against the CPU one. - void ValidateImageTexture(OCIO::OglApp & app, OCIOGPUTestRcPtr & test) + void ValidateImageTexture(OCIO::OglAppRcPtr & app, OCIOGPUTestRcPtr & test) { OCIO::ConstCPUProcessorRcPtr processor = test->getProcessor()->getDefaultCPUProcessor(); @@ -406,7 +406,7 @@ namespace // Step 2: Grab the GPU output from the rendering buffer. OCIOGPUTest::CustomValues::Values gpuImage(g_winWidth*g_winHeight*g_components, 0.0f); - app.readImage(&gpuImage[0]); + app->readImage(&gpuImage[0]); // Step 3: Compare the two results. @@ -501,7 +501,7 @@ int main(int, char **) OCIO::OglAppRcPtr app; try { - app = std::make_shared("GPU tests", 10, 10); + app = OCIO::OglApp::CreateOglApp("GPU tests", 10, 10); } catch (const OCIO::Exception & e) { @@ -512,7 +512,7 @@ int main(int, char **) app->printGLInfo(); // Step 2: Allocate the texture that holds the image. - AllocateImageTexture(*app); + AllocateImageTexture(app); // Step 3: Create the frame buffer and render buffer. app->createGLBuffers(); @@ -558,10 +558,10 @@ int main(int, char **) if(test->isValid() && enabledTest) { // Initialize the texture with the RGBA values to be processed. - UpdateImageTexture(*app, test); + UpdateImageTexture(app, test); // Update the GPU shader program. - UpdateOCIOGLState(*app, test); + UpdateOCIOGLState(app, test); const size_t numRetest = test->getNumRetests(); // Need to run once and for each retest. @@ -580,7 +580,7 @@ int main(int, char **) // Compute the expected values using the CPU and compare // against the GPU values. - ValidateImageTexture(*app, test); + ValidateImageTexture(app, test); } } } From 54ed8bb14618b707c1a65522d8938c4d3055ec3c Mon Sep 17 00:00:00 2001 From: Troy James Sobotka Date: Thu, 9 Jul 2020 16:43:50 -0700 Subject: [PATCH 32/33] Removes commented out OCIO_BUILD_PYTHON (#1055) Fixes #1050. Authored by @LazyDodo. Signed-off-by: Troy James Sobotka Co-authored-by: Patrick Hodoul --- tests/CMakeLists.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index b2076b3a90..89332a11ad 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -20,6 +20,6 @@ if(OCIO_BUILD_JAVA) add_subdirectory(java) endif() -#if(OCIO_BUILD_PYTHON) +if(OCIO_BUILD_PYTHON) add_subdirectory(python) -#endif() +endif() From acf1d150f3a1127bb3f9a750b7544819d59b4ad0 Mon Sep 17 00:00:00 2001 From: Michael Dolan Date: Sun, 12 Jul 2020 23:52:11 -0400 Subject: [PATCH 33/33] Clean up GPU/headless messaging Signed-off-by: Michael Dolan --- CMakeLists.txt | 65 +++++++++++++++++++++++++------------------------- 1 file changed, 32 insertions(+), 33 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 89c5379763..c7bb84f3a9 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -89,64 +89,63 @@ include(PackageUtils) if(OCIO_BUILD_GPU_TESTS OR OCIO_BUILD_APPS) set(OCIO_GL_ENABLED ON) + set(OCIO_USE_GLVND OFF) + set(OCIO_EGL_HEADLESS OFF) find_package(OpenGL REQUIRED COMPONENTS OpenGL) if(NOT OpenGL_OpenGL_FOUND AND NOT OPENGL_GLU_FOUND) - message(WARNING "OpenGL not found; GPU rendering disabled") + package_root_message(OpenGL) set(OCIO_GL_ENABLED OFF) endif() - # OpenGL_egl_Library is defined iff GLVND is supported (CMake 10+). - if(OPENGL_egl_LIBRARY) - message(STATUS "GLVND supported") - set(OCIO_USE_GLVND ON) - else() - message(STATUS "GLVND not supported; legacy OpenGL libraries used") - set(OCIO_USE_GLVND OFF) - endif() - if(NOT APPLE) - find_package(GLEW QUIET) + find_package(GLEW) if(NOT GLEW_FOUND) - message(WARNING "GLEW not found") + package_root_message(GLEW) set(OCIO_GL_ENABLED OFF) endif() endif() find_package(GLUT) if(NOT GLUT_FOUND) - message(WARNING "GLUT not found") + package_root_message(GLUT) set(OCIO_GL_ENABLED OFF) endif() - set(OCIO_EGL_HEADLESS OFF) - if(${OCIO_USE_HEADLESS}) - if(CMAKE_SYSTEM_NAME STREQUAL Linux) - if(NOT ${OCIO_USE_GLVND}) - message(STATUS "Can't find EGL without GLVND support; can't render headlessly") - set(OCIO_USE_HEADLESS OFF) - set(OCIO_EGL_HEADLESS OFF) - else() - set(OCIO_EGL_HEADLESS ON) - find_package(OpenGL COMPONENTS EGL) - if(NOT OpenGL_EGL_FOUND) - message(WARNING "EGL component missing; can't render headlessly") + if(NOT OCIO_GL_ENABLED) + message(WARNING "GPU rendering disabled") + else() + # OpenGL_egl_Library is defined iff GLVND is supported (CMake 10+). + if(OPENGL_egl_LIBRARY) + message(STATUS "GLVND supported") + set(OCIO_USE_GLVND ON) + else() + message(STATUS "GLVND not supported; legacy OpenGL libraries used") + endif() + + if(OCIO_USE_HEADLESS) + if(CMAKE_SYSTEM_NAME STREQUAL Linux) + if(NOT OCIO_USE_GLVND) + message(STATUS "Can't find EGL without GLVND support; can't render headlessly") set(OCIO_USE_HEADLESS OFF) - set(OCIO_EGL_HEADLESS OFF) else() - add_compile_definitions(OCIO_HEADLESS_ENABLED) + find_package(OpenGL COMPONENTS EGL) + if(NOT OpenGL_EGL_FOUND) + message(WARNING "EGL component missing; can't render headlessly") + set(OCIO_USE_HEADLESS OFF) + else() + add_compile_definitions(OCIO_HEADLESS_ENABLED) + set(OCIO_EGL_HEADLESS ON) + message(STATUS "EGL enabled") + endif() endif() + else() + message(WARNING "OS system is not Linux; can't render headlessly") endif() - else() - message(WARNING "OS system is not Linux; can't render headlessly") - set(OCIO_EGL_HEADLESS OFF) endif() endif() endif() -message(STATUS "GL enabled " ${OCIO_GL_ENABLED}) -message(STATUS "EGL enabled " ${OCIO_EGL_HEADLESS}) - ############################################################################### # Optimization / internal linking preferences