Initial commit 36/53336/3 accepted/tizen/mobile/20151206.223609 accepted/tizen/tv/20151206.223624 accepted/tizen/wearable/20151206.223646 submit/tizen/20151204.070245
authorKyungwook Tak <k.tak@samsung.com>
Mon, 30 Nov 2015 04:51:38 +0000 (13:51 +0900)
committerKyungwook Tak <k.tak@samsung.com>
Fri, 4 Dec 2015 06:01:22 +0000 (15:01 +0900)
Change-Id: Iaf7f316deb8bdb8e705f6f74676e2228ac32c3ee
Signed-off-by: Kyungwook Tak <k.tak@samsung.com>
46 files changed:
.gitignore [new file with mode: 0644]
AUTHORS [new file with mode: 0644]
CMakeLists.txt [new file with mode: 0644]
LICENSE [new file with mode: 0644]
LICENSE.BSD-3-Clause [new file with mode: 0644]
LICENSE.MPL-1.1 [new file with mode: 0644]
packaging/pubkey-pinning.manifest [new file with mode: 0644]
packaging/pubkey-pinning.spec [new file with mode: 0644]
src/CMakeLists.txt [new file with mode: 0644]
src/common/CMakeLists.txt [new file with mode: 0644]
src/common/base/logging.h [new file with mode: 0644]
src/common/base/strings/string16.h [new file with mode: 0644]
src/common/include/tpkp_common.h [new file with mode: 0644]
src/common/include/tpkp_error.h [new file with mode: 0644]
src/common/include/tpkp_logger.h [new file with mode: 0644]
src/common/net/http/transport_security_state.cpp [new file with mode: 0644]
src/common/net/http/transport_security_state.h [new file with mode: 0644]
src/common/net/http/transport_security_state_static.h [new file with mode: 0644]
src/common/src/tpkp_common.cpp [new file with mode: 0644]
src/common/url/third_party/mozilla/url_parse.h [new file with mode: 0644]
src/common/url/url_constants.cc [new file with mode: 0644]
src/common/url/url_constants.h [new file with mode: 0644]
src/common/url/url_export.h [new file with mode: 0644]
src/common/url/url_file.h [new file with mode: 0644]
src/common/url/url_parse.cc [new file with mode: 0644]
src/common/url/url_parse_file.cc [new file with mode: 0644]
src/common/url/url_parse_internal.h [new file with mode: 0644]
src/common/url/url_util.cc [new file with mode: 0644]
src/common/url/url_util.h [new file with mode: 0644]
src/common/url/url_util_internal.h [new file with mode: 0644]
src/curl/CMakeLists.txt [new file with mode: 0644]
src/curl/include/tpkp_curl.h [new file with mode: 0644]
src/curl/tpkp_curl.cpp [new file with mode: 0644]
src/gnutls/CMakeLists.txt [new file with mode: 0644]
src/gnutls/include/tpkp_gnutls.h [new file with mode: 0644]
src/gnutls/tpkp_gnutls.cpp [new file with mode: 0644]
test/CMakeLists.txt [new file with mode: 0644]
test/colors.cpp [new file with mode: 0644]
test/colors.h [new file with mode: 0644]
test/colour_log_formatter.cpp [new file with mode: 0644]
test/colour_log_formatter.h [new file with mode: 0644]
test/curl_test.cpp [new file with mode: 0644]
test/gnutls_test.cpp [new file with mode: 0644]
test/main.cpp [new file with mode: 0644]
tpkp-curl.pc.in [new file with mode: 0644]
tpkp-gnutls.pc.in [new file with mode: 0644]

diff --git a/.gitignore b/.gitignore
new file mode 100644 (file)
index 0000000..44d6a2d
--- /dev/null
@@ -0,0 +1,10 @@
+# cscope/ctag data #
+####################
+/cscope.files
+/cscope.out
+/tags
+
+# Temporary files #
+###################
+*.swp
+*~
diff --git a/AUTHORS b/AUTHORS
new file mode 100644 (file)
index 0000000..f129c9d
--- /dev/null
+++ b/AUTHORS
@@ -0,0 +1 @@
+Kyungwook Tak <k.tak@samsung.com>
diff --git a/CMakeLists.txt b/CMakeLists.txt
new file mode 100644 (file)
index 0000000..18937c3
--- /dev/null
@@ -0,0 +1,69 @@
+# Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
+#
+#    Licensed under the Apache License, Version 2.0 (the "License");
+#    you may not use this file except in compliance with the License.
+#    You may obtain a copy of the License at
+#
+#        http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS,
+#    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#    See the License for the specific language governing permissions and
+#    limitations under the License.
+#
+# @file     CMakeLists.txt
+# @author   Kyungwook Tak (k.tak@samsung.com)
+# @brief    TPKP Project makefile on top
+#
+CMAKE_MINIMUM_REQUIRED(VERSION 2.6)
+PROJECT(pubkey-pinning)
+
+INCLUDE(FindPkgConfig)
+
+STRING(REGEX MATCH "([^.]*)" SO_VERSION "${VERSION}")
+
+# compiler options
+SET(GC_SECTIONS_FLAGS         "-fdata-sections -ffunction-sections -Wl,--gc-sections")
+SET(CMAKE_C_FLAGS             "${CMAKE_C_FLAGS} ${GC_SECTIONS_FLAGS}")
+SET(CMAKE_CXX_FLAGS           "${CMAKE_CXX_FLAGS} ${GC_SECTIONS_FLAGS}")
+SET(CMAKE_C_FLAGS_RELEASE     "-g -O2")
+SET(CMAKE_CXX_FLAGS_RELEASE   "-g -std=c++0x -O2")
+SET(CMAKE_C_FLAGS_DEBUG       "-g -O0 -Wp,-U_FORTIFY_SOURCE")
+SET(CMAKE_CXX_FLAGS_DEBUG     "-g -std=c++0x -O0 -Wp,-U_FORTIFY_SOURCE")
+SET(CMAKE_C_FLAGS_CCOV        "-g -O2 --coverage")
+SET(CMAKE_CXX_FLAGS_CCOV      "-g -std=c++0x -O2 --coverage")
+SET(CMAKE_SHARED_LINKER_FLAGS "-Wl,--as-needed")
+SET(CMAKE_EXE_LINKER_FLAGS    "-Wl,--as-needed")
+SET(CMAKE_SKIP_RPATH          "TRUE")
+
+IF (CMAKE_BUILD_TYPE MATCHES "DEBUG")
+ADD_DEFINITIONS("-DBUILD_TYPE_DEBUG")
+ADD_DEFINITIONS("-DDPL_LOGS_ENABLED")
+ENDIF (CMAKE_BUILD_TYPE MATCHES "DEBUG")
+
+# compiler warning flags
+ADD_DEFINITIONS("-Wall")
+ADD_DEFINITIONS("-Wextra")
+ADD_DEFINITIONS("-Werror")
+
+SET(TARGET_TPKP_COMMON_LIB "tpkp-common")
+SET(TARGET_TPKP_CURL_LIB "tpkp-curl")
+SET(TARGET_TPKP_GNUTLS_LIB "tpkp-gnutls")
+
+CONFIGURE_FILE(tpkp-curl.pc.in tpkp-curl.pc @ONLY)
+CONFIGURE_FILE(tpkp-gnutls.pc.in tpkp-gnutls.pc @ONLY)
+INSTALL(
+       FILES
+               tpkp-curl.pc
+               tpkp-gnutls.pc
+       DESTINATION
+               ${LIB_INSTALL_DIR}/pkgconfig
+       )
+
+ADD_SUBDIRECTORY(src)
+
+IF (DEFINED PUBKEY_PINNING_TEST_BUILD)
+SET(TARGET_TPKP_TEST "tpkp-internal-test")
+ADD_SUBDIRECTORY(test)
+ENDIF (DEFINED PUBKEY_PINNING_TEST_BUILD)
diff --git a/LICENSE b/LICENSE
new file mode 100644 (file)
index 0000000..181359e
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,203 @@
+Copyright (c) 2000 - 2012 Samsung Electronics Co., Ltd. All rights reserved.
+
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
+   APPENDIX: How to apply the Apache License to your work.
+
+      To apply the Apache License to your work, attach the following
+      boilerplate notice, with the fields enclosed by brackets "[]"
+      replaced with your own identifying information. (Don't include
+      the brackets!)  The text should be enclosed in the appropriate
+      comment syntax for the file format. We also recommend that a
+      file or class name and description of purpose be included on the
+      same "printed page" as the copyright notice for easier
+      identification within third-party archives.
+
+   Copyright [yyyy] [name of copyright owner]
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
diff --git a/LICENSE.BSD-3-Clause b/LICENSE.BSD-3-Clause
new file mode 100644 (file)
index 0000000..80341c4
--- /dev/null
@@ -0,0 +1,27 @@
+Copyright 2014 The Chromium Authors. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+   * Redistributions of source code must retain the above copyright
+notice, this list of conditions and the following disclaimer.
+   * Redistributions in binary form must reproduce the above
+copyright notice, this list of conditions and the following disclaimer
+in the documentation and/or other materials provided with the
+distribution.
+   * Neither the name of Google Inc. nor the names of its
+contributors may be used to endorse or promote products derived from
+this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/LICENSE.MPL-1.1 b/LICENSE.MPL-1.1
new file mode 100644 (file)
index 0000000..9b62f1c
--- /dev/null
@@ -0,0 +1,65 @@
+Copyright 2007, Google Inc.
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+    * Redistributions of source code must retain the above copyright
+notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above
+copyright notice, this list of conditions and the following disclaimer
+in the documentation and/or other materials provided with the
+distribution.
+    * Neither the name of Google Inc. nor the names of its
+contributors may be used to endorse or promote products derived from
+this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+-------------------------------------------------------------------------------
+
+The file url_parse.cc is based on nsURLParsers.cc from Mozilla. This file is
+licensed separately as follows:
+
+The contents of this file are subject to the Mozilla Public License Version
+1.1 (the "License"); you may not use this file except in compliance with
+the License. You may obtain a copy of the License at
+http://www.mozilla.org/MPL/
+
+Software distributed under the License is distributed on an "AS IS" basis,
+WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+for the specific language governing rights and limitations under the
+License.
+
+The Original Code is mozilla.org code.
+
+The Initial Developer of the Original Code is
+Netscape Communications Corporation.
+Portions created by the Initial Developer are Copyright (C) 1998
+the Initial Developer. All Rights Reserved.
+
+Contributor(s):
+  Darin Fisher (original author)
+
+Alternatively, the contents of this file may be used under the terms of
+either the GNU General Public License Version 2 or later (the "GPL"), or
+the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+in which case the provisions of the GPL or the LGPL are applicable instead
+of those above. If you wish to allow use of your version of this file only
+under the terms of either the GPL or the LGPL, and not to allow others to
+use your version of this file under the terms of the MPL, indicate your
+decision by deleting the provisions above and replace them with the notice
+and other provisions required by the GPL or the LGPL. If you do not delete
+the provisions above, a recipient may use your version of this file under
+the terms of any one of the MPL, the GPL or the LGPL.
\ No newline at end of file
diff --git a/packaging/pubkey-pinning.manifest b/packaging/pubkey-pinning.manifest
new file mode 100644 (file)
index 0000000..a76fdba
--- /dev/null
@@ -0,0 +1,5 @@
+<manifest>
+       <request>
+               <domain name="_" />
+       </request>
+</manifest>
diff --git a/packaging/pubkey-pinning.spec b/packaging/pubkey-pinning.spec
new file mode 100644 (file)
index 0000000..2a7451d
--- /dev/null
@@ -0,0 +1,95 @@
+%define pubkey_pinning_test_build 0
+
+Name:       pubkey-pinning
+Summary:    Https Public Key Pinning for Tizen platform
+Version:    0.0.1
+Release:    0
+Group:      Security/Libraries
+License:    Apache-2.0 and BSD-3-Clause and MPL-1.1
+Source0:    %name-%version.tar.gz
+Source1:    %name.manifest
+BuildRequires: cmake
+BuildRequires: pkgconfig(glib-2.0)
+BuildRequires: pkgconfig(dlog)
+BuildRequires: pkgconfig(libxml-2.0)
+BuildRequires: pkgconfig(libiri)
+BuildRequires: pkgconfig(libcurl)
+BuildRequires: pkgconfig(gnutls)
+BuildRequires: pkgconfig(openssl)
+
+%description
+Https Public Key Pinning for Tizen platform system framework.
+
+%package devel
+Summary:  Tizen HPKP library development files
+Group:    Development/Libraries
+Requires: %name = %version-%release
+
+%description devel
+Tizen HPKP library development files including headers and
+pkgconfig.
+
+%if 0%{?pubkey_pinning_test_build}
+%package test
+Summary:  Tizen HPKP library internal test
+Group:    Security/Testing
+BuildRequires: boost-devel
+Requires: %name = %version-%release
+
+%description test
+Tizen HPKP library internal test with boost test framework.
+%endif
+
+%prep
+%setup -q
+cp %SOURCE1 .
+
+%build
+export CFLAGS="$CFLAGS -DTIZEN_DEBUG_ENABLE"
+export CXXFLAGS="$CXXFLAGS -DTIZEN_DEBUG_ENABLE"
+export FFLAGS="$FFLAGS -DTIZEN_DEBUG_ENABLE"
+
+export LDFLAGS+="-Wl,--rpath=%_prefix/lib"
+
+
+%{!?build_type:%define build_type "Release"}
+%cmake . -DCMAKE_INSTALL_PREFIX=%_prefix \
+        -DVERSION=%version               \
+        -DINCLUDEDIR=%_includedir        \
+        -DCMAKE_BUILD_TYPE=%build_type   \
+%if 0%{?pubkey_pinning_test_build}
+        -DPUBKEY_PINNING_TEST_BUILD=1    \
+%endif
+        -DCMAKE_VERBOSE_MAKEFILE=ON
+
+make %{?_smp_mflags}
+
+%install
+%make_install
+
+%post -p /sbin/ldconfig
+%postun -p /sbin/ldconfig
+
+%files
+%manifest %name.manifest
+%license LICENSE
+%license LICENSE.BSD-3-Clause
+%license LICENSE.MPL-1.1
+%_libdir/libtpkp-common.so.*
+%_libdir/libtpkp-curl.so.*
+%_libdir/libtpkp-gnutls.so.*
+
+%files devel
+%_includedir/tpkp/common/tpkp_error.h
+%_includedir/tpkp/curl/tpkp_curl.h
+%_includedir/tpkp/gnutls/tpkp_gnutls.h
+%_libdir/pkgconfig/tpkp-curl.pc
+%_libdir/pkgconfig/tpkp-gnutls.pc
+%_libdir/libtpkp-common.so
+%_libdir/libtpkp-curl.so
+%_libdir/libtpkp-gnutls.so
+
+%if 0%{?pubkey_pinning_test_build}
+%files test
+%_bindir/tpkp-internal-test
+%endif
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
new file mode 100644 (file)
index 0000000..ce746d3
--- /dev/null
@@ -0,0 +1,21 @@
+# Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
+#
+#    Licensed under the Apache License, Version 2.0 (the "License");
+#    you may not use this file except in compliance with the License.
+#    You may obtain a copy of the License at
+#
+#        http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS,
+#    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#    See the License for the specific language governing permissions and
+#    limitations under the License.
+#
+# @file     CMakeLists.txt
+# @author   Kyungwook Tak (k.tak@samsung.com)
+# @brief    TPKP lib makefile
+#
+ADD_SUBDIRECTORY(common)
+ADD_SUBDIRECTORY(curl)
+ADD_SUBDIRECTORY(gnutls)
diff --git a/src/common/CMakeLists.txt b/src/common/CMakeLists.txt
new file mode 100644 (file)
index 0000000..6933a6d
--- /dev/null
@@ -0,0 +1,52 @@
+# Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
+#
+#    Licensed under the Apache License, Version 2.0 (the "License");
+#    you may not use this file except in compliance with the License.
+#    You may obtain a copy of the License at
+#
+#        http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS,
+#    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#    See the License for the specific language governing permissions and
+#    limitations under the License.
+#
+# @file     CMakeLists.txt
+# @author   Kyungwook Tak (k.tak@samsung.com)
+# @brief    TPKP common lib makefile
+#
+PKG_CHECK_MODULES(TPKP_COMMON_DEP
+       REQUIRED
+       dlog
+       )
+
+INCLUDE_DIRECTORIES(
+       SYSTEM
+       ${TPKP_COMMON_DEP_INCLUDE_DIRS}
+       .         # common internal headers
+       include # common interface headers
+       )
+
+SET(TPKP_COMMON_SRCS
+       url/url_constants.cc
+       url/url_util.cc
+       url/url_parse.cc
+       url/url_parse_file.cc
+       net/http/transport_security_state.cpp
+       src/tpkp_common.cpp
+       )
+
+ADD_LIBRARY(${TARGET_TPKP_COMMON_LIB} SHARED ${TPKP_COMMON_SRCS})
+
+SET_TARGET_PROPERTIES(${TARGET_TPKP_COMMON_LIB}
+       PROPERTIES
+               COMPILE_FLAGS "-D_GNU_SOURCE -fPIC -fvisibility=hidden"
+               SOVERSION ${SO_VERSION}
+               VERSION ${VERSION}
+       )
+
+TARGET_LINK_LIBRARIES(${TARGET_TPKP_COMMON_LIB} ${TPKP_COMMON_DEP_LIBRARIES})
+
+INSTALL(TARGETS ${TARGET_TPKP_COMMON_LIB} DESTINATION ${LIB_INSTALL_DIR})
+INSTALL(FILES include/tpkp_error.h DESTINATION ${INCLUDEDIR}/tpkp/common)
diff --git a/src/common/base/logging.h b/src/common/base/logging.h
new file mode 100644 (file)
index 0000000..c44e291
--- /dev/null
@@ -0,0 +1,44 @@
+/*
+ * Copyright 2014 The Chromium Authors. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+
+ *    * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *    * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *    * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#pragma once
+
+#include "tpkp_logger.h"
+
+#define DCHECK(condition, format, arg...)  \
+       if(!(condition))         \
+               SLOGE("Check failed: " #condition ". " format, ##arg)
+
+#define DCHECK_LE(arg1, arg2) \
+       if(!((arg1)<=(arg2)))     \
+               SLOGE("Check failed: " #arg1 "<=" #arg2 ".")
+
+#define DCHECK_LT(arg1, arg2) \
+       if(!((arg1)<(arg2)))     \
+               SLOGE("Check failed: " #arg1 "<" #arg2 ".")
diff --git a/src/common/base/strings/string16.h b/src/common/base/strings/string16.h
new file mode 100644 (file)
index 0000000..a24994c
--- /dev/null
@@ -0,0 +1,36 @@
+/*
+ * Copyright 2014 The Chromium Authors. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+
+ *    * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *    * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *    * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#pragma once
+
+namespace base {
+
+typedef wchar_t char16;
+
+}
diff --git a/src/common/include/tpkp_common.h b/src/common/include/tpkp_common.h
new file mode 100644 (file)
index 0000000..a525b49
--- /dev/null
@@ -0,0 +1,115 @@
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ *    Licensed under the Apache License, Version 2.0 (the "License");
+ *    you may not use this file except in compliance with the License.
+ *    You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *    Unless required by applicable law or agreed to in writing, software
+ *    distributed under the License is distributed on an "AS IS" BASIS,
+ *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *    See the License for the specific language governing permissions and
+ *    limitations under the License.
+ */
+/*
+ * @file        tpkp_common.h
+ * @author      Kyungwook Tak (k.tak@samsung.com)
+ * @version     1.0
+ * @brief       Tizen Https Public Key Pinning common library interface.
+ */
+#pragma once
+
+#include <sys/types.h>
+#include <string>
+#include <vector>
+#include <memory>
+#include <sstream>
+#include <type_traits>
+
+#include "tpkp_error.h"
+#include "tpkp_logger.h"
+
+#define EXPORT_API __attribute__((visibility("default")))
+
+namespace TPKP {
+
+enum class HashAlgo : int {
+       SHA1,
+       SHA256, // currently not supported. preloaded public keys were hashed with SHA1
+       COUNT,
+       DEFAULT = SHA1
+};
+
+/* hash size as a byte */
+enum class HashSize : size_t {
+       SHA1 = 20,
+       SHA256 = 32,
+       DEFAULT = SHA1
+};
+
+template<typename E>
+constexpr auto typeCast(E e) -> typename std::underlying_type<E>::type
+{
+       return static_cast<typename std::underlying_type<E>::type>(e);
+}
+
+using RawBuffer = std::vector<unsigned char>;
+
+struct HashValue {
+       HashAlgo algo;
+       RawBuffer hash;
+
+       HashValue() = delete;
+       explicit HashValue(HashAlgo _algo, const RawBuffer &_hash)
+               : algo(_algo)
+               , hash(_hash)
+       {}
+};
+
+using HashValueVector = std::vector<HashValue>;
+
+class EXPORT_API Exception : public std::exception {
+public:
+       explicit Exception(tpkp_e code, const std::string &message);
+       virtual const char *what(void) const noexcept;
+       tpkp_e code(void) const noexcept;
+
+private:
+       tpkp_e m_code;
+       std::string m_message;
+};
+
+EXPORT_API
+tpkp_e ExceptionSafe(const std::function<void()> &func) noexcept;
+
+class EXPORT_API Context {
+public:
+       Context() = delete;
+       virtual ~Context();
+       explicit Context(const std::string &url);
+
+       void addPubkeyHash(HashAlgo algo, const RawBuffer &hashBuf);
+       bool checkPubkeyPins(void);
+       bool hasPins(void);
+
+private:
+       class Impl;
+       std::unique_ptr<Impl> pImpl;
+};
+
+EXPORT_API
+pid_t getThreadId(void);
+
+}
+
+#define TPKP_THROW_EXCEPTION(code, message) \
+do {                                        \
+       std::ostringstream log;                 \
+       log << message;                         \
+       throw TPKP::Exception(code, log.str()); \
+} while(false)
+
+#define TPKP_CHECK_THROW_EXCEPTION(cond, code, message) \
+       if (!(cond)) TPKP_THROW_EXCEPTION(code, message)
diff --git a/src/common/include/tpkp_error.h b/src/common/include/tpkp_error.h
new file mode 100644 (file)
index 0000000..a7149e1
--- /dev/null
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ *    Licensed under the Apache License, Version 2.0 (the "License");
+ *    you may not use this file except in compliance with the License.
+ *    You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *    Unless required by applicable law or agreed to in writing, software
+ *    distributed under the License is distributed on an "AS IS" BASIS,
+ *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *    See the License for the specific language governing permissions and
+ *    limitations under the License.
+ */
+/*
+ * @file        tpkp_error.h
+ * @author      Kyungwook Tak (k.tak@samsung.com)
+ * @version     1.0
+ * @brief       Tizen Https Public Key Pinning error codes.
+ */
+#ifndef TPKP_ERROR_H_
+#define TPKP_ERROR_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef enum {
+       TPKP_E_NONE                    = 0,
+       TPKP_E_MEMORY                  = -1,
+       TPKP_E_INVALID_URL             = -2,
+       TPKP_E_INVALID_CERT            = -3,
+       TPKP_E_FAILED_GET_PUBKEY_HASH  = -4,
+       TPKP_E_NO_URL_DATA             = -5,
+       TPKP_E_INVALID_PEER_CERT_CHAIN = -6,
+       TPKP_E_PUBKEY_MISMATCH         = -7,
+       TPKP_E_STD_EXCEPTION           = -99,
+       TPKP_E_INTERNAL                = -100
+} tpkp_e;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* TPKP_ERROR_H_ */
diff --git a/src/common/include/tpkp_logger.h b/src/common/include/tpkp_logger.h
new file mode 100644 (file)
index 0000000..0a148c9
--- /dev/null
@@ -0,0 +1,29 @@
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ *    Licensed under the Apache License, Version 2.0 (the "License");
+ *    you may not use this file except in compliance with the License.
+ *    You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *    Unless required by applicable law or agreed to in writing, software
+ *    distributed under the License is distributed on an "AS IS" BASIS,
+ *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *    See the License for the specific language governing permissions and
+ *    limitations under the License.
+ */
+/*
+ * @file        tpkp_logger.h
+ * @author      Kyungwook Tak (k.tak@samsung.com)
+ * @version     1.0
+ * @brief       Tizen Https Public Key Pinning dlog wrapper.
+ */
+#pragma once
+
+#ifdef LOG_TAG
+#undef LOG_TAG
+#endif
+#define LOG_TAG "TPKP"
+
+#include <dlog.h>
diff --git a/src/common/net/http/transport_security_state.cpp b/src/common/net/http/transport_security_state.cpp
new file mode 100644 (file)
index 0000000..605b274
--- /dev/null
@@ -0,0 +1,370 @@
+/*
+ * Copyright 2014 The Chromium Authors. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+
+ *    * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *    * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *    * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+// This file is subset of chromium-efl/net/http/transport_security_state.cc
+
+#include "net/http/transport_security_state.h"
+#include "net/http/transport_security_state_static.h"
+#include "base/logging.h"
+
+namespace {
+
+// BitReader is a class that allows a bytestring to be read bit-by-bit.
+class BitReader {
+ public:
+  BitReader(const uint8* bytes, size_t num_bits)
+      : bytes_(bytes),
+        num_bits_(num_bits),
+        num_bytes_((num_bits + 7) / 8),
+        current_byte_index_(0),
+        num_bits_used_(8) {}
+
+  // Next sets |*out| to the next bit from the input. It returns false if no
+  // more bits are available or true otherwise.
+  bool Next(bool* out) {
+    if (num_bits_used_ == 8) {
+      if (current_byte_index_ >= num_bytes_) {
+        return false;
+      }
+      current_byte_ = bytes_[current_byte_index_++];
+      num_bits_used_ = 0;
+    }
+
+    *out = 1 & (current_byte_ >> (7 - num_bits_used_));
+    num_bits_used_++;
+    return true;
+  }
+
+  // Read sets the |num_bits| least-significant bits of |*out| to the value of
+  // the next |num_bits| bits from the input. It returns false if there are
+  // insufficient bits in the input or true otherwise.
+  bool Read(unsigned num_bits, uint32* out) {
+    DCHECK_LE(num_bits, 32u);
+
+    uint32 ret = 0;
+    for (unsigned i = 0; i < num_bits; ++i) {
+      bool bit;
+      if (!Next(&bit)) {
+        return false;
+      }
+      ret |= static_cast<uint32>(bit) << (num_bits - 1 - i);
+    }
+
+    *out = ret;
+    return true;
+  }
+
+  // Unary sets |*out| to the result of decoding a unary value from the input.
+  // It returns false if there were insufficient bits in the input and true
+  // otherwise.
+  bool Unary(size_t* out) {
+    size_t ret = 0;
+
+    for (;;) {
+      bool bit;
+      if (!Next(&bit)) {
+        return false;
+      }
+      if (!bit) {
+        break;
+      }
+      ret++;
+    }
+
+    *out = ret;
+    return true;
+  }
+
+  // Seek sets the current offest in the input to bit number |offset|. It
+  // returns true if |offset| is within the range of the input and false
+  // otherwise.
+  bool Seek(size_t offset) {
+    if (offset >= num_bits_) {
+      return false;
+    }
+    current_byte_index_ = offset / 8;
+    current_byte_ = bytes_[current_byte_index_++];
+    num_bits_used_ = offset % 8;
+    return true;
+  }
+
+ private:
+  const uint8* const bytes_;
+  const size_t num_bits_;
+  const size_t num_bytes_;
+  // current_byte_index_ contains the current byte offset in |bytes_|.
+  size_t current_byte_index_;
+  // current_byte_ contains the current byte of the input.
+  uint8 current_byte_;
+  // num_bits_used_ contains the number of bits of |current_byte_| that have
+  // been read.
+  unsigned num_bits_used_;
+};
+
+// HuffmanDecoder is a very simple Huffman reader. The input Huffman tree is
+// simply encoded as a series of two-byte structures. The first byte determines
+// the "0" pointer for that node and the second the "1" pointer. Each byte
+// either has the MSB set, in which case the bottom 7 bits are the value for
+// that position, or else the bottom seven bits contain the index of a node.
+//
+// The tree is decoded by walking rather than a table-driven approach.
+class HuffmanDecoder {
+ public:
+  HuffmanDecoder(const uint8* tree, size_t tree_bytes)
+      : tree_(tree),
+        tree_bytes_(tree_bytes) {}
+
+  bool Decode(BitReader* reader, char* out) {
+    const uint8* current = &tree_[tree_bytes_-2];
+
+    for (;;) {
+      bool bit;
+      if (!reader->Next(&bit)) {
+        return false;
+      }
+
+      uint8 b = current[bit];
+      if (b & 0x80) {
+        *out = static_cast<char>(b & 0x7f);
+        return true;
+      }
+
+      unsigned offset = static_cast<unsigned>(b) * 2;
+      DCHECK_LT(offset, tree_bytes_);
+      if (offset >= tree_bytes_) {
+        return false;
+      }
+
+      current = &tree_[offset];
+    }
+  }
+
+ private:
+  const uint8* const tree_;
+  const size_t tree_bytes_;
+};
+
+} // namespace anonymous
+
+namespace net {
+
+// DecodeHSTSPreloadRaw resolves |hostname| in the preloaded data. It returns
+// false on internal error and true otherwise. After a successful return,
+// |*out_found| is true iff a relevant entry has been found. If so, |*out|
+// contains the details.
+//
+// Don't call this function, call DecodeHSTSPreload, below.
+//
+// Although this code should be robust, it never processes attacker-controlled
+// data -- it only operates on the preloaded data built into the binary.
+//
+// The preloaded data is represented as a trie and matches the hostname
+// backwards. Each node in the trie starts with a number of characters, which
+// must match exactly. After that is a dispatch table which maps the next
+// character in the hostname to another node in the trie.
+//
+// In the dispatch table, the zero character represents the "end of string"
+// (which is the *beginning* of a hostname since we process it backwards). The
+// value in that case is special -- rather than an offset to another trie node,
+// it contains the HSTS information: whether subdomains are included, pinsets
+// etc. If an "end of string" matches a period in the hostname then the
+// information is remembered because, if no more specific node is found, then
+// that information applies to the hostname.
+//
+// Dispatch tables are always given in order, but the "end of string" (zero)
+// value always comes before an entry for '.'.
+bool DecodeHSTSPreloadRaw(const std::string& hostname,
+                          bool* out_found,
+                          PreloadResult* out) {
+  HuffmanDecoder huffman(kHSTSHuffmanTree, sizeof(kHSTSHuffmanTree));
+  BitReader reader(kPreloadedHSTSData, kPreloadedHSTSBits);
+  size_t bit_offset = kHSTSRootPosition;
+  static const char kEndOfString = 0;
+  static const char kEndOfTable = 127;
+
+  *out_found = false;
+
+  if (hostname.empty()) {
+    return true;
+  }
+  // hostname_offset contains one more than the index of the current character
+  // in the hostname that is being considered. It's one greater so that we can
+  // represent the position just before the beginning (with zero).
+  size_t hostname_offset = hostname.size();
+
+  for (;;) {
+    // Seek to the desired location.
+    if (!reader.Seek(bit_offset)) {
+      return false;
+    }
+
+    // Decode the unary length of the common prefix.
+    size_t prefix_length;
+    if (!reader.Unary(&prefix_length)) {
+      return false;
+    }
+
+    // Match each character in the prefix.
+    for (size_t i = 0; i < prefix_length; ++i) {
+      if (hostname_offset == 0) {
+        // We can't match the terminator with a prefix string.
+        return true;
+      }
+
+      char c;
+      if (!huffman.Decode(&reader, &c)) {
+        return false;
+      }
+      if (hostname[hostname_offset - 1] != c) {
+        return true;
+      }
+      hostname_offset--;
+    }
+
+    bool is_first_offset = true;
+    size_t current_offset = 0;
+
+    // Next is the dispatch table.
+    for (;;) {
+      char c;
+      if (!huffman.Decode(&reader, &c)) {
+        return false;
+      }
+      if (c == kEndOfTable) {
+        // No exact match.
+        return true;
+      }
+
+      if (c == kEndOfString) {
+        PreloadResult tmp;
+        if (!reader.Next(&tmp.sts_include_subdomains) ||
+            !reader.Next(&tmp.force_https) ||
+            !reader.Next(&tmp.has_pins)) {
+          return false;
+        }
+
+        tmp.pkp_include_subdomains = tmp.sts_include_subdomains;
+
+        if (tmp.has_pins) {
+          if (!reader.Read(4, &tmp.pinset_id) ||
+              !reader.Read(9, &tmp.domain_id) ||
+              (!tmp.sts_include_subdomains &&
+               !reader.Next(&tmp.pkp_include_subdomains))) {
+            return false;
+          }
+        }
+
+        tmp.hostname_offset = hostname_offset;
+
+        if (hostname_offset == 0 || hostname[hostname_offset - 1] == '.') {
+          *out_found =
+              tmp.sts_include_subdomains || tmp.pkp_include_subdomains;
+          *out = tmp;
+
+          if (hostname_offset > 0) {
+            out->force_https &= tmp.sts_include_subdomains;
+          } else {
+            *out_found = true;
+            return true;
+          }
+        }
+
+        continue;
+      }
+
+      // The entries in a dispatch table are in order thus we can tell if there
+      // will be no match if the current character past the one that we want.
+      if (hostname_offset == 0 || hostname[hostname_offset-1] < c) {
+        return true;
+      }
+
+      if (is_first_offset) {
+        // The first offset is backwards from the current position.
+        uint32 jump_delta_bits;
+        uint32 jump_delta;
+        if (!reader.Read(5, &jump_delta_bits) ||
+            !reader.Read(jump_delta_bits, &jump_delta)) {
+          return false;
+        }
+
+        if (bit_offset < jump_delta) {
+          return false;
+        }
+
+        current_offset = bit_offset - jump_delta;
+        is_first_offset = false;
+      } else {
+        // Subsequent offsets are forward from the target of the first offset.
+        uint32 is_long_jump;
+        if (!reader.Read(1, &is_long_jump)) {
+          return false;
+        }
+
+        uint32 jump_delta;
+        if (!is_long_jump) {
+          if (!reader.Read(7, &jump_delta)) {
+            return false;
+          }
+        } else {
+          uint32 jump_delta_bits;
+          if (!reader.Read(4, &jump_delta_bits) ||
+              !reader.Read(jump_delta_bits + 8, &jump_delta)) {
+            return false;
+          }
+        }
+
+        current_offset += jump_delta;
+        if (current_offset >= bit_offset) {
+          return false;
+        }
+      }
+
+      DCHECK_LT(0u, hostname_offset);
+      if (hostname[hostname_offset - 1] == c) {
+        bit_offset = current_offset;
+        hostname_offset--;
+        break;
+      }
+    }
+  }
+}
+
+bool DecodeHSTSPreload(const std::string& hostname, PreloadResult* out)
+{
+  bool found;
+  if (!DecodeHSTSPreloadRaw(hostname, &found, out)) {
+    DCHECK(false, "Internal error in DecodeHSTSPreloadRaw for hostname %s", hostname.c_str());
+    return false;
+  }
+
+  return found;
+}
+
+} // namespace TPKP
diff --git a/src/common/net/http/transport_security_state.h b/src/common/net/http/transport_security_state.h
new file mode 100644 (file)
index 0000000..4344f9c
--- /dev/null
@@ -0,0 +1,58 @@
+/*
+ * Copyright 2014 The Chromium Authors. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+
+ *    * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *    * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *    * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+// This file is subset of chromium-efl/net/http/transport_security_state.cc
+#pragma once
+
+#include  <cstddef>
+#include  <string>
+
+#define uint8  unsigned char
+#define uint32 unsigned int
+
+namespace net {
+
+// PreloadResult is the result of resolving a specific name in the preloaded
+// data.
+struct PreloadResult {
+  uint32 pinset_id;
+  uint32 domain_id;
+  // hostname_offset contains the number of bytes from the start of the given
+  // hostname where the name of the matching entry starts.
+  size_t hostname_offset;
+  bool sts_include_subdomains;
+  bool pkp_include_subdomains;
+  bool force_https;
+  bool has_pins;
+};
+
+bool DecodeHSTSPreload(const std::string &hostname, PreloadResult *out);
+
+}
diff --git a/src/common/net/http/transport_security_state_static.h b/src/common/net/http/transport_security_state_static.h
new file mode 100644 (file)
index 0000000..f4fbbfc
--- /dev/null
@@ -0,0 +1,2074 @@
+/*
+ * Copyright 2014 The Chromium Authors. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+
+ *    * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *    * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *    * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+// This file is automatically generated by transport_security_state_static_generate.go.
+// You can find it at https://github.com/agl/transport-security-state-generate.
+
+#pragma once
+
+enum SecondLevelDomainName {
+  DOMAIN_NOT_PINNED,
+  DOMAIN_GOOGLE_COM,
+  DOMAIN_ANDROID_COM,
+  DOMAIN_GOOGLE_ANALYTICS_COM,
+  DOMAIN_GOOGLEPLEX_COM,
+  DOMAIN_YTIMG_COM,
+  DOMAIN_GOOGLEUSERCONTENT_COM,
+  DOMAIN_YOUTUBE_COM,
+  DOMAIN_GOOGLEAPIS_COM,
+  DOMAIN_GOOGLEADSERVICES_COM,
+  DOMAIN_GOOGLECODE_COM,
+  DOMAIN_APPSPOT_COM,
+  DOMAIN_GOOGLESYNDICATION_COM,
+  DOMAIN_DOUBLECLICK_NET,
+  DOMAIN_GSTATIC_COM,
+  DOMAIN_GMAIL_COM,
+  DOMAIN_GOOGLEMAIL_COM,
+  DOMAIN_GOOGLEGROUPS_COM,
+  DOMAIN_TORPROJECT_ORG,
+  DOMAIN_TWITTER_COM,
+  DOMAIN_TWIMG_COM,
+  DOMAIN_AKAMAIHD_NET,
+  DOMAIN_TOR2WEB_ORG,
+  DOMAIN_YOUTU_BE,
+  DOMAIN_GOOGLECOMMERCE_COM,
+  DOMAIN_URCHIN_COM,
+  DOMAIN_GOO_GL,
+  DOMAIN_G_CO,
+  DOMAIN_GOOGLE_AC,
+  DOMAIN_GOOGLE_AD,
+  DOMAIN_GOOGLE_AE,
+  DOMAIN_GOOGLE_AF,
+  DOMAIN_GOOGLE_AG,
+  DOMAIN_GOOGLE_AM,
+  DOMAIN_GOOGLE_AS,
+  DOMAIN_GOOGLE_AT,
+  DOMAIN_GOOGLE_AZ,
+  DOMAIN_GOOGLE_BA,
+  DOMAIN_GOOGLE_BE,
+  DOMAIN_GOOGLE_BF,
+  DOMAIN_GOOGLE_BG,
+  DOMAIN_GOOGLE_BI,
+  DOMAIN_GOOGLE_BJ,
+  DOMAIN_GOOGLE_BS,
+  DOMAIN_GOOGLE_BY,
+  DOMAIN_GOOGLE_CA,
+  DOMAIN_GOOGLE_CAT,
+  DOMAIN_GOOGLE_CC,
+  DOMAIN_GOOGLE_CD,
+  DOMAIN_GOOGLE_CF,
+  DOMAIN_GOOGLE_CG,
+  DOMAIN_GOOGLE_CH,
+  DOMAIN_GOOGLE_CI,
+  DOMAIN_GOOGLE_CL,
+  DOMAIN_GOOGLE_CM,
+  DOMAIN_GOOGLE_CN,
+  DOMAIN_CO_AO,
+  DOMAIN_CO_BW,
+  DOMAIN_CO_CK,
+  DOMAIN_CO_CR,
+  DOMAIN_CO_HU,
+  DOMAIN_CO_ID,
+  DOMAIN_CO_IL,
+  DOMAIN_CO_IM,
+  DOMAIN_CO_IN,
+  DOMAIN_CO_JE,
+  DOMAIN_CO_JP,
+  DOMAIN_CO_KE,
+  DOMAIN_CO_KR,
+  DOMAIN_CO_LS,
+  DOMAIN_CO_MA,
+  DOMAIN_CO_MZ,
+  DOMAIN_CO_NZ,
+  DOMAIN_CO_TH,
+  DOMAIN_CO_TZ,
+  DOMAIN_CO_UG,
+  DOMAIN_CO_UK,
+  DOMAIN_CO_UZ,
+  DOMAIN_CO_VE,
+  DOMAIN_CO_VI,
+  DOMAIN_CO_ZA,
+  DOMAIN_CO_ZM,
+  DOMAIN_CO_ZW,
+  DOMAIN_COM_AF,
+  DOMAIN_COM_AG,
+  DOMAIN_COM_AI,
+  DOMAIN_COM_AR,
+  DOMAIN_COM_AU,
+  DOMAIN_COM_BD,
+  DOMAIN_COM_BH,
+  DOMAIN_COM_BN,
+  DOMAIN_COM_BO,
+  DOMAIN_COM_BR,
+  DOMAIN_COM_BY,
+  DOMAIN_COM_BZ,
+  DOMAIN_COM_CN,
+  DOMAIN_COM_CO,
+  DOMAIN_COM_CU,
+  DOMAIN_COM_CY,
+  DOMAIN_COM_DO,
+  DOMAIN_COM_EC,
+  DOMAIN_COM_EG,
+  DOMAIN_COM_ET,
+  DOMAIN_COM_FJ,
+  DOMAIN_COM_GE,
+  DOMAIN_COM_GH,
+  DOMAIN_COM_GI,
+  DOMAIN_COM_GR,
+  DOMAIN_COM_GT,
+  DOMAIN_COM_HK,
+  DOMAIN_COM_IQ,
+  DOMAIN_COM_JM,
+  DOMAIN_COM_JO,
+  DOMAIN_COM_KH,
+  DOMAIN_COM_KW,
+  DOMAIN_COM_LB,
+  DOMAIN_COM_LY,
+  DOMAIN_COM_MT,
+  DOMAIN_COM_MX,
+  DOMAIN_COM_MY,
+  DOMAIN_COM_NA,
+  DOMAIN_COM_NF,
+  DOMAIN_COM_NG,
+  DOMAIN_COM_NI,
+  DOMAIN_COM_NP,
+  DOMAIN_COM_NR,
+  DOMAIN_COM_OM,
+  DOMAIN_COM_PA,
+  DOMAIN_COM_PE,
+  DOMAIN_COM_PH,
+  DOMAIN_COM_PK,
+  DOMAIN_COM_PL,
+  DOMAIN_COM_PR,
+  DOMAIN_COM_PY,
+  DOMAIN_COM_QA,
+  DOMAIN_COM_RU,
+  DOMAIN_COM_SA,
+  DOMAIN_COM_SB,
+  DOMAIN_COM_SG,
+  DOMAIN_COM_SL,
+  DOMAIN_COM_SV,
+  DOMAIN_COM_TJ,
+  DOMAIN_COM_TN,
+  DOMAIN_COM_TR,
+  DOMAIN_COM_TW,
+  DOMAIN_COM_UA,
+  DOMAIN_COM_UY,
+  DOMAIN_COM_VC,
+  DOMAIN_COM_VE,
+  DOMAIN_COM_VN,
+  DOMAIN_GOOGLE_CV,
+  DOMAIN_GOOGLE_CZ,
+  DOMAIN_GOOGLE_DE,
+  DOMAIN_GOOGLE_DJ,
+  DOMAIN_GOOGLE_DK,
+  DOMAIN_GOOGLE_DM,
+  DOMAIN_GOOGLE_DZ,
+  DOMAIN_GOOGLE_EE,
+  DOMAIN_GOOGLE_ES,
+  DOMAIN_GOOGLE_FI,
+  DOMAIN_GOOGLE_FM,
+  DOMAIN_GOOGLE_FR,
+  DOMAIN_GOOGLE_GA,
+  DOMAIN_GOOGLE_GE,
+  DOMAIN_GOOGLE_GG,
+  DOMAIN_GOOGLE_GL,
+  DOMAIN_GOOGLE_GM,
+  DOMAIN_GOOGLE_GP,
+  DOMAIN_GOOGLE_GR,
+  DOMAIN_GOOGLE_GY,
+  DOMAIN_GOOGLE_HK,
+  DOMAIN_GOOGLE_HN,
+  DOMAIN_GOOGLE_HR,
+  DOMAIN_GOOGLE_HT,
+  DOMAIN_GOOGLE_HU,
+  DOMAIN_GOOGLE_IE,
+  DOMAIN_GOOGLE_IM,
+  DOMAIN_GOOGLE_INFO,
+  DOMAIN_GOOGLE_IQ,
+  DOMAIN_GOOGLE_IS,
+  DOMAIN_GOOGLE_IT,
+  DOMAIN_IT_AO,
+  DOMAIN_GOOGLE_JE,
+  DOMAIN_GOOGLE_JO,
+  DOMAIN_GOOGLE_JOBS,
+  DOMAIN_GOOGLE_JP,
+  DOMAIN_GOOGLE_KG,
+  DOMAIN_GOOGLE_KI,
+  DOMAIN_GOOGLE_KZ,
+  DOMAIN_GOOGLE_LA,
+  DOMAIN_GOOGLE_LI,
+  DOMAIN_GOOGLE_LK,
+  DOMAIN_GOOGLE_LT,
+  DOMAIN_GOOGLE_LU,
+  DOMAIN_GOOGLE_LV,
+  DOMAIN_GOOGLE_MD,
+  DOMAIN_GOOGLE_ME,
+  DOMAIN_GOOGLE_MG,
+  DOMAIN_GOOGLE_MK,
+  DOMAIN_GOOGLE_ML,
+  DOMAIN_GOOGLE_MN,
+  DOMAIN_GOOGLE_MS,
+  DOMAIN_GOOGLE_MU,
+  DOMAIN_GOOGLE_MV,
+  DOMAIN_GOOGLE_MW,
+  DOMAIN_GOOGLE_NE,
+  DOMAIN_NE_JP,
+  DOMAIN_GOOGLE_NET,
+  DOMAIN_GOOGLE_NL,
+  DOMAIN_GOOGLE_NO,
+  DOMAIN_GOOGLE_NR,
+  DOMAIN_GOOGLE_NU,
+  DOMAIN_OFF_AI,
+  DOMAIN_GOOGLE_PK,
+  DOMAIN_GOOGLE_PL,
+  DOMAIN_GOOGLE_PN,
+  DOMAIN_GOOGLE_PS,
+  DOMAIN_GOOGLE_PT,
+  DOMAIN_GOOGLE_RO,
+  DOMAIN_GOOGLE_RS,
+  DOMAIN_GOOGLE_RU,
+  DOMAIN_GOOGLE_RW,
+  DOMAIN_GOOGLE_SC,
+  DOMAIN_GOOGLE_SE,
+  DOMAIN_GOOGLE_SH,
+  DOMAIN_GOOGLE_SI,
+  DOMAIN_GOOGLE_SK,
+  DOMAIN_GOOGLE_SM,
+  DOMAIN_GOOGLE_SN,
+  DOMAIN_GOOGLE_SO,
+  DOMAIN_GOOGLE_ST,
+  DOMAIN_GOOGLE_TD,
+  DOMAIN_GOOGLE_TG,
+  DOMAIN_GOOGLE_TK,
+  DOMAIN_GOOGLE_TL,
+  DOMAIN_GOOGLE_TM,
+  DOMAIN_GOOGLE_TN,
+  DOMAIN_GOOGLE_TO,
+  DOMAIN_GOOGLE_TP,
+  DOMAIN_GOOGLE_TT,
+  DOMAIN_GOOGLE_US,
+  DOMAIN_GOOGLE_UZ,
+  DOMAIN_GOOGLE_VG,
+  DOMAIN_GOOGLE_VU,
+  DOMAIN_GOOGLE_WS,
+  DOMAIN_CHROMIUM_ORG,
+  DOMAIN_CRYPTO_CAT,
+  DOMAIN_LAVABIT_COM,
+  DOMAIN_GOOGLETAGMANAGER_COM,
+  DOMAIN_GOOGLETAGSERVICES_COM,
+  DOMAIN_DROPBOX_COM,
+  DOMAIN_YOUTUBE_NOCOOKIE_COM,
+  DOMAIN_2MDN_NET,
+  DOMAIN_FACEBOOK_COM,
+  DOMAIN_SPIDEROAK_COM,
+  DOMAIN_BLOGGER_COM,
+  DOMAIN_CHROME_COM,
+  // Boundary value for UMA_HISTOGRAM_ENUMERATION.
+  DOMAIN_NUM_EVENTS,
+};
+
+// These are SubjectPublicKeyInfo hashes for public key pinning. The
+// hashes are SHA1 digests.
+
+static const char kSPKIHash_TestSPKI[] =
+    "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+    "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00";
+
+static const char kSPKIHash_VeriSignClass3[] =
+    "\xe2\x7f\x7b\xd8\x77\xd5\xdf\x9e\x0a\x3f"
+    "\x9e\xb4\xcb\x0e\x2e\xa9\xef\xdb\x69\x77";
+
+static const char kSPKIHash_VeriSignClass3_G3[] =
+    "\x22\xf1\x9e\x2e\xc6\xea\xcc\xfc\x5d\x23"
+    "\x46\xf4\xc2\xe8\xf6\xc5\x54\xdd\x5e\x07";
+
+static const char kSPKIHash_GoogleBackup2048[] =
+    "\xbe\xae\xce\xca\x34\xa7\xa8\xe7\x28\xf6"
+    "\x7c\x8c\x08\x31\x9d\xcb\xbe\xde\x8a\x33";
+
+static const char kSPKIHash_GoogleG2[] =
+    "\x43\xda\xd6\x30\xee\x53\xf8\xa9\x80\xca"
+    "\x6e\xfd\x85\xf4\x6a\xa3\x79\x90\xe0\xea";
+
+static const char kSPKIHash_GeoTrustGlobal[] =
+    "\xc0\x7a\x98\x68\x8d\x89\xfb\xab\x05\x64"
+    "\x0c\x11\x7d\xaa\x7d\x65\xb8\xca\xcc\x4e";
+
+static const char kSPKIHash_GeoTrustPrimary[] =
+    "\xb0\x19\x89\xe7\xef\xfb\x4a\xaf\xcb\x14"
+    "\x8f\x58\x46\x39\x76\x22\x41\x50\xe1\xba";
+
+static const char kSPKIHash_RapidSSL[] =
+    "\xa3\x93\x99\xc4\x04\xc3\xb2\x09\xb0\x81"
+    "\xc2\x1f\x21\x62\x27\x78\xc2\x74\x8e\x4c";
+
+static const char kSPKIHash_DigiCertEVRoot[] =
+    "\x83\x31\x7e\x62\x85\x42\x53\xd6\xd7\x78"
+    "\x31\x90\xec\x91\x90\x56\xe9\x91\xb9\xe3";
+
+static const char kSPKIHash_DigiCertAssuredIDRoot[] =
+    "\x68\x33\x0e\x61\x35\x85\x21\x59\x29\x83"
+    "\xa3\xc8\xd2\xd2\xe1\x40\x6e\x7a\xb3\xc1";
+
+static const char kSPKIHash_DigiCertGlobalRoot[] =
+    "\xd5\x2e\x13\xc1\xab\xe3\x49\xda\xe8\xb4"
+    "\x95\x94\xef\x7c\x38\x43\x60\x64\x66\xbd";
+
+static const char kSPKIHash_Tor1[] =
+    "\x8e\xe3\x71\x49\x3b\xfd\x50\x03\x66\xa4"
+    "\x2f\x64\x17\x91\x8a\xa6\x65\x8d\xc7\x76";
+
+static const char kSPKIHash_Tor2[] =
+    "\x96\x26\xb8\xde\x53\xe8\x97\x34\x8f\x54"
+    "\x8a\xb7\xe0\x3c\x39\xee\xe6\x1c\x2c\x3f";
+
+static const char kSPKIHash_Tor3[] =
+    "\xaf\x31\x32\x40\x82\x8e\x87\xbe\xe3\xf3"
+    "\xb9\xf9\x6e\x35\x94\x36\x0b\x97\x17\xc6";
+
+static const char kSPKIHash_VeriSignClass1[] =
+    "\x23\x43\xd1\x48\xa2\x55\x89\x9b\x94\x7d"
+    "\x46\x1a\x79\x7e\xc0\x4c\xfe\xd1\x70\xb7";
+
+static const char kSPKIHash_VeriSignClass3_G4[] =
+    "\xed\x66\x31\x35\xd3\x1b\xd4\xec\xa6\x14"
+    "\xc4\x29\xe3\x19\x06\x9f\x94\xc1\x26\x50";
+
+static const char kSPKIHash_VeriSignClass4_G3[] =
+    "\x3c\x03\x43\x68\x68\x95\x1c\xf3\x69\x2a"
+    "\xb8\xb4\x26\xda\xba\x8f\xe9\x22\xe5\xbd";
+
+static const char kSPKIHash_VeriSignClass1_G3[] =
+    "\x55\x19\xb2\x78\xac\xb2\x81\xd7\xed\xa7"
+    "\xab\xc1\x83\x99\xc3\xbb\x69\x04\x24\xb5";
+
+static const char kSPKIHash_VeriSignClass2_G3[] =
+    "\x5a\xbe\xc5\x75\xdc\xae\xf3\xb0\x8e\x27"
+    "\x19\x43\xfc\x7f\x25\x0c\x3d\xf6\x61\xe3";
+
+static const char kSPKIHash_VeriSignClass3_G2[] =
+    "\x1a\x21\xb4\x95\x2b\x62\x93\xce\x18\xb3"
+    "\x65\xec\x9c\x0e\x93\x4c\xb3\x81\xe6\xd4";
+
+static const char kSPKIHash_VeriSignClass2_G2[] =
+    "\x12\x37\xba\x45\x17\xee\xad\x29\x26\xfd"
+    "\xc1\xcd\xfe\xbe\xed\xf2\xde\xd9\x14\x5c";
+
+static const char kSPKIHash_VeriSignClass3_G5[] =
+    "\xb1\x81\x08\x1a\x19\xa4\xc0\x94\x1f\xfa"
+    "\xe8\x95\x28\xc1\x24\xc9\x9b\x34\xac\xc7";
+
+static const char kSPKIHash_VeriSignUniversal[] =
+    "\xbb\xc2\x3e\x29\x0b\xb3\x28\x77\x1d\xad"
+    "\x3e\xa2\x4d\xbd\xf4\x23\xbd\x06\xb0\x3d";
+
+static const char kSPKIHash_Twitter1[] =
+    "\x56\xfe\xf3\xc2\x14\x7d\x4e\xd3\x88\x37"
+    "\xfd\xbd\x30\x52\x38\x72\x01\xe5\x77\x8d";
+
+static const char kSPKIHash_GeoTrustGlobal2[] =
+    "\x71\x38\x36\xf2\x02\x31\x53\x47\x2b\x6e"
+    "\xba\x65\x46\xa9\x10\x15\x58\x20\x05\x09";
+
+static const char kSPKIHash_GeoTrustUniversal[] =
+    "\x87\xe8\x5b\x63\x53\xc6\x23\xa3\x12\x8c"
+    "\xb0\xff\xbb\xf5\x51\xfe\x59\x80\x0e\x22";
+
+static const char kSPKIHash_GeoTrustUniversal2[] =
+    "\x5e\x4f\x53\x86\x85\xdd\x4f\x9e\xca\x5f"
+    "\xdc\x0d\x45\x6f\x7d\x51\xb1\xdc\x9b\x7b";
+
+static const char kSPKIHash_GeoTrustPrimary_G2[] =
+    "\xbd\xbe\xa7\x1b\xab\x71\x57\xf9\xe4\x75"
+    "\xd9\x54\xd2\xb7\x27\x80\x1a\x82\x26\x82";
+
+static const char kSPKIHash_GeoTrustPrimary_G3[] =
+    "\x9c\xa9\x8d\x00\xaf\x74\x0d\xdd\x81\x80"
+    "\xd2\x13\x45\xa5\x8b\x8f\x2e\x94\x38\xd6";
+
+static const char kSPKIHash_Entrust_2048[] =
+    "\x55\xe4\x81\xd1\x11\x80\xbe\xd8\x89\xb9"
+    "\x08\xa3\x31\xf9\xa1\x24\x09\x16\xb9\x70";
+
+static const char kSPKIHash_Entrust_EV[] =
+    "\xba\x42\xb0\x81\x88\x53\x88\x1d\x86\x63"
+    "\xbd\x4c\xc0\x5e\x08\xfe\xea\x6e\xbb\x77";
+
+static const char kSPKIHash_Entrust_G2[] =
+    "\xab\x30\xd3\xaf\x4b\xd8\xf1\x6b\x58\x69"
+    "\xee\x45\x69\x29\xda\x84\xb8\x73\x94\x88";
+
+static const char kSPKIHash_Entrust_SSL[] =
+    "\xf0\x17\x62\x13\x55\x3d\xb3\xff\x0a\x00"
+    "\x6b\xfb\x50\x84\x97\xf3\xed\x62\xd0\x1a";
+
+static const char kSPKIHash_AAACertificateServices[] =
+    "\xc4\x30\x28\xc5\xd3\xe3\x08\x0c\x10\x44"
+    "\x8b\x2c\x77\xba\x24\x53\x97\x60\xbb\xf9";
+
+static const char kSPKIHash_AddTrustClass1CARoot[] =
+    "\x8b\xdb\xd7\xcc\xa0\x68\x53\x42\x16\xf4"
+    "\xc1\x2b\x25\x44\xfc\x02\x9c\xa5\x8b\x47";
+
+static const char kSPKIHash_AddTrustExternalCARoot[] =
+    "\x4f\x9c\x7d\x21\x79\x9c\xad\x0e\xd8\xb9"
+    "\x0c\x57\x9f\x1a\x02\x99\xe7\x90\xf3\x87";
+
+static const char kSPKIHash_AddTrustPublicCARoot[] =
+    "\xa8\x57\x65\xd6\xe8\x32\xc8\xc5\x19\x63"
+    "\x73\x5a\x9a\x17\x74\x3a\x81\xdf\xee\x2e";
+
+static const char kSPKIHash_AddTrustQualifiedCARoot[] =
+    "\xbc\xe4\xb7\x23\x12\x55\x98\xe5\x63\x41"
+    "\x19\x1c\x50\xe4\xb6\x47\xc2\x76\x05\xd7";
+
+static const char kSPKIHash_COMODOCertificationAuthority[] =
+    "\x11\xe4\x91\xd1\xc9\xe4\xc0\xeb\x9a\xce"
+    "\xcf\x73\x54\x5d\xe1\xf1\xa8\x30\x3e\xc3";
+
+static const char kSPKIHash_SecureCertificateServices[] =
+    "\x3c\xb4\x1a\x84\x2e\xf5\x5c\xf2\x1a\x3d"
+    "\xa5\x4a\xc8\xd1\xbe\x39\x08\x76\x37\xbc";
+
+static const char kSPKIHash_TrustedCertificateServices[] =
+    "\xfe\x72\xc8\xeb\xbf\x0c\x2f\xbb\x0e\x26"
+    "\x13\x93\x93\x3c\x2c\xa9\x8d\xdc\x24\x94";
+
+static const char kSPKIHash_UTNDATACorpSGC[] =
+    "\x53\x32\xd1\xb3\xcf\x7f\xfa\xe0\xf1\xa0"
+    "\x5d\x85\x4e\x92\xd2\x9e\x45\x1d\xb4\x4f";
+
+static const char kSPKIHash_UTNUSERFirstClientAuthenticationandEmail[] =
+    "\x89\x82\x67\x7d\xc4\x9d\x26\x70\x00\x4b"
+    "\xb4\x50\x48\x7c\xde\x3d\xae\x04\x6e\x7d";
+
+static const char kSPKIHash_UTNUSERFirstHardware[] =
+    "\xa1\x72\x5f\x26\x1b\x28\x98\x43\x95\x5d"
+    "\x07\x37\xd5\x85\x96\x9d\x4b\xd2\xc3\x45";
+
+static const char kSPKIHash_UTNUSERFirstObject[] =
+    "\xda\xed\x64\x74\x14\x9c\x14\x3c\xab\xdd"
+    "\x99\xa9\xbd\x5b\x28\x4d\x8b\x3c\xc9\xd8";
+
+static const char kSPKIHash_GTECyberTrustGlobalRoot[] =
+    "\x59\x79\x12\xde\x61\x75\xd6\x6f\xc4\x23"
+    "\xb7\x77\x13\x74\xc7\x96\xde\x6f\x88\x72";
+
+static const char kSPKIHash_BaltimoreCyberTrustRoot[] =
+    "\x30\xa4\xe6\x4f\xde\x76\x8a\xfc\xed\x5a"
+    "\x90\x84\x28\x30\x46\x79\x2c\x29\x15\x70";
+
+static const char kSPKIHash_GlobalSignRootCA[] =
+    "\x87\xdb\xd4\x5f\xb0\x92\x8d\x4e\x1d\xf8"
+    "\x15\x67\xe7\xf2\xab\xaf\xd6\x2b\x67\x75";
+
+static const char kSPKIHash_GlobalSignRootCA_R2[] =
+    "\xa5\x06\x8a\x78\xcf\x84\xbd\x74\x32\xdd"
+    "\x58\xf9\x65\xeb\x3a\x55\xe7\xc7\x80\xdc";
+
+static const char kSPKIHash_GlobalSignRootCA_R3[] =
+    "\xf7\x93\x19\xef\xdf\xc1\xf5\x20\xfb\xac"
+    "\x85\x55\x2c\xf2\xd2\x8f\x5a\xb9\xca\x0b";
+
+static const char kSPKIHash_EntrustRootEC1[] =
+    "\x07\x23\x2d\x45\x65\x87\xb9\xd7\xb1\xd9"
+    "\x7d\xd1\xc5\xfb\x65\xc5\x89\xbf\x92\x96";
+
+static const char kSPKIHash_TheGoDaddyGroupClass2[] =
+    "\xee\xe5\x9f\x1e\x2a\xa5\x44\xc3\xcb\x25"
+    "\x43\xa6\x9a\x5b\xd4\x6a\x25\xbc\xbb\x8e";
+
+static const char kSPKIHash_GoDaddyRoot_G2[] =
+    "\x21\x0f\x2c\x89\xf7\xc4\xcd\x5d\x1b\x82"
+    "\x5e\x38\xd6\xc6\x59\x3b\xa6\x93\x75\xae";
+
+static const char kSPKIHash_GoDaddySecure[] =
+    "\xba\x2e\xb5\xa8\x3e\x13\x23\xd9\x53\x4b"
+    "\x5e\x65\xbc\xe7\xa3\x13\x5d\xd0\xa9\x96";
+
+static const char kSPKIHash_ThawtePremiumServer[] =
+    "\x5f\xf3\x24\x6c\x8f\x91\x24\xaf\x9b\x5f"
+    "\x3e\xb0\x34\x6a\xf4\x2d\x5c\xa8\x5d\xcc";
+
+static const char kSPKIHash_ThawtePrimaryRootCA_G2[] =
+    "\x6a\x25\x23\x9d\x62\x75\xcd\x52\x21\x69"
+    "\x5c\x31\xe9\x89\xc4\xd5\x38\xb8\xc4\xea";
+
+static const char kSPKIHash_ThawtePrimaryRootCA_G3[] =
+    "\xab\x76\x88\xf4\xe5\xe1\x38\xc9\xe9\x50"
+    "\x17\xcd\xcd\xb3\x18\x17\xb3\x3e\x8c\xf5";
+
+static const char kSPKIHash_ThawtePrimaryRootCA[] =
+    "\x6c\xca\xbd\x7d\xb4\x7e\x94\xa5\x75\x99"
+    "\x01\xb6\xa7\xdf\xd4\x5d\x1c\x09\x1c\xcc";
+
+static const char kSPKIHash_SymantecClass3EVG3[] =
+    "\x47\x49\xdf\x16\x57\xf4\x6c\x8b\xd2\x8c"
+    "\x79\x1b\x99\xfb\x9f\x28\x81\x2a\x60\xe0";
+
+static const char kSPKIHash_DigiCertECCSecureServerCA[] =
+    "\xc3\x02\xb1\x73\x62\x0b\x47\x78\x5d\x21"
+    "\xe2\x4d\xb3\xac\x46\xb1\xfc\xb8\xc5\xa9";
+
+static const char kSPKIHash_FacebookBackup[] =
+    "\xd7\x0c\x3c\x13\x40\x18\xb1\x1d\xa8\x5f"
+    "\x99\x67\x76\x4d\xa1\xc2\x9d\x94\xa2\xc9";
+
+static const char kSPKIHash_SpiderOak1[] =
+    "\x50\xfa\xef\x15\x44\xab\xa7\xd6\x9a\x97"
+    "\x9b\xfa\x46\x7d\x09\xbf\x76\x09\xff\x05";
+
+static const char kSPKIHash_SpiderOak2[] =
+    "\x0f\x47\xd2\xfe\x1a\xae\x03\xa4\x29\xae"
+    "\x5b\x9c\x8b\x23\xb5\x86\x51\x54\x03\x18";
+
+// The following is static data describing the hosts that are hardcoded with
+// certificate pins or HSTS information.
+
+// kNoRejectedPublicKeys is a placeholder for when no public keys are rejected.
+static const char* const kNoRejectedPublicKeys[] = {
+  NULL,
+};
+
+static const char* const kTestAcceptableCerts[] = {
+  kSPKIHash_TestSPKI,
+  NULL,
+};
+static const char* const kGoogleAcceptableCerts[] = {
+  kSPKIHash_GoogleBackup2048,
+  kSPKIHash_GoogleG2,
+  NULL,
+};
+static const char* const kTorAcceptableCerts[] = {
+  kSPKIHash_RapidSSL,
+  kSPKIHash_DigiCertEVRoot,
+  kSPKIHash_Tor1,
+  kSPKIHash_Tor2,
+  kSPKIHash_Tor3,
+  NULL,
+};
+static const char* const kTwitterComAcceptableCerts[] = {
+  kSPKIHash_VeriSignClass1,
+  kSPKIHash_VeriSignClass3,
+  kSPKIHash_VeriSignClass3_G4,
+  kSPKIHash_VeriSignClass4_G3,
+  kSPKIHash_VeriSignClass3_G3,
+  kSPKIHash_VeriSignClass1_G3,
+  kSPKIHash_VeriSignClass2_G3,
+  kSPKIHash_VeriSignClass3_G2,
+  kSPKIHash_VeriSignClass2_G2,
+  kSPKIHash_VeriSignClass3_G5,
+  kSPKIHash_VeriSignUniversal,
+  kSPKIHash_GeoTrustGlobal,
+  kSPKIHash_GeoTrustGlobal2,
+  kSPKIHash_GeoTrustUniversal,
+  kSPKIHash_GeoTrustUniversal2,
+  kSPKIHash_GeoTrustPrimary,
+  kSPKIHash_GeoTrustPrimary_G2,
+  kSPKIHash_GeoTrustPrimary_G3,
+  kSPKIHash_DigiCertGlobalRoot,
+  kSPKIHash_DigiCertEVRoot,
+  kSPKIHash_DigiCertAssuredIDRoot,
+  kSPKIHash_Twitter1,
+  NULL,
+};
+static const char* const kTwitterCDNAcceptableCerts[] = {
+  kSPKIHash_VeriSignClass1,
+  kSPKIHash_VeriSignClass3,
+  kSPKIHash_VeriSignClass3_G4,
+  kSPKIHash_VeriSignClass4_G3,
+  kSPKIHash_VeriSignClass3_G3,
+  kSPKIHash_VeriSignClass1_G3,
+  kSPKIHash_VeriSignClass2_G3,
+  kSPKIHash_VeriSignClass3_G2,
+  kSPKIHash_VeriSignClass2_G2,
+  kSPKIHash_VeriSignClass3_G5,
+  kSPKIHash_VeriSignUniversal,
+  kSPKIHash_GeoTrustGlobal,
+  kSPKIHash_GeoTrustGlobal2,
+  kSPKIHash_GeoTrustUniversal,
+  kSPKIHash_GeoTrustUniversal2,
+  kSPKIHash_GeoTrustPrimary,
+  kSPKIHash_GeoTrustPrimary_G2,
+  kSPKIHash_GeoTrustPrimary_G3,
+  kSPKIHash_DigiCertGlobalRoot,
+  kSPKIHash_DigiCertEVRoot,
+  kSPKIHash_DigiCertAssuredIDRoot,
+  kSPKIHash_Twitter1,
+  kSPKIHash_Entrust_2048,
+  kSPKIHash_Entrust_EV,
+  kSPKIHash_Entrust_G2,
+  kSPKIHash_Entrust_SSL,
+  kSPKIHash_AAACertificateServices,
+  kSPKIHash_AddTrustClass1CARoot,
+  kSPKIHash_AddTrustExternalCARoot,
+  kSPKIHash_AddTrustPublicCARoot,
+  kSPKIHash_AddTrustQualifiedCARoot,
+  kSPKIHash_COMODOCertificationAuthority,
+  kSPKIHash_SecureCertificateServices,
+  kSPKIHash_TrustedCertificateServices,
+  kSPKIHash_UTNDATACorpSGC,
+  kSPKIHash_UTNUSERFirstClientAuthenticationandEmail,
+  kSPKIHash_UTNUSERFirstHardware,
+  kSPKIHash_UTNUSERFirstObject,
+  kSPKIHash_GTECyberTrustGlobalRoot,
+  kSPKIHash_BaltimoreCyberTrustRoot,
+  kSPKIHash_GlobalSignRootCA,
+  kSPKIHash_GlobalSignRootCA_R2,
+  kSPKIHash_GlobalSignRootCA_R3,
+  NULL,
+};
+static const char* const kDropboxAcceptableCerts[] = {
+  kSPKIHash_DigiCertAssuredIDRoot,
+  kSPKIHash_DigiCertGlobalRoot,
+  kSPKIHash_DigiCertEVRoot,
+  kSPKIHash_EntrustRootEC1,
+  kSPKIHash_Entrust_G2,
+  kSPKIHash_Entrust_EV,
+  kSPKIHash_Entrust_2048,
+  kSPKIHash_GeoTrustGlobal,
+  kSPKIHash_GeoTrustPrimary_G2,
+  kSPKIHash_GeoTrustPrimary_G3,
+  kSPKIHash_GeoTrustPrimary,
+  kSPKIHash_TheGoDaddyGroupClass2,
+  kSPKIHash_GoDaddyRoot_G2,
+  kSPKIHash_GoDaddySecure,
+  kSPKIHash_ThawtePremiumServer,
+  kSPKIHash_ThawtePrimaryRootCA_G2,
+  kSPKIHash_ThawtePrimaryRootCA_G3,
+  kSPKIHash_ThawtePrimaryRootCA,
+  NULL,
+};
+static const char* const kFacebookAcceptableCerts[] = {
+  kSPKIHash_SymantecClass3EVG3,
+  kSPKIHash_DigiCertECCSecureServerCA,
+  kSPKIHash_DigiCertEVRoot,
+  kSPKIHash_FacebookBackup,
+  NULL,
+};
+static const char* const kSpideroakAcceptableCerts[] = {
+  kSPKIHash_RapidSSL,
+  kSPKIHash_SpiderOak1,
+  kSPKIHash_SpiderOak2,
+  NULL,
+};
+
+struct Pinset {
+  const char *const *const accepted_pins;
+  const char *const *const rejected_pins;
+};
+
+static const struct Pinset kPinsets[] = {
+  {kTestAcceptableCerts, kNoRejectedPublicKeys},
+  {kGoogleAcceptableCerts, kNoRejectedPublicKeys},
+  {kTorAcceptableCerts, kNoRejectedPublicKeys},
+  {kTwitterComAcceptableCerts, kNoRejectedPublicKeys},
+  {kTwitterCDNAcceptableCerts, kNoRejectedPublicKeys},
+  {kDropboxAcceptableCerts, kNoRejectedPublicKeys},
+  {kFacebookAcceptableCerts, kNoRejectedPublicKeys},
+  {kSpideroakAcceptableCerts, kNoRejectedPublicKeys},
+};
+
+// kHSTSHuffmanTree describes a Huffman tree. The nodes of the tree are pairs
+// of uint8s. The last node in the array is the root of the tree. Each pair is
+// two uint8 values, the first is "left" and the second is "right". If a uint8
+// value has the MSB set then it represents a literal leaf value. Otherwise
+// it's a pointer to the n'th element of the array.
+static const uint8_t kHSTSHuffmanTree[] = {
+    0xf9, 0xe6, 0xf0, 0x00, 0x01, 0xf2, 0xae, 0xed, 0xe9, 0x03, 0x02, 0x04,
+    0xf1, 0xb2, 0xb1, 0xb5, 0xb3, 0x07, 0x06, 0x08, 0x09, 0xfa, 0x0a, 0xf6,
+    0xeb, 0x0b, 0x0c, 0xe3, 0xe1, 0x0d, 0x80, 0x0e, 0x05, 0x0f, 0xe2, 0xf7,
+    0x11, 0xf3, 0xef, 0x12, 0xff, 0x13, 0xe8, 0xf5, 0xee, 0x15, 0xe5, 0x16,
+    0xf4, 0xe7, 0xb7, 0xb6, 0xb9, 0xb8, 0x19, 0x1a, 0x1b, 0xb0, 0xb4, 0x1c,
+    0x1d, 0xea, 0xf8, 0x1e, 0xad, 0x1f, 0x20, 0xe4, 0x21, 0xec, 0x18, 0x22,
+    0x17, 0x23, 0x14, 0x24, 0x10, 0x25,
+};
+
+static const uint8_t kPreloadedHSTSData[] = {
+    0xfe, 0x36, 0x7f, 0xb5, 0x5d, 0x54, 0x44, 0xb3, 0xef, 0xf6, 0xab, 0xaa,
+    0x88, 0xb6, 0x6c, 0xd9, 0x29, 0x32, 0x52, 0x07, 0xcd, 0x28, 0x05, 0xa7,
+    0xf7, 0x33, 0xe0, 0x39, 0x5d, 0x23, 0x1a, 0x79, 0xf9, 0xfa, 0x27, 0x78,
+    0xe2, 0xd0, 0xc7, 0xe3, 0x48, 0x53, 0xfc, 0x2d, 0xa2, 0xeb, 0x1c, 0x96,
+    0x91, 0xb1, 0x34, 0x5f, 0x28, 0x78, 0x04, 0x41, 0x3f, 0x8d, 0x9f, 0xed,
+    0x57, 0x55, 0x15, 0x14, 0xff, 0xf6, 0x8b, 0x46, 0x0f, 0x32, 0xcf, 0x5b,
+    0x3d, 0x5a, 0x7d, 0xfe, 0xd5, 0x75, 0x51, 0x5e, 0xcf, 0x89, 0xd7, 0xbb,
+    0xd8, 0xb4, 0x8d, 0x87, 0xbf, 0xf3, 0x39, 0xff, 0x8d, 0x4f, 0x36, 0x7f,
+    0xb5, 0x5d, 0x54, 0x48, 0xd3, 0xff, 0x8c, 0x7a, 0x79, 0xb3, 0xfd, 0xaa,
+    0xea, 0xa2, 0x78, 0x9f, 0xfc, 0x63, 0xd3, 0xcd, 0x9f, 0xed, 0x57, 0x55,
+    0x13, 0xfc, 0xff, 0xe3, 0x1e, 0x9e, 0x6c, 0xff, 0x6a, 0xba, 0xa8, 0xa1,
+    0xa7, 0xff, 0x18, 0xf4, 0xf3, 0x67, 0xfb, 0x55, 0xd5, 0x45, 0x11, 0x3f,
+    0xea, 0x79, 0xb3, 0xfd, 0xaa, 0xea, 0xa2, 0x91, 0x9f, 0xff, 0xb3, 0xdd,
+    0x30, 0x46, 0xe0, 0xd0, 0x2f, 0x76, 0x02, 0x52, 0x31, 0xd1, 0x49, 0xe4,
+    0x93, 0x3f, 0xf1, 0xa9, 0xe6, 0xcf, 0xf6, 0xab, 0xaa, 0x89, 0x42, 0x2c,
+    0x5d, 0x99, 0x7c, 0x70, 0x7d, 0x3f, 0xf3, 0x9f, 0x7e, 0x16, 0x07, 0x27,
+    0xd2, 0x78, 0x15, 0x5d, 0x05, 0x5b, 0xaa, 0xef, 0x0f, 0x97, 0x52, 0xc9,
+    0xff, 0xc6, 0x3d, 0x3c, 0xd9, 0xfe, 0xd5, 0x75, 0x51, 0x39, 0xcf, 0xfe,
+    0x31, 0xe9, 0xe6, 0xcf, 0xf6, 0xab, 0xaa, 0x8a, 0x26, 0x7f, 0xef, 0xbc,
+    0xda, 0x2b, 0xb8, 0xf2, 0x02, 0xd1, 0xf4, 0x77, 0xdd, 0x57, 0x75, 0x59,
+    0xfc, 0x6c, 0xff, 0x6a, 0xba, 0xa8, 0x87, 0x27, 0xf9, 0xbf, 0x9d, 0xd3,
+    0x6c, 0xf5, 0xa7, 0xdf, 0xed, 0x57, 0x55, 0x11, 0x7c, 0xfe, 0xbe, 0x7b,
+    0xac, 0x05, 0x2d, 0x35, 0xf6, 0x5a, 0x7b, 0x8f, 0x60, 0xd2, 0x83, 0x9b,
+    0x9a, 0x17, 0x91, 0xac, 0x47, 0xb6, 0x1c, 0x38, 0x66, 0x2d, 0x73, 0xff,
+    0x8c, 0x7a, 0x79, 0xb3, 0xfd, 0xaa, 0xea, 0xa2, 0x64, 0x9f, 0xc6, 0xcf,
+    0xf6, 0xab, 0xaa, 0x8b, 0x7a, 0x7f, 0xf1, 0x8f, 0x4f, 0x36, 0x7f, 0xb5,
+    0x5d, 0x54, 0x52, 0x73, 0x79, 0xb7, 0x49, 0x69, 0xfb, 0x60, 0x05, 0xfa,
+    0x02, 0xd3, 0x68, 0xce, 0x89, 0xe8, 0x51, 0x0c, 0x32, 0xae, 0x17, 0xc6,
+    0x69, 0x88, 0x77, 0x55, 0x76, 0x7c, 0x14, 0x29, 0x67, 0xf1, 0xb3, 0xfd,
+    0xaa, 0xea, 0xa2, 0x1d, 0x9f, 0xfc, 0x63, 0xd3, 0xcd, 0x9f, 0xed, 0x57,
+    0x55, 0x12, 0xc4, 0xfe, 0x36, 0x7f, 0xb5, 0x5d, 0x54, 0x46, 0x13, 0xef,
+    0xf6, 0xab, 0xaa, 0x88, 0xf6, 0x7a, 0xf5, 0xb3, 0xb5, 0xa7, 0x8d, 0x4f,
+    0x36, 0x1e, 0xbf, 0x0c, 0xe7, 0xf1, 0xb3, 0xfd, 0xaa, 0xea, 0xa2, 0xc3,
+    0x9f, 0xc6, 0xcf, 0xf6, 0xab, 0xaa, 0x8b, 0x9e, 0x19, 0x3d, 0xcb, 0x0f,
+    0x9e, 0xaa, 0x50, 0x95, 0x39, 0xc7, 0x0f, 0xa7, 0xf1, 0xb3, 0xfd, 0xaa,
+    0xea, 0xa2, 0x1e, 0x9f, 0x7f, 0xb5, 0x5d, 0x54, 0x44, 0xd3, 0xff, 0xb3,
+    0x95, 0xad, 0x33, 0xb7, 0xe7, 0xd9, 0x69, 0xb8, 0x75, 0xa7, 0xff, 0x66,
+    0x82, 0xb2, 0xec, 0x5b, 0x71, 0x8e, 0xb4, 0x6c, 0x7c, 0x3a, 0x16, 0x9e,
+    0xe6, 0xf4, 0x12, 0xa2, 0x17, 0x91, 0xb1, 0x33, 0x0d, 0x19, 0xde, 0x15,
+    0x5b, 0x91, 0xce, 0xfd, 0x75, 0x69, 0x69, 0x68, 0x0c, 0xd5, 0xee, 0x37,
+    0x3d, 0xcd, 0x17, 0x16, 0x9f, 0xff, 0xfb, 0x5b, 0xfa, 0x59, 0xf7, 0x07,
+    0x1d, 0xeb, 0x3d, 0x6b, 0xdd, 0x83, 0x5a, 0x7f, 0xf1, 0x38, 0xfc, 0xd9,
+    0xfe, 0x0f, 0x54, 0x2b, 0x4d, 0x4e, 0xab, 0x46, 0x23, 0xeb, 0xa4, 0x3a,
+    0x76, 0xa4, 0xb9, 0xdf, 0xae, 0xad, 0x0e, 0x89, 0xeb, 0x06, 0x77, 0x3e,
+    0xd5, 0x72, 0x9e, 0xb4, 0xfe, 0x7d, 0xda, 0xfe, 0x68, 0xf3, 0x7e, 0x6d,
+    0x69, 0xe2, 0xb9, 0x01, 0x69, 0xd6, 0xdb, 0x6a, 0x53, 0xea, 0x1e, 0x6b,
+    0x12, 0x31, 0x7f, 0x3e, 0xae, 0x39, 0x9c, 0x5a, 0x3d, 0x44, 0xd0, 0x0f,
+    0xc4, 0xd2, 0x7b, 0x55, 0x54, 0xb4, 0xff, 0xc0, 0x27, 0x3c, 0x69, 0x8b,
+    0xfb, 0xf9, 0xd6, 0x9f, 0xf1, 0x06, 0xc2, 0xd7, 0x62, 0x3a, 0xd3, 0xf6,
+    0x3b, 0xdd, 0xf9, 0x75, 0xa7, 0xb3, 0xdc, 0xb1, 0x68, 0xc5, 0x45, 0xbb,
+    0x13, 0x14, 0x38, 0x7c, 0xe6, 0x0e, 0x0f, 0xe9, 0x2c, 0x4e, 0xf8, 0x5f,
+    0x3f, 0x65, 0xad, 0x9e, 0x92, 0xd3, 0x9b, 0x70, 0x2d, 0x3f, 0xff, 0xf8,
+    0x47, 0x66, 0x0c, 0x73, 0xdd, 0x13, 0x9e, 0x2f, 0x9b, 0x3f, 0xf9, 0x6a,
+    0xd3, 0xe2, 0xe6, 0xed, 0x62, 0xd3, 0xff, 0xfb, 0x36, 0x7d, 0xcf, 0x83,
+    0xe1, 0xd4, 0xb5, 0x61, 0x67, 0xd6, 0x9f, 0xff, 0xf5, 0xbe, 0x07, 0x3b,
+    0xa2, 0x1c, 0xdf, 0x6e, 0x78, 0xab, 0x70, 0x35, 0xa7, 0xf6, 0xcf, 0xb8,
+    0x7b, 0xb6, 0xcb, 0x4f, 0xea, 0xb7, 0x77, 0x1b, 0x94, 0xb4, 0x32, 0x37,
+    0x49, 0xc8, 0x4d, 0xe7, 0x81, 0xc2, 0xb1, 0x69, 0xff, 0x35, 0x58, 0xc7,
+    0x16, 0xd8, 0x0b, 0x43, 0x2a, 0x72, 0xc7, 0xc2, 0x28, 0xfc, 0x68, 0x54,
+    0x5a, 0x24, 0x53, 0x6e, 0xf5, 0xa7, 0xcc, 0x0b, 0xd9, 0xc5, 0xa7, 0x57,
+    0x2e, 0xb4, 0xdb, 0xd8, 0xb4, 0xe1, 0xe3, 0x8f, 0x36, 0x7f, 0x1b, 0x9f,
+    0xb7, 0xef, 0x8f, 0x76, 0xb5, 0x68, 0x63, 0xe7, 0x23, 0x39, 0xff, 0xf6,
+    0xed, 0xcf, 0x03, 0xbb, 0xaf, 0x8c, 0xe7, 0x96, 0x71, 0x69, 0xff, 0xb4,
+    0xc1, 0xf8, 0xe0, 0xd7, 0x1b, 0x8b, 0x4f, 0xef, 0x1b, 0x3c, 0xb5, 0xb9,
+    0xd6, 0x80, 0x1f, 0xe0, 0xa2, 0xcf, 0xfb, 0xee, 0x78, 0xbb, 0x15, 0x95,
+    0xc5, 0xa1, 0x8f, 0x8b, 0x72, 0x19, 0xff, 0xff, 0xed, 0xc6, 0xff, 0x16,
+    0x73, 0xc0, 0x5c, 0x27, 0xe6, 0xdc, 0xc7, 0x63, 0x97, 0x5a, 0x4c, 0xb4,
+    0xfd, 0x5f, 0x2b, 0xb6, 0xcb, 0x4f, 0xfa, 0xad, 0xfb, 0x0f, 0x35, 0x8e,
+    0xab, 0x43, 0xcf, 0xb3, 0xe5, 0x93, 0xfd, 0xa2, 0xfb, 0x9a, 0xac, 0xfa,
+    0xd3, 0xff, 0xff, 0xf0, 0x2e, 0x39, 0x5b, 0x78, 0xf7, 0x5b, 0xf8, 0x1c,
+    0xd9, 0xf9, 0xbd, 0x83, 0x95, 0xb2, 0xd1, 0xd4, 0x64, 0x11, 0xc4, 0xea,
+    0xae, 0xaa, 0x29, 0x88, 0xc3, 0xc9, 0xe9, 0x14, 0xff, 0xb0, 0x76, 0x7d,
+    0xf8, 0xdf, 0x71, 0x69, 0xd8, 0x40, 0x5a, 0x58, 0xb4, 0xed, 0x87, 0x00,
+    0x6a, 0x5d, 0x8d, 0x41, 0x22, 0x72, 0x9a, 0x27, 0x3d, 0xb6, 0x5a, 0x7f,
+    0x1f, 0xdd, 0x35, 0x99, 0x6a, 0xd1, 0xb1, 0xe8, 0xd0, 0xe4, 0xff, 0xfe,
+    0x1c, 0xef, 0x38, 0xdc, 0xbb, 0x83, 0x96, 0xf8, 0x67, 0x4c, 0xb4, 0xff,
+    0xba, 0xc7, 0xd6, 0x5f, 0x08, 0x56, 0x86, 0x45, 0x1e, 0x9a, 0x27, 0xdf,
+    0x67, 0x6d, 0xf5, 0xa7, 0xea, 0x1f, 0x1e, 0xb0, 0xad, 0x18, 0x7e, 0xe4,
+    0x45, 0xb9, 0x44, 0x58, 0xbe, 0x44, 0xf1, 0x7f, 0x61, 0x84, 0x19, 0x07,
+    0x63, 0x3e, 0xd8, 0x88, 0xa1, 0x04, 0xe3, 0xdf, 0xe3, 0x33, 0x3c, 0x2f,
+    0x45, 0xcb, 0x91, 0x9e, 0x4f, 0xf8, 0x3f, 0xd5, 0xbe, 0x2b, 0xda, 0xb1,
+    0x69, 0xec, 0x10, 0xfc, 0xeb, 0x4f, 0xff, 0xff, 0xb4, 0x5c, 0xd6, 0x7d,
+    0x9d, 0xf8, 0x3e, 0xee, 0xbe, 0x33, 0x67, 0xe6, 0xe2, 0x0b, 0xad, 0x2e,
+    0x12, 0x2c, 0xee, 0x4b, 0x3f, 0xfe, 0xcc, 0xd1, 0x77, 0x59, 0xe2, 0xfb,
+    0xe9, 0xbc, 0xeb, 0x4f, 0xff, 0x73, 0x58, 0x0f, 0x07, 0x6c, 0xe7, 0xb8,
+    0x2b, 0x4f, 0xf6, 0xde, 0x0e, 0xd8, 0x3c, 0xf2, 0x5a, 0x57, 0xc4, 0x46,
+    0xd2, 0x84, 0x88, 0x53, 0x0e, 0xe4, 0x39, 0xe7, 0xcf, 0x6d, 0x9f, 0x75,
+    0xa7, 0xff, 0xff, 0xfd, 0x82, 0x1f, 0x82, 0xd6, 0xe6, 0x70, 0xb8, 0xc7,
+    0x1a, 0x0f, 0x44, 0x6c, 0xd6, 0xc0, 0x6f, 0x52, 0x9f, 0xff, 0xfb, 0xa5,
+    0x6f, 0xbb, 0xff, 0xc6, 0xed, 0x65, 0xfb, 0xad, 0xf5, 0xb5, 0x5a, 0xb4,
+    0xdb, 0xd9, 0xb2, 0x68, 0x64, 0x51, 0x78, 0x4f, 0x43, 0x2a, 0xea, 0xd4,
+    0x66, 0xc3, 0x1b, 0x84, 0xff, 0xe3, 0xf7, 0xc6, 0xa9, 0xf8, 0x7a, 0x10,
+    0x2d, 0x3f, 0xfe, 0x21, 0xe6, 0xb1, 0xd7, 0x8e, 0x67, 0x9e, 0x84, 0x0b,
+    0x4f, 0xfc, 0xc3, 0x60, 0xe3, 0xbb, 0xee, 0xdb, 0x2d, 0x17, 0x45, 0x06,
+    0xeb, 0x53, 0xd9, 0xcc, 0x74, 0x16, 0x9d, 0xe5, 0x9a, 0x5a, 0x6c, 0xf5,
+    0x68, 0xb1, 0x36, 0x77, 0xc3, 0xaa, 0xe4, 0x9c, 0x25, 0x76, 0x3d, 0x3e,
+    0x2e, 0x5f, 0x00, 0xb4, 0xfd, 0xeb, 0x0e, 0xa9, 0xeb, 0x4e, 0x6f, 0x59,
+    0x69, 0xf9, 0xf9, 0xcb, 0xd3, 0x9e, 0x0f, 0x1c, 0xe5, 0x90, 0xf4, 0x5a,
+    0x38, 0xdb, 0x3f, 0x3a, 0xea, 0xbc, 0xec, 0x05, 0xa7, 0xf7, 0xdc, 0x1c,
+    0xd5, 0x71, 0x68, 0xc3, 0xe5, 0x23, 0x39, 0xf9, 0x81, 0x9c, 0x0a, 0xc5,
+    0xa1, 0xe7, 0x9c, 0x24, 0x13, 0xfd, 0xcd, 0x63, 0xe8, 0x73, 0x65, 0xa7,
+    0xff, 0xf8, 0x68, 0x17, 0xb3, 0x08, 0x78, 0x38, 0xef, 0xc5, 0xed, 0x15,
+    0xa0, 0x51, 0x3f, 0xc3, 0x79, 0xff, 0x16, 0x39, 0xe2, 0xed, 0xaa, 0xf3,
+    0xad, 0x3f, 0xab, 0x6b, 0xeb, 0x2b, 0xeb, 0x47, 0xa7, 0xeb, 0xc4, 0x39,
+    0xfe, 0xcf, 0xd8, 0xc5, 0xfc, 0x15, 0xa4, 0x75, 0xbc, 0x1b, 0x69, 0xc3,
+    0x9e, 0xad, 0x0c, 0x6f, 0x76, 0x22, 0x9f, 0xb6, 0xbe, 0x60, 0x86, 0xb4,
+    0xf1, 0xc2, 0x60, 0x2d, 0x18, 0x79, 0xe4, 0x5b, 0x3b, 0x7d, 0x80, 0xb4,
+    0x32, 0x7b, 0x79, 0x09, 0x72, 0x84, 0xb7, 0xdc, 0x04, 0x82, 0x7f, 0x70,
+    0xac, 0xcd, 0x6f, 0xc5, 0xa4, 0xe2, 0xd3, 0xf6, 0x6f, 0x9a, 0xed, 0x8b,
+    0x4d, 0x9b, 0x31, 0xbf, 0xb8, 0x8c, 0xfd, 0xaa, 0x79, 0xfe, 0x4b, 0x4f,
+    0x03, 0xf9, 0xb2, 0xd3, 0xe2, 0xbd, 0xd8, 0xeb, 0x41, 0x1e, 0x43, 0xb2,
+    0x28, 0x0d, 0x33, 0x62, 0x73, 0x01, 0x66, 0xee, 0x93, 0xff, 0xf7, 0xdf,
+    0xac, 0x73, 0x4c, 0x21, 0x8e, 0x73, 0x5b, 0xad, 0x3f, 0xff, 0x8b, 0x36,
+    0x7d, 0xf9, 0xa6, 0x3b, 0x17, 0xbe, 0x19, 0xd3, 0x2d, 0x3f, 0xff, 0xfe,
+    0xdc, 0x7c, 0x5b, 0x5b, 0x3f, 0xf4, 0x0f, 0x17, 0xdd, 0xb6, 0xd6, 0x10,
+    0xe0, 0x6b, 0x4f, 0xff, 0xb7, 0xff, 0xf3, 0x97, 0xd1, 0x67, 0x8d, 0x01,
+    0x96, 0x8c, 0x47, 0x0e, 0xa1, 0x15, 0x3f, 0xfc, 0xf7, 0x5d, 0x63, 0x0b,
+    0x83, 0x9c, 0xbd, 0x2d, 0x3f, 0xfe, 0xf7, 0x0f, 0xe1, 0xd7, 0x8d, 0x77,
+    0x1f, 0x5f, 0xb1, 0x69, 0xff, 0xfb, 0x85, 0x66, 0x7b, 0xe0, 0xf4, 0xff,
+    0x95, 0x94, 0x75, 0xa7, 0xf5, 0x94, 0x71, 0x6f, 0xb8, 0xb4, 0xff, 0x6d,
+    0x81, 0x80, 0xf9, 0xe3, 0xf8, 0x89, 0x12, 0x5e, 0x9f, 0xec, 0x1b, 0x3c,
+    0x02, 0xa9, 0xc5, 0xa7, 0xfb, 0xf6, 0x35, 0x96, 0x6f, 0xfb, 0x16, 0x9f,
+    0xed, 0xc7, 0xc5, 0xf7, 0xf2, 0xdf, 0xeb, 0x43, 0x1f, 0xfd, 0xcf, 0xa7,
+    0xff, 0x59, 0xe2, 0xfa, 0xdf, 0xc7, 0x2f, 0x76, 0xfa, 0xd3, 0xff, 0xfe,
+    0xcd, 0xae, 0x59, 0x6f, 0x8d, 0x67, 0x2f, 0x96, 0x78, 0xc2, 0xf5, 0x68,
+    0xc4, 0x61, 0x12, 0x8c, 0x58, 0xb9, 0x7d, 0xd8, 0xd2, 0x76, 0x27, 0x25,
+    0x0f, 0xc3, 0xb8, 0xea, 0x77, 0x85, 0xcf, 0x21, 0xc7, 0x3f, 0xb8, 0x39,
+    0xcd, 0x65, 0x8b, 0x4f, 0xfa, 0xbf, 0xac, 0xe3, 0x09, 0x01, 0x69, 0xfe,
+    0xcb, 0x76, 0x7d, 0xfc, 0x70, 0x96, 0x9f, 0xff, 0xf3, 0x75, 0x8f, 0xe1,
+    0xcd, 0x10, 0xfb, 0xe0, 0x2e, 0x8e, 0x6b, 0x16, 0x86, 0x4c, 0x67, 0xa6,
+    0x42, 0x76, 0xea, 0x79, 0x3c, 0x5c, 0x26, 0x5a, 0x7f, 0xff, 0xf0, 0x90,
+    0x7a, 0xa7, 0x3c, 0x0e, 0xee, 0xbe, 0x33, 0x67, 0xe6, 0xe2, 0x0b, 0xad,
+    0x3e, 0xd1, 0x30, 0xd8, 0xb4, 0xdc, 0x63, 0xa2, 0x9d, 0xdc, 0x20, 0x61,
+    0xe8, 0xfb, 0x28, 0x63, 0x43, 0x32, 0x07, 0xb2, 0x74, 0x68, 0xa3, 0xa3,
+    0xa8, 0xce, 0xa7, 0xcc, 0x3c, 0x27, 0x6b, 0x4f, 0x72, 0xf4, 0x05, 0xa7,
+    0xfe, 0xd1, 0x78, 0x2f, 0xef, 0x65, 0x7f, 0xab, 0x4f, 0x16, 0xaa, 0xc5,
+    0xa7, 0x9d, 0xb7, 0x19, 0x69, 0xfb, 0x55, 0x67, 0x87, 0xf1, 0x69, 0xf5,
+    0x7c, 0x76, 0x25, 0xa0, 0x8f, 0x5b, 0x86, 0x11, 0xea, 0x69, 0x38, 0x4e,
+    0x19, 0x0f, 0x51, 0xc8, 0x87, 0x8f, 0x13, 0xc1, 0x6f, 0x57, 0x5a, 0x7f,
+    0xfe, 0x2f, 0xf8, 0xc2, 0xc1, 0x0f, 0x45, 0x87, 0xce, 0xad, 0x3f, 0xff,
+    0xc5, 0x67, 0xd8, 0xf7, 0xdd, 0xbc, 0x37, 0xdb, 0xdd, 0x31, 0xd6, 0x8c,
+    0x46, 0x17, 0xd6, 0x67, 0xff, 0xff, 0x7f, 0xe5, 0x67, 0x8d, 0x67, 0x05,
+    0x9c, 0xd6, 0x58, 0xdb, 0x73, 0x7e, 0xad, 0x3f, 0xff, 0xf3, 0x07, 0xa6,
+    0xf0, 0x39, 0xb8, 0x7e, 0x36, 0x7d, 0xc8, 0x42, 0x6b, 0x16, 0x9f, 0x6d,
+    0x72, 0xc1, 0x5a, 0x31, 0x13, 0xfb, 0xbc, 0xc1, 0x26, 0x7f, 0xa8, 0xc7,
+    0x27, 0xfe, 0x7d, 0xc8, 0x3d, 0x31, 0x58, 0xc1, 0xad, 0x3f, 0xc3, 0xbb,
+    0x83, 0x9a, 0xae, 0x2d, 0x3f, 0xde, 0xe9, 0xad, 0xf7, 0x54, 0x75, 0xa7,
+    0xff, 0xfa, 0xbf, 0xac, 0xe1, 0x60, 0xd9, 0x76, 0xc1, 0xf7, 0x4c, 0xb4,
+    0xf7, 0x3c, 0x59, 0xf5, 0xa3, 0x64, 0x44, 0x53, 0x1c, 0xff, 0xeb, 0x68,
+    0x6c, 0x3e, 0xe5, 0xe9, 0x09, 0x2d, 0x3f, 0x39, 0xb3, 0xf7, 0x6e, 0x2d,
+    0x3f, 0xda, 0xa3, 0x8e, 0x6a, 0xb8, 0xb4, 0xf6, 0x7c, 0x16, 0xad, 0x0c,
+    0x88, 0x8b, 0x98, 0x70, 0xda, 0x7e, 0xce, 0x7f, 0xf8, 0xf5, 0xa7, 0xe1,
+    0xcd, 0x0e, 0x75, 0x69, 0xe1, 0xcb, 0xf8, 0x70, 0xf5, 0xb8, 0x59, 0x1e,
+    0xae, 0x3f, 0xf6, 0x36, 0x1d, 0x8a, 0x49, 0x17, 0xe7, 0x1a, 0x86, 0x1d,
+    0xc8, 0xf9, 0x0d, 0x27, 0x70, 0x85, 0x9f, 0xf8, 0x47, 0x3c, 0x7f, 0x34,
+    0x38, 0xe2, 0xd0, 0xcb, 0xc8, 0x19, 0x3a, 0xc9, 0x50, 0x99, 0x9f, 0x0b,
+    0x1e, 0xbd, 0x5a, 0x7f, 0x63, 0x9a, 0xce, 0x37, 0xab, 0x4f, 0xff, 0xff,
+    0x6b, 0x39, 0x7a, 0x73, 0xc0, 0xe6, 0xcf, 0xcd, 0xec, 0x1c, 0xf7, 0x44,
+    0xe2, 0xd3, 0x6e, 0x1a, 0xd1, 0xf4, 0x4d, 0x72, 0x10, 0x53, 0xf6, 0x58,
+    0x39, 0xb5, 0xd6, 0x9f, 0xfd, 0xfd, 0x9f, 0x7c, 0x3e, 0xcd, 0xad, 0x32,
+    0xd2, 0xba, 0xd1, 0xb9, 0xed, 0x84, 0x97, 0x3f, 0x98, 0xe3, 0x9a, 0xae,
+    0x2d, 0x3d, 0xe3, 0xb6, 0x5a, 0xb4, 0xff, 0xff, 0xb8, 0x2c, 0x0d, 0x9f,
+    0x7d, 0xdb, 0x83, 0x9e, 0x96, 0x7d, 0xc5, 0xa0, 0x95, 0x45, 0x38, 0x4d,
+    0x50, 0xcd, 0x12, 0x8b, 0xc2, 0x23, 0x72, 0x47, 0x66, 0x01, 0x13, 0x4f,
+    0x9e, 0x5f, 0xcd, 0x96, 0x9f, 0x65, 0xec, 0xcb, 0x56, 0x8d, 0x8f, 0x3f,
+    0x44, 0xf3, 0xff, 0xe2, 0xb3, 0x3b, 0xee, 0x8b, 0x03, 0xf0, 0x1e, 0xec,
+    0xb4, 0xf3, 0xaf, 0x33, 0x4b, 0x4c, 0x47, 0x5a, 0x7f, 0xff, 0xdb, 0x3e,
+    0xb6, 0xf0, 0x3b, 0xba, 0xf8, 0xcd, 0x9f, 0x9b, 0x88, 0x2e, 0xb4, 0x1d,
+    0x11, 0x8e, 0xa2, 0xb1, 0x62, 0x35, 0xb2, 0x16, 0x13, 0xff, 0xff, 0xe6,
+    0xda, 0xfb, 0xb6, 0xde, 0x35, 0x9e, 0xf8, 0x1c, 0xdc, 0x3f, 0x17, 0x00,
+    0x0b, 0x8b, 0x4f, 0x98, 0x76, 0xab, 0x16, 0x9f, 0xff, 0xff, 0xfd, 0x87,
+    0xce, 0xb6, 0x98, 0xfc, 0xcb, 0xdd, 0xbf, 0xf6, 0x1c, 0xb3, 0x37, 0xbe,
+    0xee, 0x0b, 0x1d, 0x69, 0xfe, 0x06, 0x7a, 0x39, 0xaa, 0xe2, 0xd3, 0xfa,
+    0xcd, 0xdb, 0x87, 0x2e, 0x2d, 0x3f, 0xe6, 0x0d, 0xd7, 0x7c, 0x17, 0x02,
+    0x3a, 0xd1, 0x87, 0xf1, 0xb1, 0xa4, 0xff, 0xb3, 0x01, 0x7f, 0x1f, 0xbf,
+    0xb7, 0x5a, 0x7f, 0x7f, 0x3b, 0xa2, 0xfb, 0x8b, 0x4d, 0x9c, 0xf4, 0xfd,
+    0x31, 0x06, 0x7a, 0xc2, 0x1e, 0x2d, 0x0c, 0xb8, 0xcf, 0x84, 0x65, 0x19,
+    0x87, 0xca, 0x0f, 0x08, 0xed, 0x13, 0xd4, 0x29, 0x06, 0x15, 0xf7, 0x84,
+    0xb6, 0xe5, 0xb3, 0xbd, 0xf0, 0xe2, 0xd3, 0xff, 0xdb, 0x3c, 0x5b, 0xc1,
+    0xc5, 0x83, 0xe1, 0x58, 0xb4, 0x61, 0xf9, 0x11, 0x04, 0xfd, 0x63, 0x8f,
+    0xf3, 0x3f, 0x62, 0xd3, 0xe3, 0x97, 0xb9, 0xea, 0xd2, 0x71, 0x69, 0x98,
+    0xeb, 0x4b, 0x8b, 0x47, 0xcd, 0x2d, 0x0a, 0xc7, 0xa7, 0xad, 0xa3, 0x69,
+    0xee, 0x5e, 0xb6, 0x5a, 0x67, 0x29, 0x69, 0xfd, 0xa2, 0xfe, 0xcf, 0x16,
+    0x5a, 0x3c, 0xda, 0x68, 0x2c, 0x6d, 0x8f, 0xc4, 0x46, 0x72, 0x2d, 0xc5,
+    0xa7, 0xf5, 0xcb, 0x6b, 0x68, 0x40, 0xb4, 0xff, 0xf9, 0xbe, 0xdd, 0xc3,
+    0xb7, 0x5e, 0x57, 0xdc, 0xeb, 0x43, 0x88, 0x87, 0xf2, 0x33, 0x9f, 0xbf,
+    0x8c, 0x1b, 0x0a, 0xd3, 0x86, 0x8e, 0xb4, 0xc0, 0x65, 0xa1, 0xe7, 0xb4,
+    0x45, 0x62, 0x35, 0x0e, 0x93, 0xb7, 0x5b, 0xf3, 0x23, 0x73, 0x69, 0x4a,
+    0xb6, 0x3d, 0xbc, 0xb3, 0xd9, 0x51, 0xd9, 0x3e, 0xf8, 0x1c, 0x33, 0x3b,
+    0x2f, 0x83, 0x68, 0xe8, 0xca, 0x30, 0x77, 0x21, 0xaf, 0xf9, 0x53, 0x67,
+    0x8e, 0x1f, 0x54, 0x85, 0xda, 0x8e, 0x68, 0x67, 0xa6, 0x2f, 0x2b, 0x1f,
+    0x93, 0xa6, 0xae, 0xe3, 0x16, 0xf2, 0x8d, 0x84, 0x28, 0x71, 0xba, 0xc2,
+    0x06, 0x7f, 0xfe, 0xdf, 0xa6, 0xdb, 0x9f, 0x6c, 0xdb, 0xcc, 0xf6, 0xa8,
+    0x35, 0xa0, 0xca, 0x8c, 0xca, 0x3c, 0xf9, 0xfc, 0x6c, 0xff, 0x6a, 0xba,
+    0xa8, 0xa7, 0x67, 0xdf, 0xed, 0x57, 0x55, 0x15, 0x1c, 0xff, 0xa9, 0xe6,
+    0xcf, 0xf6, 0xab, 0xaa, 0x89, 0xa2, 0x30, 0xff, 0x0e, 0x67, 0x3f, 0x82,
+    0xa7, 0x66, 0xe1, 0x58, 0xb4, 0x18, 0xf5, 0xd8, 0x86, 0x7f, 0x1b, 0x3f,
+    0xda, 0xae, 0xaa, 0x2a, 0xf9, 0xf7, 0xfb, 0x55, 0xd5, 0x45, 0x6d, 0x3f,
+    0xcf, 0x36, 0x7f, 0xb5, 0x5d, 0x54, 0x48, 0x32, 0x36, 0x1f, 0xbd, 0x19,
+    0xcf, 0xfc, 0x6a, 0x79, 0xb3, 0xfd, 0xaa, 0xea, 0xa2, 0x43, 0x9f, 0xf3,
+    0xf4, 0xdc, 0xbb, 0xa6, 0xbb, 0xa4, 0x2b, 0x4b, 0x65, 0xa6, 0x21, 0x5a,
+    0x3d, 0x34, 0xae, 0x08, 0xcf, 0xb3, 0x04, 0x17, 0x5a, 0x7d, 0xfe, 0xd5,
+    0x75, 0x51, 0x62, 0x4f, 0xb3, 0xec, 0x21, 0xad, 0x3e, 0x0b, 0xcb, 0x3e,
+    0xcb, 0x4e, 0xbb, 0x0a, 0xd2, 0xd3, 0x1e, 0x21, 0x15, 0x4f, 0xfc, 0xd9,
+    0x7c, 0x1f, 0x48, 0x0c, 0x2b, 0x4e, 0x16, 0xb1, 0x69, 0x3c, 0x4f, 0x6f,
+    0x74, 0x09, 0xde, 0x44, 0x05, 0xa7, 0xc4, 0xef, 0x7a, 0xba, 0xd3, 0xff,
+    0x3b, 0xdf, 0x36, 0xf5, 0xde, 0xb2, 0x9c, 0x5a, 0x66, 0x7a, 0xd1, 0x87,
+    0xc1, 0xf4, 0xb9, 0xfd, 0x9f, 0x78, 0x33, 0x1c, 0x5a, 0x7d, 0x4f, 0x0b,
+    0x4c, 0xb4, 0xfd, 0x7b, 0xfc, 0xad, 0xf3, 0xad, 0x0c, 0x88, 0xb2, 0x32,
+    0xa2, 0x79, 0xff, 0xe7, 0xb1, 0xd9, 0xfe, 0x8b, 0x6a, 0xb3, 0xeb, 0x4f,
+    0xee, 0x8e, 0x3b, 0x1c, 0xba, 0xd1, 0xb1, 0xff, 0xe9, 0x36, 0x7f, 0x01,
+    0xb3, 0x84, 0x36, 0xa5, 0x3f, 0xf6, 0xa8, 0xb8, 0xfc, 0x0c, 0x70, 0x0b,
+    0x4f, 0xb3, 0x5b, 0x57, 0x9d, 0x69, 0xe0, 0x5d, 0x85, 0x69, 0xfd, 0xfd,
+    0x51, 0x5c, 0x9d, 0xad, 0x0c, 0x7a, 0x78, 0x41, 0x04, 0x8e, 0x01, 0x42,
+    0xbb, 0xf4, 0xfd, 0x56, 0x71, 0xb6, 0x7a, 0xd3, 0xfe, 0x16, 0x2f, 0x78,
+    0x35, 0xb5, 0xd6, 0x87, 0x49, 0x77, 0x21, 0x9b, 0xbd, 0x23, 0xc2, 0x50,
+    0xcc, 0xfa, 0xd5, 0xb4, 0x20, 0x48, 0xa1, 0xc1, 0xef, 0xc2, 0x27, 0x50,
+    0xac, 0xa8, 0x56, 0x00, 0x8e, 0xf1, 0x88, 0xf0, 0xb8, 0x22, 0xe9, 0xff,
+    0xb4, 0x4d, 0xcd, 0x50, 0x78, 0x20, 0x5a, 0x7f, 0xfb, 0x36, 0x7f, 0x37,
+    0xb0, 0xda, 0xa3, 0x95, 0xd6, 0x9d, 0xc1, 0x65, 0xa6, 0xd1, 0xb1, 0x15,
+    0xc2, 0x84, 0x12, 0x94, 0x19, 0x3e, 0x56, 0x8e, 0xaa, 0x7f, 0x1b, 0x3f,
+    0xda, 0xae, 0xaa, 0x2c, 0xd9, 0xb3, 0xd5, 0xa7, 0xfd, 0x4f, 0x36, 0x7f,
+    0xb5, 0x5d, 0x54, 0x50, 0x13, 0xf8, 0x8e, 0xde, 0x7d, 0x65, 0x8b, 0x48,
+    0xd8, 0x89, 0x53, 0x8b, 0x69, 0x26, 0x6d, 0xf4, 0xb4, 0xfd, 0x76, 0x38,
+    0xb3, 0x8b, 0x4b, 0x4b, 0x4e, 0x08, 0x5c, 0x5a, 0x6c, 0xe6, 0x1a, 0xd0,
+    0x08, 0x40, 0x11, 0x08, 0x2b, 0x33, 0x78, 0xba, 0xd3, 0xfd, 0xac, 0xff,
+    0x05, 0x8f, 0x75, 0xa7, 0xbb, 0x55, 0xd5, 0x45, 0xbf, 0x3f, 0x05, 0xca,
+    0xed, 0x7d, 0x68, 0xf9, 0xed, 0x00, 0xb6, 0x7b, 0x04, 0x9c, 0x5a, 0x7d,
+    0xc7, 0xdc, 0x2b, 0xad, 0x3f, 0x3b, 0x0b, 0x82, 0xc0, 0x5a, 0x7d, 0xeb,
+    0x79, 0xf7, 0x3a, 0xd0, 0xc7, 0xb8, 0x45, 0xf3, 0xd4, 0x43, 0xc5, 0xa7,
+    0xf6, 0xfb, 0x5d, 0xbb, 0x87, 0x5a, 0x7b, 0x41, 0xfa, 0x75, 0xa6, 0xc7,
+    0xad, 0x18, 0x6e, 0x44, 0x92, 0x46, 0x74, 0x95, 0x7c, 0x34, 0x26, 0xde,
+    0x45, 0xe8, 0xc6, 0x42, 0x44, 0x88, 0xbe, 0x41, 0xa8, 0x42, 0x80, 0x80,
+    0x47, 0xf8, 0xdb, 0x3f, 0xea, 0x79, 0xb3, 0xfd, 0xaa, 0xea, 0xa2, 0x94,
+    0x9f, 0xe7, 0x9b, 0x3f, 0xda, 0xae, 0xaa, 0x24, 0xe9, 0x18, 0xe8, 0x8d,
+    0xa4, 0x98, 0x67, 0xcb, 0x32, 0xb2, 0x36, 0xef, 0x6d, 0xd0, 0x16, 0x15,
+    0x76, 0x31, 0x12, 0x21, 0xf3, 0xc2, 0xd5, 0xc2, 0x63, 0xcf, 0xfe, 0x68,
+    0xa4, 0x10, 0xd3, 0xbc, 0xb2, 0xd7, 0x71, 0x9f, 0x4f, 0xbf, 0xda, 0xae,
+    0xaa, 0x21, 0xf9, 0xff, 0x53, 0xcd, 0x9f, 0xed, 0x57, 0x55, 0x12, 0x9c,
+    0x8d, 0x87, 0xf8, 0x73, 0x39, 0xfc, 0x6c, 0xff, 0x6a, 0xba, 0xa8, 0x89,
+    0xe7, 0xf1, 0xb3, 0xfd, 0xaa, 0xea, 0xa2, 0x31, 0x9f, 0xfc, 0x63, 0xd3,
+    0xcd, 0x9f, 0xed, 0x57, 0x55, 0x13, 0xcc, 0x32, 0x3e, 0x2c, 0x27, 0x79,
+    0xf6, 0x8f, 0xa7, 0xdf, 0xed, 0x57, 0x55, 0x11, 0x04, 0xff, 0xa9, 0xe6,
+    0xcf, 0xf6, 0xab, 0xaa, 0x89, 0x52, 0x46, 0xc3, 0xfc, 0x39, 0x9c, 0xfe,
+    0x36, 0x7f, 0xb5, 0x5d, 0x54, 0x45, 0x13, 0xf8, 0xd9, 0xfe, 0xd5, 0x75,
+    0x51, 0x19, 0x4f, 0xfe, 0x31, 0xe9, 0xe6, 0xcf, 0xf6, 0xab, 0xaa, 0x89,
+    0x96, 0x7f, 0x1b, 0x3f, 0xda, 0xae, 0xaa, 0x2a, 0x49, 0xfc, 0x6c, 0xff,
+    0x6a, 0xba, 0xa8, 0xae, 0xa7, 0xf1, 0xb3, 0xfd, 0xaa, 0xea, 0xa2, 0xc5,
+    0x9f, 0xf8, 0xf4, 0xf3, 0x67, 0xfb, 0x55, 0xd5, 0x44, 0xf5, 0x3f, 0xd6,
+    0x9a, 0x98, 0xbc, 0x89, 0xd5, 0x68, 0x32, 0x23, 0x19, 0x3e, 0x7e, 0xf3,
+    0x46, 0x70, 0xb7, 0xba, 0xd3, 0xdf, 0x3f, 0x36, 0x5a, 0x77, 0x73, 0x49,
+    0x4e, 0x3b, 0x5d, 0x69, 0xff, 0xfb, 0x43, 0x41, 0x97, 0xd9, 0xef, 0xcb,
+    0x80, 0x0c, 0xb4, 0xff, 0xfd, 0xf2, 0x75, 0xa3, 0x99, 0xbf, 0xf2, 0x75,
+    0xee, 0xf6, 0x2d, 0x3c, 0x5a, 0x08, 0xeb, 0x4f, 0xfe, 0x20, 0xfc, 0x60,
+    0xd6, 0xd7, 0x0c, 0x3a, 0x5a, 0x3a, 0x7d, 0xe2, 0x45, 0x3f, 0xfa, 0xae,
+    0x38, 0x03, 0x68, 0xbb, 0x5f, 0x5a, 0x7e, 0xf7, 0x03, 0xe6, 0x75, 0x69,
+    0xed, 0x31, 0xfa, 0xb4, 0x51, 0xe7, 0xf0, 0xba, 0x7f, 0xf0, 0xf8, 0x66,
+    0x16, 0x3f, 0x8f, 0x1a, 0xf2, 0x5a, 0x6a, 0xd9, 0x69, 0xfd, 0x57, 0xad,
+    0x6e, 0x36, 0x2d, 0x02, 0x79, 0x3b, 0x8b, 0x45, 0x8a, 0xb6, 0x08, 0x6f,
+    0xeb, 0x27, 0x86, 0x8e, 0x88, 0x46, 0x12, 0xdc, 0x21, 0x75, 0x84, 0xcc,
+    0xe1, 0xae, 0x2d, 0x38, 0x4a, 0xeb, 0x4a, 0xd7, 0x44, 0xda, 0x30, 0xd4,
+    0xf7, 0xdd, 0xd1, 0xd6, 0x8c, 0x3c, 0xf2, 0x2c, 0x9f, 0xf1, 0x6a, 0xb8,
+    0xce, 0x5c, 0x8e, 0xb4, 0xf8, 0x43, 0x2c, 0xba, 0xd3, 0xff, 0x65, 0xb4,
+    0x0c, 0xee, 0xa8, 0x17, 0x5a, 0x7f, 0xd7, 0xad, 0x98, 0x6b, 0xdc, 0x0d,
+    0x68, 0x24, 0x53, 0x89, 0x37, 0x10, 0xe7, 0x1d, 0xb4, 0xb4, 0xf0, 0xfb,
+    0xe0, 0x35, 0xa7, 0xec, 0xbd, 0xb4, 0x36, 0x2d, 0x18, 0x7d, 0xb4, 0x36,
+    0x24, 0xb3, 0xed, 0xc3, 0xbf, 0xac, 0xb4, 0x62, 0x3c, 0x4a, 0x13, 0x7a,
+    0x2c, 0x9f, 0xff, 0xfd, 0xa6, 0x2f, 0xfd, 0x82, 0xe1, 0x0e, 0xef, 0xcb,
+    0xfb, 0xbd, 0x7d, 0xeb, 0x4f, 0xac, 0xf7, 0xe5, 0x6a, 0xd3, 0xf7, 0xb5,
+    0xf0, 0x79, 0x62, 0xd3, 0xfe, 0x12, 0x7f, 0x35, 0x9f, 0x2b, 0xad, 0x3f,
+    0xea, 0xc0, 0x30, 0xd7, 0xb8, 0x1a, 0xd0, 0xf3, 0xf8, 0x01, 0xe4, 0xfe,
+    0xad, 0xaf, 0xce, 0x67, 0x9d, 0x69, 0xff, 0xcd, 0x9b, 0x73, 0x4d, 0xc1,
+    0x60, 0x5d, 0x69, 0xd7, 0xd1, 0xd6, 0x8e, 0x1f, 0x26, 0xe9, 0x13, 0xf6,
+    0xf7, 0xe5, 0xf3, 0x8b, 0x4e, 0xb6, 0xdb, 0x52, 0x9f, 0xfd, 0xc2, 0xe5,
+    0xf4, 0x5e, 0x41, 0x7d, 0x9e, 0x91, 0x8b, 0xf8, 0x24, 0x54, 0xee, 0x9b,
+    0x0f, 0x55, 0xef, 0x8f, 0x24, 0x55, 0xf8, 0x54, 0x1c, 0x88, 0x61, 0x37,
+    0xc8, 0x66, 0x4f, 0xf6, 0xcf, 0xbd, 0xf3, 0xda, 0xe2, 0xd2, 0xc5, 0xa1,
+    0x8f, 0x24, 0x33, 0xa9, 0xff, 0xfe, 0x21, 0xae, 0x16, 0xa8, 0xfe, 0x32,
+    0xed, 0x9f, 0xc1, 0x5a, 0x7b, 0x8d, 0xb5, 0xab, 0x46, 0x91, 0x0b, 0x6b,
+    0x14, 0xee, 0xdb, 0xa5, 0xa7, 0xf3, 0x57, 0xf5, 0x6d, 0x7a, 0x94, 0xd6,
+    0xda, 0x94, 0x7a, 0x79, 0x76, 0x99, 0xce, 0xe1, 0x79, 0xd2, 0x31, 0xa4,
+    0x9e, 0xdd, 0xfb, 0xf1, 0x68, 0xb9, 0xe9, 0xf9, 0x17, 0xcd, 0x6d, 0xd6,
+    0x96, 0x2d, 0x2d, 0xb0, 0xd3, 0x70, 0x5e, 0x7f, 0xeb, 0xdf, 0xd1, 0x6f,
+    0x74, 0xdc, 0xba, 0xd0, 0xc7, 0xd9, 0xb9, 0x3c, 0xff, 0xb8, 0x5f, 0xa0,
+    0x3a, 0xf3, 0x34, 0xb4, 0xff, 0x15, 0xa3, 0x9c, 0x2d, 0xc0, 0xb4, 0xfe,
+    0xaf, 0xf2, 0xe2, 0x41, 0xad, 0x0f, 0x46, 0x61, 0x11, 0x79, 0xd0, 0x28,
+    0xe2, 0x76, 0x17, 0xd6, 0x9e, 0xaf, 0xb3, 0xd6, 0x8b, 0x0d, 0xd1, 0xc6,
+    0xa7, 0xfc, 0xdb, 0x69, 0x8f, 0xdd, 0x13, 0x8b, 0x46, 0x1f, 0x0f, 0xc8,
+    0xa7, 0xee, 0x37, 0xfd, 0xc1, 0x5a, 0x7f, 0x7b, 0xa6, 0x1b, 0x6b, 0x65,
+    0xa7, 0xfe, 0x2f, 0x74, 0xdd, 0x60, 0x50, 0x81, 0x69, 0xff, 0xff, 0x11,
+    0xe8, 0x76, 0x79, 0xad, 0xc2, 0x77, 0x83, 0x9e, 0xd3, 0xd7, 0x17, 0xac,
+    0x32, 0x63, 0x74, 0x59, 0x73, 0x4d, 0xd0, 0xa7, 0xff, 0xb3, 0x97, 0xc7,
+    0x34, 0xce, 0xf3, 0x5a, 0x65, 0xa7, 0xff, 0xff, 0xc5, 0x9b, 0x5c, 0xb2,
+    0xdf, 0x19, 0xb3, 0xee, 0x5c, 0xb9, 0x6d, 0xef, 0xbb, 0xd8, 0xb4, 0xff,
+    0xf8, 0x87, 0xdf, 0x01, 0x70, 0xaf, 0x44, 0x3b, 0xbd, 0x68, 0x14, 0xcc,
+    0xb8, 0xa0, 0xee, 0x11, 0x73, 0xfa, 0xca, 0xe0, 0x02, 0x17, 0xad, 0x35,
+    0x7a, 0xb4, 0xfd, 0xfa, 0xbe, 0xa9, 0xeb, 0x4b, 0x65, 0xa6, 0x2b, 0x56,
+    0x98, 0x20, 0x2d, 0x0e, 0x1a, 0xd0, 0x0b, 0x4e, 0x7d, 0x7a, 0xb4, 0xd6,
+    0xda, 0xb4, 0x3d, 0x1a, 0xd8, 0x2d, 0xd2, 0xc2, 0x3e, 0xb9, 0x15, 0xa3,
+    0x93, 0xb8, 0x10, 0x12, 0x31, 0xeb, 0x4f, 0xff, 0xfe, 0xe3, 0x7b, 0xad,
+    0xe8, 0x33, 0xd7, 0xb9, 0x82, 0x1d, 0xef, 0x82, 0x05, 0xa3, 0x64, 0x53,
+    0x91, 0x74, 0xff, 0x67, 0x34, 0xdf, 0xe6, 0x75, 0x69, 0xcd, 0xf7, 0x16,
+    0x8c, 0x55, 0x68, 0x46, 0xf5, 0x28, 0x1c, 0x48, 0xfc, 0x8d, 0xe7, 0x5e,
+    0x9c, 0x5a, 0x7b, 0x39, 0x4e, 0xab, 0x46, 0xc6, 0xfc, 0x47, 0x27, 0xfe,
+    0xcf, 0xff, 0x1c, 0xd6, 0x5e, 0x85, 0x69, 0xfc, 0x2d, 0xfd, 0xfb, 0xa6,
+    0x5a, 0x7c, 0x41, 0xea, 0x9e, 0xb4, 0xfc, 0x4c, 0x7b, 0x32, 0xd5, 0xa6,
+    0xb6, 0xd5, 0xa3, 0xa7, 0xd9, 0xf2, 0x7b, 0x4b, 0x67, 0xfb, 0x1c, 0xa7,
+    0x2b, 0x67, 0xdd, 0x23, 0x1b, 0x09, 0xde, 0xb1, 0xd6, 0x9f, 0xd8, 0x0c,
+    0x71, 0xb6, 0xba, 0xd0, 0xc7, 0x9f, 0x83, 0x93, 0xff, 0xb0, 0x41, 0x9a,
+    0x2d, 0xaf, 0xad, 0xee, 0xb4, 0xfc, 0x34, 0x0f, 0x70, 0x56, 0x9f, 0x8e,
+    0x5e, 0x59, 0xf0, 0xd6, 0x9d, 0x6d, 0xb6, 0xa5, 0x3f, 0xf3, 0x7c, 0x77,
+    0xa0, 0xb1, 0xc6, 0x3a, 0xc6, 0x2f, 0xe3, 0xce, 0xaa, 0x79, 0xc8, 0x67,
+    0x0c, 0x26, 0x6e, 0x41, 0xc4, 0xad, 0xca, 0xed, 0x4f, 0x93, 0xa0, 0xb4,
+    0x89, 0x69, 0xfe, 0xe3, 0x7e, 0xfa, 0x61, 0xe2, 0xd2, 0x74, 0x16, 0x9f,
+    0xee, 0x37, 0xef, 0xa6, 0x1e, 0x2d, 0x35, 0xd9, 0x69, 0xc7, 0xf5, 0x96,
+    0x9f, 0xc3, 0xca, 0x72, 0xed, 0xc5, 0xa0, 0x8f, 0x3a, 0x87, 0x27, 0x8a,
+    0xb3, 0xab, 0x4f, 0xfb, 0x1d, 0x8e, 0x5d, 0xc1, 0x6f, 0x56, 0x9e, 0xef,
+    0xad, 0x62, 0xd3, 0x01, 0x96, 0x9d, 0x72, 0xfa, 0xd1, 0x87, 0xa6, 0x02,
+    0x3e, 0x0a, 0xcf, 0xe7, 0xe0, 0x97, 0xb8, 0x2b, 0x4e, 0xe5, 0xcc, 0xc9,
+    0xef, 0x60, 0xab, 0x86, 0xfa, 0x63, 0x01, 0x00, 0x8f, 0xde, 0x12, 0x5c,
+    0x2e, 0x9a, 0xec, 0xb4, 0xe3, 0xfa, 0xcb, 0x4f, 0xe1, 0xe5, 0x39, 0x76,
+    0xe2, 0xd0, 0x47, 0x9d, 0x43, 0x93, 0xc5, 0x59, 0xd5, 0xa7, 0xfd, 0x8e,
+    0xc7, 0x2e, 0xe0, 0xb7, 0xab, 0x4f, 0x77, 0xd6, 0xb1, 0x69, 0xf9, 0xc0,
+    0x17, 0x9e, 0x9c, 0x5a, 0x60, 0x32, 0xd3, 0xae, 0x5f, 0x5a, 0x31, 0x10,
+    0xbd, 0x23, 0x01, 0x97, 0x05, 0x67, 0xf3, 0xf0, 0x4b, 0xdc, 0x15, 0xa7,
+    0xe1, 0xaf, 0x70, 0x33, 0x32, 0xe4, 0x97, 0xa2, 0xb8, 0x1f, 0xd9, 0x42,
+    0xae, 0x42, 0x1f, 0x4c, 0x60, 0x20, 0x11, 0xfb, 0xc3, 0x13, 0x87, 0x93,
+    0xff, 0xea, 0xf7, 0x30, 0x43, 0x08, 0x58, 0x6c, 0x2f, 0xad, 0x3a, 0xbf,
+    0x62, 0xe4, 0x12, 0x9e, 0x7e, 0x6c, 0xf5, 0xc8, 0x25, 0x3a, 0xe5, 0xea,
+    0xe4, 0x12, 0x9a, 0xdb, 0x57, 0x20, 0x94, 0x75, 0x14, 0xce, 0x14, 0xf0,
+    0xbe, 0xd2, 0x99, 0xab, 0x89, 0x90, 0x48, 0x63, 0x7f, 0x3f, 0x66, 0xb3,
+    0x04, 0x35, 0xa7, 0x50, 0x81, 0x95, 0x2c, 0x1e, 0x18, 0x23, 0x19, 0xcf,
+    0x0c, 0xe7, 0xbc, 0xb2, 0xb4, 0xb4, 0xb3, 0xce, 0x7f, 0x60, 0x58, 0x9f,
+    0xce, 0x3f, 0x7b, 0x38, 0x56, 0x25, 0x3f, 0x89, 0xfb, 0xd5, 0xf4, 0x4b,
+    0x49, 0xe9, 0x4e, 0xaf, 0xd8, 0x94, 0x25, 0x0c, 0x6d, 0xba, 0x20, 0x71,
+    0xc9, 0xe1, 0x60, 0x75, 0x23, 0x1a, 0xd8, 0x64, 0x62, 0xe4, 0x25, 0x67,
+    0xb7, 0xaf, 0xbd, 0x69, 0x1d, 0x69, 0xb1, 0xfe, 0x9b, 0x27, 0x08, 0xa7,
+    0xd6, 0xe3, 0x84, 0x75, 0xa7, 0xee, 0xb3, 0x8f, 0x60, 0x25, 0x22, 0x5a,
+    0x7f, 0xac, 0xdd, 0xfe, 0xeb, 0x7a, 0x15, 0xa7, 0xe2, 0x63, 0xd9, 0x96,
+    0xad, 0x3e, 0xcb, 0x0f, 0x87, 0x5a, 0x75, 0xcb, 0xeb, 0x40, 0x9e, 0x17,
+    0x09, 0xe7, 0xe1, 0xa0, 0x03, 0x7b, 0xad, 0x3f, 0x10, 0x61, 0x31, 0xcd,
+    0xea, 0x61, 0x18, 0x1f, 0xf3, 0xcb, 0xb7, 0xf0, 0x86, 0x31, 0x3c, 0xc2,
+    0x28, 0x18, 0xcd, 0x67, 0x87, 0x2c, 0xdd, 0x68, 0x7a, 0xbc, 0xfc, 0x2b,
+    0xd4, 0x3f, 0x05, 0x62, 0xf1, 0xfd, 0x70, 0xd2, 0x7f, 0xfd, 0x67, 0xff,
+    0x9e, 0xd1, 0xf5, 0x5c, 0x16, 0x71, 0x69, 0xff, 0xff, 0xdb, 0xff, 0x77,
+    0x06, 0x81, 0x7b, 0xe0, 0x79, 0xbf, 0xeb, 0xd6, 0xd3, 0x2d, 0x3a, 0xdb,
+    0x6d, 0x4a, 0x67, 0xb2, 0x46, 0x2f, 0xe1, 0x93, 0x14, 0xb1, 0x5b, 0xf0,
+    0x9a, 0x9f, 0xac, 0x71, 0xfe, 0x67, 0xec, 0x5a, 0x7b, 0x55, 0xb5, 0xab,
+    0x4f, 0xac, 0xf9, 0x31, 0xd6, 0x9f, 0xfe, 0x60, 0xb8, 0x2c, 0x0a, 0xe0,
+    0x02, 0x17, 0xad, 0x1e, 0x6d, 0x19, 0xe4, 0x6d, 0x44, 0x7c, 0x27, 0x9c,
+    0x17, 0xae, 0x2d, 0x39, 0xe4, 0x2b, 0x4f, 0xdc, 0x67, 0x07, 0x7b, 0xad,
+    0x16, 0x1f, 0x3b, 0xc7, 0xf8, 0x35, 0x35, 0x5d, 0x69, 0xb7, 0x74, 0x16,
+    0x81, 0x36, 0x3b, 0x8a, 0xcd, 0x46, 0x74, 0x9d, 0x33, 0x9b, 0xa7, 0x35,
+    0xf3, 0x51, 0x1b, 0x4a, 0xf3, 0xb2, 0x30, 0x77, 0x90, 0x7b, 0x1e, 0xae,
+    0x4b, 0x2a, 0x0e, 0x17, 0x7d, 0x85, 0x3e, 0xc4, 0x85, 0x0d, 0xf7, 0x23,
+    0x83, 0xfc, 0x36, 0x8f, 0x19, 0xe6, 0xa7, 0x08, 0xea, 0x12, 0x22, 0x43,
+    0x79, 0x5c, 0x1c, 0xa5, 0xd5, 0x6f, 0x1b, 0xb7, 0x94, 0x60, 0xa1, 0x42,
+    0xa1, 0xd5, 0x86, 0x7f, 0xf1, 0x8f, 0x4f, 0x36, 0x7f, 0xb5, 0x5d, 0x54,
+    0x51, 0x53, 0xf8, 0xd9, 0xfe, 0xd5, 0x75, 0x51, 0x74, 0x4f, 0xfc, 0x6a,
+    0x79, 0xb3, 0xfd, 0xaa, 0xea, 0xa2, 0x4b, 0x9f, 0xc6, 0xcf, 0xf6, 0xab,
+    0xaa, 0x8b, 0xca, 0x19, 0xd5, 0xe4, 0x58, 0x4e, 0xf3, 0xec, 0x3e, 0xea,
+    0xab, 0x87, 0xc7, 0x3e, 0xd4, 0x32, 0x86, 0xd3, 0x4a, 0xde, 0x3d, 0x5e,
+    0x2a, 0xee, 0x7c, 0xed, 0x3e, 0x7f, 0xf1, 0x8f, 0x4f, 0x36, 0x7f, 0xb5,
+    0x5d, 0x54, 0x4b, 0x33, 0x6f, 0xa5, 0xa7, 0xbb, 0x55, 0xd5, 0x44, 0x67,
+    0x3f, 0x13, 0x1e, 0xcc, 0xb5, 0x69, 0x85, 0xeb, 0x48, 0xeb, 0x4f, 0x8b,
+    0xfa, 0xa3, 0x7c, 0xf4, 0x8e, 0x5a, 0x10, 0xac, 0xfd, 0x4f, 0x2f, 0xd7,
+    0xd6, 0x9f, 0xfa, 0xe5, 0xbd, 0xf0, 0x77, 0x7e, 0x5d, 0x69, 0xd7, 0x6d,
+    0x96, 0x8f, 0xa6, 0xac, 0x77, 0xf1, 0x4c, 0xb9, 0x5f, 0x11, 0x27, 0xf9,
+    0xf7, 0xc6, 0xf0, 0xd7, 0x3a, 0xd3, 0xff, 0x70, 0xbf, 0x40, 0xf1, 0xb3,
+    0xd8, 0xeb, 0x4f, 0x85, 0x9f, 0x7a, 0x5a, 0x08, 0xfa, 0xdd, 0xa3, 0x4e,
+    0xa0, 0x9e, 0xb4, 0xff, 0xf6, 0xfc, 0xbe, 0xcf, 0x61, 0x05, 0xfc, 0x6e,
+    0x2b, 0x4e, 0x6e, 0x32, 0xd2, 0x2f, 0x4f, 0xb9, 0xda, 0xa4, 0xda, 0x71,
+    0x69, 0xfd, 0xb5, 0xc7, 0x3f, 0xeb, 0x2d, 0x04, 0x79, 0x54, 0x2f, 0x3d,
+    0xcd, 0x6f, 0xe4, 0xb4, 0xff, 0x70, 0xad, 0xbb, 0x6a, 0xbc, 0xeb, 0x4b,
+    0x08, 0xf8, 0x8e, 0x4d, 0x3f, 0xed, 0x31, 0x68, 0x98, 0x5c, 0xdd, 0x69,
+    0xfd, 0x97, 0x6e, 0x5f, 0x44, 0xb4, 0x8c, 0xe9, 0x2e, 0x49, 0x64, 0x6d,
+    0xbb, 0x25, 0x39, 0x0a, 0x4d, 0x11, 0xd4, 0x22, 0x80, 0xe8, 0x30, 0x82,
+    0xb9, 0x37, 0x91, 0xec, 0xff, 0xe3, 0x1e, 0x9e, 0x6c, 0xff, 0x6a, 0xba,
+    0xa8, 0x9a, 0x67, 0xff, 0x18, 0xf4, 0xf3, 0x67, 0xfb, 0x55, 0xd5, 0x44,
+    0xe3, 0x3f, 0xf8, 0xc7, 0xa7, 0x9b, 0x3f, 0xda, 0xae, 0xaa, 0x28, 0x19,
+    0xf7, 0xfb, 0x55, 0xd5, 0x45, 0xc1, 0x33, 0x12, 0xd3, 0xf8, 0x5e, 0xc5,
+    0xee, 0x1d, 0x69, 0x1b, 0x0f, 0xe3, 0x46, 0x7b, 0x8a, 0x4f, 0xe2, 0x30,
+    0x4c, 0x0c, 0xb5, 0x69, 0xfe, 0x79, 0xb3, 0xfd, 0xaa, 0xea, 0xa2, 0x49,
+    0x91, 0xb4, 0x7e, 0xf4, 0x67, 0x3e, 0xa3, 0x7b, 0x68, 0x16, 0x8b, 0x19,
+    0x01, 0x4f, 0x9c, 0xe7, 0xec, 0x2c, 0x1c, 0x55, 0x02, 0xad, 0xe1, 0x9b,
+    0xc8, 0x56, 0x3b, 0x27, 0x9f, 0xf0, 0x74, 0x6c, 0xff, 0x6a, 0xba, 0xa8,
+    0xb5, 0x27, 0xfd, 0x4f, 0x36, 0x7f, 0xb5, 0x5d, 0x54, 0x4a, 0xb0, 0xb4,
+    0x8c, 0x1a, 0x27, 0x4e, 0x94, 0xea, 0x93, 0x3f, 0x8d, 0x9f, 0xed, 0x57,
+    0x55, 0x11, 0x4c, 0xfe, 0x36, 0x7f, 0xb5, 0x5d, 0x54, 0x46, 0x93, 0x6f,
+    0xa5, 0xa7, 0xbb, 0x55, 0xd5, 0x45, 0x3f, 0x37, 0x19, 0x68, 0xf9, 0xe1,
+    0x70, 0xb6, 0x7f, 0xdc, 0x71, 0xb9, 0xaa, 0x73, 0xc6, 0x2d, 0x3f, 0xf6,
+    0xfc, 0xfe, 0xee, 0x5f, 0xb4, 0xe5, 0xd6, 0x9f, 0xfb, 0x1c, 0xdc, 0x6c,
+    0xbf, 0x69, 0xcb, 0xad, 0x23, 0x3a, 0x49, 0xa6, 0x62, 0xc9, 0x11, 0x0a,
+    0x0f, 0x12, 0x67, 0xff, 0x18, 0xf4, 0xf3, 0x67, 0xfb, 0x55, 0xd5, 0x44,
+    0xd5, 0x3f, 0x8d, 0x9f, 0xed, 0x57, 0x55, 0x15, 0xdc, 0xf7, 0x6a, 0xba,
+    0xa8, 0xaf, 0xa7, 0x5b, 0x6d, 0xa9, 0x48, 0x52, 0x31, 0x7f, 0x1f, 0x3e,
+    0xa3, 0xa6, 0x4e, 0x7b, 0x6c, 0xb4, 0xe7, 0x33, 0x4b, 0x4f, 0xfb, 0x35,
+    0x6d, 0x72, 0xed, 0x96, 0x2d, 0x2e, 0x2d, 0x3f, 0xc5, 0xfc, 0xb0, 0x9f,
+    0x9e, 0xad, 0x1f, 0x3c, 0x8a, 0x10, 0x91, 0xb1, 0x30, 0x17, 0x08, 0xa8,
+    0x70, 0x47, 0x2f, 0x08, 0x69, 0xff, 0xc6, 0x3d, 0x3c, 0xd9, 0xfe, 0xd5,
+    0x75, 0x51, 0x3d, 0xcf, 0xe3, 0x67, 0xfb, 0x55, 0xd5, 0x45, 0xc3, 0x3f,
+    0xf1, 0xa9, 0xe6, 0xcf, 0xf6, 0xab, 0xaa, 0x89, 0x3e, 0x19, 0x76, 0x26,
+    0xc3, 0xa7, 0x9f, 0x07, 0x1c, 0x57, 0x54, 0xdc, 0x55, 0xfc, 0x75, 0x3a,
+    0x54, 0xba, 0xab, 0xb3, 0xe9, 0xfc, 0x6c, 0xff, 0x6a, 0xba, 0xa8, 0x8a,
+    0xa7, 0xdf, 0xed, 0x57, 0x55, 0x14, 0xcc, 0xfc, 0x5a, 0xca, 0xd8, 0x0b,
+    0x48, 0xd8, 0x7b, 0xfe, 0x46, 0x73, 0xff, 0x8c, 0x7a, 0x79, 0xb3, 0xfd,
+    0xaa, 0xea, 0xa2, 0x67, 0x9f, 0xfc, 0x63, 0xd3, 0xcd, 0x9f, 0xed, 0x57,
+    0x55, 0x14, 0x6c, 0x58, 0x9b, 0x8f, 0xb0, 0x9d, 0x0c, 0xab, 0x8a, 0xb3,
+    0xff, 0x1a, 0x9e, 0x6c, 0xff, 0x6a, 0xba, 0xa8, 0x8e, 0xa6, 0xdf, 0x4b,
+    0x4f, 0xc5, 0x83, 0xee, 0x58, 0xb4, 0xf7, 0x6a, 0xba, 0xa8, 0xa6, 0xa7,
+    0xd9, 0xb5, 0xb5, 0xa5, 0xa3, 0xe7, 0xaa, 0x25, 0xb3, 0xff, 0xb4, 0x5c,
+    0xbd, 0x6d, 0x8e, 0x36, 0xae, 0xb4, 0xff, 0xcf, 0xd1, 0x0d, 0x97, 0xdd,
+    0xbe, 0xe2, 0xd3, 0x30, 0x6b, 0x4f, 0xc4, 0xc7, 0xb3, 0x2d, 0x5a, 0x7f,
+    0xfb, 0x39, 0xac, 0x7f, 0xe8, 0x79, 0xaa, 0x7a, 0xd3, 0x30, 0x16, 0x9f,
+    0xd5, 0xb3, 0x74, 0xba, 0x6f, 0xa2, 0x3c, 0x4b, 0x42, 0x4d, 0x8d, 0x23,
+    0xf6, 0xf0, 0xa5, 0x91, 0x9d, 0x25, 0x4d, 0xde, 0x8b, 0xe4, 0x20, 0x7a,
+    0x43, 0xb2, 0x57, 0x23, 0x43, 0x9f, 0x7f, 0xb5, 0x5d, 0x54, 0x55, 0x53,
+    0xfe, 0xa7, 0x9b, 0x3f, 0xda, 0xae, 0xaa, 0x26, 0xd9, 0x1b, 0x0f, 0xf0,
+    0xe6, 0x73, 0xf8, 0xd9, 0xfe, 0xd5, 0x75, 0x51, 0x5f, 0xcf, 0xe3, 0x67,
+    0xfb, 0x55, 0xd5, 0x45, 0x8d, 0x3f, 0xd9, 0xce, 0x67, 0xfd, 0xc1, 0x5a,
+    0x70, 0x6f, 0xc5, 0xa7, 0x17, 0xcc, 0x27, 0xa7, 0x73, 0x79, 0xf7, 0xfb,
+    0x55, 0xd5, 0x45, 0xab, 0x3f, 0xea, 0x79, 0xb3, 0xfd, 0xaa, 0xea, 0xa2,
+    0x82, 0x91, 0xb0, 0xff, 0x0e, 0x67, 0x3e, 0xff, 0x6a, 0xba, 0xa8, 0xb8,
+    0xa7, 0xa9, 0xd4, 0xac, 0x5a, 0x79, 0xd5, 0xd4, 0xba, 0xb4, 0xfe, 0x63,
+    0xd3, 0xb6, 0xfb, 0xaa, 0xd2, 0x36, 0x22, 0xd3, 0x46, 0x74, 0x49, 0xc2,
+    0x79, 0xf7, 0xfb, 0x55, 0xd5, 0x45, 0xd3, 0x3e, 0x61, 0xaf, 0x59, 0x69,
+    0x1b, 0x0f, 0x60, 0x8c, 0xe7, 0xff, 0xb0, 0x78, 0x47, 0xd3, 0x10, 0xd7,
+    0xc3, 0x5a, 0x7f, 0xfe, 0x39, 0xb1, 0xed, 0xf0, 0x78, 0xbe, 0x98, 0xf4,
+    0x2b, 0x4f, 0x65, 0xbe, 0x6c, 0xeb, 0x4f, 0xff, 0xda, 0x1d, 0xeb, 0xcf,
+    0x8f, 0xd6, 0x07, 0x9e, 0xb9, 0xba, 0xd3, 0x77, 0x16, 0x86, 0x3f, 0x70,
+    0xd8, 0xa7, 0xfc, 0xfc, 0xff, 0xe9, 0xf6, 0x65, 0xab, 0x4e, 0x1a, 0x37,
+    0xcf, 0x87, 0x84, 0x53, 0xfe, 0xfb, 0x6d, 0xaa, 0xbf, 0x1a, 0xd5, 0xa6,
+    0xdf, 0x4b, 0x4f, 0x87, 0x35, 0x5c, 0x5a, 0x7e, 0x7d, 0x63, 0xb6, 0xf5,
+    0x68, 0x74, 0x4f, 0x4f, 0xcd, 0x24, 0xb3, 0xf0, 0x29, 0xc7, 0x97, 0x16,
+    0x9f, 0xff, 0xe6, 0xf7, 0x59, 0xb7, 0x06, 0xb4, 0x0a, 0xbd, 0xeb, 0xfd,
+    0x5a, 0x7f, 0x66, 0x60, 0x61, 0xd3, 0xd6, 0x80, 0xd1, 0x31, 0xc6, 0x69,
+    0xff, 0xfe, 0xd3, 0x0e, 0xf7, 0xd1, 0x5f, 0x9a, 0xcf, 0x4a, 0xf8, 0x2b,
+    0x4f, 0x76, 0xab, 0xaa, 0x89, 0x32, 0x7d, 0xdf, 0x35, 0xf9, 0x9e, 0x6d,
+    0xd1, 0x5a, 0x7f, 0x66, 0xdc, 0xe5, 0x3e, 0xeb, 0x43, 0x1f, 0x9f, 0xd0,
+    0x21, 0xe9, 0x93, 0x7d, 0x94, 0xf0, 0xa0, 0x9f, 0xbd, 0x03, 0xa3, 0x70,
+    0x79, 0x2d, 0x3f, 0xfb, 0x45, 0xcd, 0xba, 0x5f, 0xbb, 0x8d, 0x4b, 0x4f,
+    0xb3, 0x84, 0x7a, 0x5a, 0x7f, 0x9b, 0x5c, 0x2b, 0x0e, 0xdd, 0x5a, 0x7f,
+    0xfd, 0x5d, 0xfb, 0x68, 0x73, 0x98, 0x6b, 0x6d, 0xb5, 0x28, 0x7a, 0x2c,
+    0xee, 0x4b, 0xc3, 0x89, 0xfb, 0xbd, 0xdf, 0xa2, 0xcb, 0x4f, 0xfe, 0xdc,
+    0x6b, 0x8d, 0xfb, 0xe9, 0x87, 0x8b, 0x4e, 0xb6, 0xdb, 0x52, 0x9f, 0xbf,
+    0x56, 0x1c, 0xae, 0x91, 0x8b, 0xf9, 0xf6, 0x1f, 0xf9, 0xe7, 0x5a, 0x7c,
+    0x5c, 0xb3, 0x2d, 0x5a, 0x7f, 0x9b, 0xba, 0x1d, 0xf8, 0xd7, 0x5a, 0x7f,
+    0xfd, 0xcd, 0x63, 0xfc, 0x77, 0x45, 0xcd, 0xba, 0x5f, 0x5a, 0x3e, 0x8b,
+    0x83, 0x94, 0x09, 0xc4, 0xff, 0x65, 0x03, 0xc6, 0x7b, 0x4f, 0x5a, 0x7f,
+    0xbc, 0x0f, 0x8b, 0xd9, 0x55, 0xa5, 0xa7, 0xff, 0x55, 0x9a, 0x26, 0x1c,
+    0x70, 0xbe, 0x4b, 0x46, 0x23, 0xaf, 0x85, 0xfb, 0x9c, 0xda, 0x79, 0x3e,
+    0x1c, 0xd5, 0x71, 0x69, 0xff, 0x3d, 0x86, 0xc0, 0xbe, 0x3b, 0xbd, 0x68,
+    0xf3, 0x9f, 0x2b, 0x84, 0xb3, 0xdc, 0xb3, 0x3d, 0x5a, 0x7f, 0x88, 0x30,
+    0xbe, 0x03, 0x95, 0xd6, 0x87, 0x0f, 0x77, 0xc8, 0x8e, 0x75, 0xb6, 0xda,
+    0xb4, 0xff, 0xfb, 0x0f, 0xc1, 0x60, 0x67, 0xb7, 0xc3, 0xb7, 0x52, 0x31,
+    0x7f, 0x18, 0x99, 0x59, 0x42, 0x13, 0x48, 0xb2, 0x25, 0xa7, 0xed, 0x37,
+    0x8e, 0x95, 0x8b, 0x4f, 0xdf, 0xaf, 0x8b, 0x3d, 0x68, 0x74, 0xe7, 0xd3,
+    0xe8, 0x7f, 0xcb, 0xe6, 0x79, 0x9d, 0x26, 0x4c, 0x07, 0x98, 0xd4, 0xc5,
+    0xef, 0x86, 0x2e, 0x46, 0x94, 0x19, 0xb7, 0x4d, 0xf6, 0x87, 0xe9, 0x18,
+    0x38, 0x5b, 0x4c, 0xe2, 0x79, 0x78, 0xf3, 0x79, 0x1e, 0x70, 0x50, 0x9d,
+    0x9f, 0xfd, 0xfc, 0xb7, 0xdd, 0x63, 0x83, 0x9f, 0x7a, 0xd3, 0xbf, 0x9e,
+    0x75, 0xa5, 0x9f, 0x3e, 0xa3, 0xa5, 0xcf, 0xfd, 0x9a, 0x16, 0xb0, 0x2d,
+    0x6a, 0xbc, 0xeb, 0x4f, 0xd5, 0xd3, 0x5b, 0x6d, 0xab, 0x48, 0xcc, 0xcd,
+    0xa7, 0xc4, 0xc0, 0xd6, 0xfb, 0x18, 0x07, 0xcc, 0xaa, 0x93, 0x7e, 0x31,
+    0xb8, 0x5c, 0x9d, 0xda, 0x44, 0x3d, 0xb5, 0x2a, 0xf6, 0x55, 0xee, 0xd0,
+    0xec, 0xf9, 0x39, 0xcf, 0xb5, 0x09, 0x10, 0x42, 0xba, 0xf0, 0xdb, 0xe4,
+    0x26, 0x77, 0xa6, 0xe6, 0xcf, 0xe3, 0x67, 0xfb, 0x55, 0xd5, 0x44, 0x6b,
+    0x3e, 0xff, 0x6a, 0xba, 0xa8, 0xa9, 0x66, 0xae, 0xaa, 0x21, 0xa9, 0x1b,
+    0x0f, 0x56, 0x8c, 0xe7, 0xfe, 0x35, 0x3c, 0xd9, 0xfe, 0xd5, 0x75, 0x51,
+    0x1f, 0x4f, 0xbf, 0xda, 0xae, 0xaa, 0x2c, 0x79, 0xfe, 0x1a, 0x0f, 0x44,
+    0xc3, 0x62, 0xd2, 0x36, 0x1f, 0x53, 0x86, 0x73, 0xbc, 0xd6, 0x70, 0xd6,
+    0x9f, 0x9d, 0x11, 0xcd, 0x57, 0x16, 0x9f, 0xe1, 0xa0, 0x5e, 0xb9, 0xca,
+    0x5a, 0x78, 0x07, 0x2f, 0xad, 0x3f, 0xff, 0xcd, 0xf1, 0xcf, 0x73, 0x5a,
+    0x2e, 0xe8, 0xb9, 0x7a, 0xd9, 0x68, 0x24, 0x43, 0x68, 0x86, 0x75, 0x57,
+    0x55, 0x16, 0x84, 0xff, 0xaa, 0xd7, 0x5e, 0xd7, 0xec, 0xcb, 0x56, 0x8e,
+    0x9f, 0x57, 0xc9, 0xe7, 0xff, 0xff, 0x8b, 0xfa, 0xa1, 0x26, 0xe1, 0x69,
+    0xaf, 0xac, 0xbf, 0xf3, 0xb9, 0xc5, 0xa3, 0xe8, 0x9a, 0xd1, 0x14, 0xfa,
+    0x9e, 0x34, 0x12, 0xd3, 0xf3, 0xb0, 0xb8, 0x2c, 0x05, 0xa7, 0xcd, 0xcc,
+    0xd3, 0x2d, 0x3f, 0xfd, 0x9c, 0xbe, 0x39, 0xa6, 0x77, 0x9a, 0xd3, 0x2d,
+    0x16, 0x1f, 0xa8, 0x92, 0xc3, 0x23, 0x1b, 0x21, 0x49, 0x3f, 0xe0, 0x37,
+    0x74, 0x4e, 0x55, 0x58, 0xb4, 0xff, 0x16, 0xe2, 0xff, 0xb6, 0x7a, 0xb4,
+    0xff, 0xff, 0x6b, 0x1f, 0xdd, 0x16, 0x9b, 0x3e, 0xfe, 0x0b, 0x1e, 0xeb,
+    0x4b, 0x2e, 0x89, 0xce, 0x1c, 0x4f, 0xdf, 0x6e, 0x59, 0x96, 0xad, 0x3e,
+    0xe6, 0xa8, 0x43, 0x5a, 0x7f, 0x87, 0x7b, 0x3d, 0xd6, 0x0b, 0x2d, 0x2c,
+    0xc3, 0xe0, 0xe9, 0x3c, 0x12, 0x2d, 0x06, 0x11, 0xd3, 0xfb, 0x34, 0xe1,
+    0x68, 0x8e, 0xb4, 0xfe, 0x7e, 0x7e, 0xe2, 0xd6, 0x2d, 0x3b, 0x35, 0x4b,
+    0x4f, 0x9c, 0xf7, 0x7d, 0xc5, 0x68, 0xf4, 0xf1, 0x68, 0x6a, 0x7f, 0xb3,
+    0x2d, 0xce, 0xf7, 0x2d, 0x5a, 0x31, 0x30, 0x3d, 0x8c, 0xa9, 0xde, 0xe4,
+    0x53, 0xd9, 0xaa, 0xe2, 0xd3, 0xf1, 0x0e, 0xef, 0xcb, 0xad, 0x3f, 0xff,
+    0xc4, 0x3b, 0xbf, 0x2f, 0xe3, 0x38, 0xdb, 0x02, 0xb5, 0xa2, 0x5a, 0x03,
+    0x44, 0x9f, 0x0b, 0x24, 0x67, 0x49, 0x7d, 0x7f, 0xcc, 0x25, 0x63, 0x0f,
+    0x61, 0x79, 0x91, 0x93, 0x1c, 0x8f, 0x50, 0xec, 0x01, 0x30, 0xc3, 0x6a,
+    0xf0, 0xdc, 0xe4, 0x65, 0x3e, 0x47, 0xa1, 0x42, 0xce, 0x7e, 0x75, 0x2f,
+    0x45, 0x9c, 0x5a, 0x7b, 0x35, 0x5c, 0x5a, 0x4e, 0x8e, 0x1e, 0x80, 0x98,
+    0x4f, 0xbf, 0xda, 0xae, 0xaa, 0x2d, 0x69, 0xff, 0x53, 0xcd, 0x9f, 0xed,
+    0x57, 0x55, 0x14, 0x1c, 0x8d, 0xe6, 0x22, 0x9f, 0x0a, 0xce, 0x67, 0x3f,
+    0xf8, 0xc7, 0xa7, 0x9b, 0x3f, 0xda, 0xae, 0xaa, 0x28, 0xb9, 0xfc, 0x6c,
+    0xff, 0x6a, 0xba, 0xa8, 0xba, 0xa1, 0xec, 0xba, 0x9e, 0xc2, 0x4c, 0x89,
+    0x8f, 0x0b, 0x9d, 0x4f, 0xc3, 0x82, 0x3e, 0x3b, 0x9d, 0x71, 0x56, 0x7d,
+    0xfe, 0xd5, 0x75, 0x51, 0x10, 0xce, 0xd6, 0x7a, 0xb4, 0xf6, 0x3b, 0x2f,
+    0xad, 0x23, 0x61, 0xf8, 0xec, 0x67, 0xe7, 0x1c, 0x9f, 0xc6, 0xcf, 0xf6,
+    0xab, 0xaa, 0x88, 0xda, 0x7f, 0x1b, 0x3f, 0xda, 0xae, 0xaa, 0x29, 0xb9,
+    0xfc, 0x6c, 0xff, 0x6a, 0xba, 0xa8, 0xa8, 0x27, 0xf1, 0xb3, 0xfd, 0xaa,
+    0xea, 0xa2, 0xa6, 0x9f, 0x7f, 0xb5, 0x5d, 0x54, 0x56, 0x13, 0xe2, 0xb7,
+    0xdd, 0xfe, 0xb4, 0xff, 0x3c, 0xd9, 0xfe, 0xd5, 0x75, 0x51, 0x1f, 0xce,
+    0xc6, 0xb1, 0x69, 0x1b, 0x11, 0x79, 0xd3, 0x3a, 0x2a, 0x14, 0x49, 0xff,
+    0xc6, 0x3d, 0x3c, 0xd9, 0xfe, 0xd5, 0x75, 0x51, 0x37, 0xcf, 0xfc, 0x7a,
+    0x79, 0xb3, 0xfd, 0xaa, 0xea, 0xa2, 0x7e, 0x9f, 0x79, 0xb7, 0x47, 0xcb,
+    0x36, 0x5a, 0x5a, 0x5a, 0x1d, 0x31, 0xe3, 0x6e, 0x6d, 0x3f, 0xde, 0x6a,
+    0xd5, 0x73, 0x95, 0x56, 0xad, 0x3e, 0xf0, 0x1f, 0xeb, 0xab, 0x4f, 0xbc,
+    0xc7, 0x4e, 0x00, 0xd9, 0x69, 0xff, 0xe6, 0x66, 0x66, 0x66, 0x66, 0x6d,
+    0xae, 0xb4, 0xfb, 0xe5, 0x65, 0x1d, 0x29, 0xad, 0xb5, 0x28, 0xc3, 0x7f,
+    0x69, 0x3c, 0xb7, 0x48, 0xc6, 0x86, 0x19, 0x19, 0x57, 0x85, 0x4c, 0xf7,
+    0xc4, 0x99, 0x69, 0xff, 0xfb, 0x0f, 0x7e, 0x7e, 0xac, 0xf7, 0x4d, 0x7e,
+    0x6f, 0xa5, 0xa7, 0xd5, 0xdd, 0x17, 0xd6, 0x9f, 0xff, 0xfc, 0x34, 0x19,
+    0x7d, 0x9f, 0xe3, 0x44, 0x7f, 0x5b, 0xc7, 0x96, 0xfa, 0x2f, 0xad, 0x3d,
+    0x4f, 0x2d, 0x96, 0x8f, 0x53, 0x24, 0xfa, 0xf6, 0x89, 0x85, 0xfe, 0x7f,
+    0xfc, 0xea, 0xdb, 0x3e, 0x84, 0x1e, 0x00, 0x5f, 0x20, 0xd6, 0x9e, 0xb0,
+    0xe4, 0xf5, 0xa7, 0xd7, 0x1d, 0xe9, 0xeb, 0x4f, 0xed, 0x31, 0xcc, 0x00,
+    0x32, 0xd2, 0xfb, 0x1f, 0xde, 0x11, 0x11, 0x3c, 0xff, 0x9b, 0x6f, 0x42,
+    0x6f, 0x3e, 0xb7, 0xba, 0xd3, 0xb3, 0x1c, 0x5a, 0x5e, 0x75, 0xa6, 0xbe,
+    0x2d, 0x04, 0x6a, 0x40, 0x29, 0x3f, 0xf7, 0xad, 0xca, 0xbe, 0x6b, 0x44,
+    0x75, 0xa7, 0x70, 0x9c, 0x5a, 0x18, 0xf7, 0xee, 0x87, 0x0c, 0xaf, 0x67,
+    0x09, 0xca, 0x34, 0x37, 0x0f, 0xbf, 0x0d, 0x53, 0x99, 0x01, 0x18, 0x51,
+    0x38, 0xff, 0x39, 0xc0, 0x8e, 0xb4, 0xff, 0x67, 0x2f, 0x9c, 0xd6, 0x01,
+    0x68, 0xa3, 0xd5, 0x11, 0xe9, 0xa8, 0x56, 0x8f, 0x9b, 0x43, 0x90, 0x4e,
+    0xb6, 0xdb, 0x56, 0x9e, 0xb0, 0x49, 0x92, 0x31, 0x7f, 0x36, 0xcf, 0x5a,
+    0x7f, 0x06, 0xdc, 0xbe, 0xab, 0x75, 0xa7, 0xc5, 0x66, 0x6d, 0xc5, 0xa6,
+    0x2e, 0xad, 0x2d, 0x99, 0x11, 0x01, 0x8b, 0x9c, 0xd3, 0x85, 0x10, 0xc9,
+    0x9d, 0xe9, 0x03, 0x78, 0x5b, 0xcf, 0xfd, 0x66, 0xe0, 0xc1, 0xdd, 0xc6,
+    0xe5, 0x2d, 0x3f, 0xf3, 0x68, 0x2f, 0x78, 0x58, 0xe3, 0x1d, 0x69, 0xe6,
+    0xe6, 0xe7, 0x5a, 0x6b, 0xf5, 0x51, 0x07, 0x49, 0x8e, 0x78, 0xbc, 0x22,
+    0x9f, 0xab, 0x4d, 0xe7, 0xdd, 0xeb, 0x47, 0xd3, 0x28, 0x3a, 0x37, 0x21,
+    0x14, 0xec, 0x9e, 0x6f, 0xfa, 0xb4, 0xd6, 0xda, 0xb4, 0x3c, 0xd7, 0xda,
+    0x2f, 0x3d, 0x76, 0x27, 0x69, 0x18, 0xd1, 0x4f, 0xae, 0x17, 0xa0, 0xba,
+    0xd0, 0x47, 0xb8, 0x11, 0x94, 0xeb, 0x6d, 0xb5, 0x28, 0x48, 0xc5, 0xfc,
+    0xf1, 0x5a, 0x4e, 0x25, 0x1d, 0x37, 0x64, 0x33, 0x04, 0x9c, 0x76, 0xa1,
+    0xe4, 0x2f, 0x93, 0x84, 0xae, 0xb4, 0xf7, 0xb4, 0x20, 0x5a, 0x7f, 0xe6,
+    0x10, 0x0b, 0x6c, 0xe3, 0x08, 0x16, 0x82, 0x3f, 0xd0, 0x0d, 0x5c, 0x86,
+    0x7c, 0xd9, 0xfd, 0x12, 0xd3, 0xb0, 0xfe, 0x75, 0xa7, 0xf6, 0x5c, 0x73,
+    0x9a, 0x25, 0xa3, 0xd3, 0xcf, 0x11, 0xf8, 0x71, 0x12, 0xce, 0xdd, 0x27,
+    0xee, 0x63, 0x82, 0xc7, 0x5c, 0x40, 0x53, 0xea, 0x1f, 0x74, 0xca, 0x88,
+    0x08, 0xc6, 0xe6, 0x7e, 0xfb, 0x3e, 0xb6, 0xb5, 0x69, 0xfe, 0x6f, 0xd9,
+    0xe3, 0x1c, 0x23, 0xad, 0x3c, 0x76, 0xc3, 0xad, 0x3e, 0x60, 0x16, 0xd7,
+    0x5a, 0x7f, 0x7d, 0xcb, 0x90, 0xf0, 0x96, 0x9e, 0xd8, 0x1f, 0x64, 0xa6,
+    0xb6, 0xd4, 0xa1, 0x8d, 0xd5, 0xa4, 0x53, 0xf5, 0x7d, 0xef, 0x12, 0x48,
+    0xc6, 0x86, 0x19, 0x56, 0xf6, 0x43, 0x10, 0x97, 0xfe, 0x87, 0xa2, 0xea,
+    0x3b, 0x12, 0x0e, 0x13, 0xef, 0x08, 0xd9, 0xf6, 0xfc, 0xde, 0x82, 0x54,
+    0x40, 0xf3, 0x36, 0xeb, 0x4f, 0xb7, 0x10, 0x04, 0xf5, 0xa7, 0xff, 0xce,
+    0xc7, 0x2f, 0xe0, 0x2d, 0x30, 0x0f, 0x4f, 0xf1, 0x86, 0xfe, 0xe2, 0xd3,
+    0xfe, 0xd6, 0xf6, 0x37, 0x86, 0xe3, 0x7a, 0xb4, 0xea, 0xfd, 0x8b, 0x4d,
+    0x6d, 0xab, 0x4f, 0xef, 0x96, 0x3b, 0x09, 0xe6, 0xe9, 0xb4, 0xb4, 0x72,
+    0x3d, 0x46, 0x1f, 0xdd, 0xa7, 0xfe, 0x1c, 0x0f, 0x54, 0xf0, 0xab, 0x66,
+    0x5a, 0x18, 0xfa, 0x30, 0x92, 0x7f, 0xf6, 0x1c, 0xf4, 0xfc, 0xff, 0x6a,
+    0xba, 0xa8, 0x86, 0x20, 0x95, 0x08, 0x6a, 0x39, 0xc1, 0x20, 0x9f, 0x7f,
+    0xb5, 0x5d, 0x54, 0x41, 0x53, 0xb4, 0xc7, 0x5a, 0x30, 0xf3, 0x88, 0xce,
+    0x7b, 0x97, 0x60, 0x25, 0x3a, 0xbf, 0x62, 0x53, 0xdb, 0x8d, 0x06, 0x94,
+    0xfe, 0x2b, 0x33, 0x97, 0x60, 0x25, 0x09, 0x4f, 0xd9, 0xd6, 0xd3, 0x1d,
+    0x29, 0xad, 0xb5, 0x29, 0xf8, 0x58, 0x6c, 0x2f, 0xa5, 0x18, 0x98, 0x4f,
+    0x48, 0x4e, 0x39, 0xa2, 0x20, 0x19, 0x08, 0x55, 0xa5, 0x61, 0x0c, 0x4c,
+    0x5f, 0x48, 0xc7, 0xe5, 0x2a, 0x7a, 0x78, 0x3a, 0x8e, 0x6e, 0x7f, 0xcc,
+    0xfa, 0x1c, 0xbf, 0xda, 0xeb, 0x4f, 0xf7, 0x34, 0xce, 0xfd, 0x60, 0x32,
+    0xd3, 0xfc, 0xdb, 0x3f, 0xc9, 0xbb, 0x87, 0x5a, 0x18, 0xfd, 0x74, 0x75,
+    0x3f, 0xff, 0x39, 0x54, 0xfa, 0xd7, 0x8c, 0xb3, 0x7e, 0x6f, 0x41, 0x2a,
+    0x2f, 0xb9, 0xdc, 0xce, 0xad, 0x3d, 0xc1, 0xc7, 0xad, 0x0c, 0x6e, 0xc8,
+    0x6e, 0x7f, 0xc2, 0x4f, 0xe6, 0xb3, 0xe5, 0x75, 0xa7, 0xf7, 0x00, 0x10,
+    0xbf, 0x58, 0xb8, 0x80, 0x67, 0x57, 0xde, 0xb8, 0x80, 0x63, 0x0f, 0xa3,
+    0x74, 0x09, 0xa9, 0xeb, 0x88, 0x06, 0x7a, 0x87, 0x67, 0xae, 0x20, 0x19,
+    0xfc, 0x5d, 0xd6, 0x00, 0x0c, 0xb8, 0x80, 0x67, 0x10, 0xfa, 0xb8, 0x80,
+    0x63, 0xd4, 0x5b, 0x1c, 0x8b, 0x45, 0xce, 0xcf, 0xa7, 0x7d, 0xb8, 0xb8,
+    0x80, 0x61, 0x71, 0x00, 0xcc, 0xc7, 0x5c, 0x40, 0x31, 0xe9, 0xb9, 0x21,
+    0x79, 0xe2, 0x3f, 0xac, 0xb8, 0x80, 0x67, 0x72, 0xba, 0xb8, 0x80, 0x67,
+    0xfc, 0x34, 0xf3, 0x68, 0xbb, 0x5f, 0x5c, 0x40, 0x33, 0x57, 0xab, 0x88,
+    0x06, 0x7f, 0x0d, 0x5b, 0x7b, 0xb0, 0x17, 0x10, 0x0c, 0xf8, 0x83, 0xa1,
+    0x02, 0xe2, 0x01, 0x98, 0xae, 0xb8, 0x80, 0x63, 0xe7, 0xab, 0xc3, 0x39,
+    0xf7, 0x05, 0xb6, 0x7a, 0xa2, 0x01, 0x98, 0x0c, 0xb8, 0x80, 0x4c, 0x6d,
+    0x27, 0xc4, 0xc7, 0xaf, 0x57, 0x10, 0x0c, 0xf6, 0xf4, 0x3d, 0x5c, 0x40,
+    0x33, 0x9b, 0xfd, 0x5c, 0x40, 0x33, 0xfe, 0xcd, 0xaf, 0xeb, 0x60, 0x82,
+    0xeb, 0x88, 0x06, 0x7d, 0xbd, 0x3d, 0xec, 0xb8, 0x80, 0x63, 0x0f, 0xff,
+    0x49, 0x73, 0x7c, 0x0b, 0x88, 0x06, 0x1e, 0xaa, 0x2f, 0xd2, 0x3c, 0x84,
+    0xa1, 0x2b, 0x68, 0xc8, 0x06, 0x77, 0x2e, 0xe4, 0x29, 0xf7, 0x21, 0x9f,
+    0x67, 0x2f, 0x5b, 0x2e, 0x20, 0x19, 0xfd, 0xeb, 0x75, 0xcf, 0xb7, 0x17,
+    0x10, 0x0f, 0xa6, 0xd2, 0x77, 0xda, 0xd5, 0xc4, 0x03, 0x1d, 0x3f, 0xbf,
+    0xa9, 0x4f, 0x10, 0xbe, 0xeb, 0x88, 0x06, 0x7e, 0xa7, 0x1f, 0x9b, 0x3d,
+    0x71, 0x00, 0xc6, 0x22, 0x28, 0x04, 0x5b, 0x96, 0xcf, 0xf6, 0x9a, 0xe6,
+    0xbe, 0xff, 0x02, 0xe2, 0x01, 0x91, 0x2e, 0x20, 0x19, 0xaa, 0xcf, 0x4f,
+    0x8f, 0x48, 0xf3, 0x7c, 0x0b, 0x88, 0x06, 0x7d, 0x5c, 0xb9, 0x6c, 0xb8,
+    0x80, 0x67, 0xe2, 0x1d, 0xdf, 0x97, 0x5c, 0x40, 0x30, 0xc8, 0x90, 0x12,
+    0x3e, 0x1a, 0x47, 0xac, 0x80, 0x7c, 0x86, 0xc3, 0x88, 0x1f, 0x61, 0xd1,
+    0x0d, 0x17, 0x00, 0xa2, 0xf2, 0xb5, 0x39, 0x1e, 0x1f, 0x94, 0x24, 0xc2,
+    0x85, 0xfc, 0xea, 0xae, 0xaa, 0x20, 0x13, 0x22, 0xf2, 0x78, 0x37, 0x4f,
+    0xe9, 0xd6, 0x9f, 0xf9, 0xe3, 0x9d, 0xd1, 0x00, 0x1b, 0xb8, 0xb4, 0xc0,
+    0x64, 0xa4, 0x1a, 0x53, 0xb4, 0xd6, 0x2d, 0x35, 0xb6, 0xa5, 0x04, 0x7b,
+    0x5e, 0x71, 0x57, 0x04, 0x6d, 0x1c, 0x9c, 0x72, 0xba, 0x46, 0x3c, 0x19,
+    0xff, 0xdc, 0xbe, 0x06, 0x5f, 0x08, 0x00, 0x6d, 0x96, 0x8b, 0x19, 0x68,
+    0x2f, 0x1f, 0xed, 0x25, 0x9c, 0x8e, 0x68, 0xa8, 0x10, 0xe0, 0x08, 0xb2,
+    0x7e, 0xe0, 0x4e, 0xdd, 0xb5, 0xd6, 0x9c, 0x3b, 0x3d, 0x71, 0x80, 0x41,
+    0x1e, 0xdd, 0x19, 0x4f, 0xdf, 0x71, 0xed, 0xfb, 0x16, 0x9f, 0xf3, 0xef,
+    0xe0, 0x70, 0xed, 0xf0, 0xd6, 0x9f, 0xfb, 0xfa, 0xac, 0x7b, 0x7c, 0x01,
+    0x1d, 0x69, 0xf8, 0x2b, 0x7e, 0x59, 0xa4, 0xa7, 0x9c, 0xd5, 0x38, 0xb4,
+    0xfb, 0x1c, 0x7b, 0x6c, 0xb4, 0xf6, 0x0b, 0x3d, 0x28, 0xf9, 0xf5, 0x09,
+    0x1b, 0xa9, 0x44, 0x32, 0x6f, 0x98, 0x5e, 0x48, 0x1a, 0x44, 0xa8, 0x4c,
+    0x4f, 0xdb, 0x5f, 0xff, 0x6e, 0x2d, 0x3c, 0x43, 0xcb, 0xad, 0x3b, 0x77,
+    0x42, 0xeb, 0x4f, 0xfc, 0x03, 0xe7, 0x74, 0x5e, 0xeb, 0x70, 0xd6, 0x9f,
+    0xfa, 0xe1, 0x87, 0x5e, 0x18, 0xe2, 0x41, 0xad, 0x3f, 0xd9, 0xce, 0x10,
+    0x7c, 0xce, 0xad, 0x3f, 0xbd, 0x6d, 0xaf, 0x9b, 0x71, 0x69, 0xfe, 0x6e,
+    0x17, 0x4b, 0xd6, 0xe2, 0xd2, 0xbf, 0xa8, 0xa4, 0xc3, 0x8f, 0x9a, 0xc6,
+    0xc9, 0x90, 0xf2, 0x1d, 0x73, 0xf9, 0xf9, 0x70, 0xaf, 0xcc, 0x5a, 0x19,
+    0x3e, 0x72, 0x22, 0xa8, 0xda, 0x37, 0x2a, 0x9f, 0xf9, 0xb6, 0x78, 0xee,
+    0x0f, 0x1d, 0x38, 0x16, 0x9f, 0x53, 0xbf, 0x7d, 0x65, 0xa6, 0xbd, 0xd6,
+    0x9d, 0x6d, 0xb6, 0xad, 0x30, 0x29, 0x23, 0x17, 0xf1, 0xf3, 0xd9, 0xb9,
+    0xac, 0xff, 0xb2, 0xe3, 0x41, 0xb8, 0x24, 0xe2, 0xd3, 0xa8, 0x18, 0x94,
+    0x3d, 0x1f, 0xa7, 0x84, 0x1e, 0x88, 0xbc, 0x8f, 0xa7, 0xf7, 0x07, 0x36,
+    0x00, 0x4f, 0x5a, 0x6a, 0x3a, 0xd3, 0xfc, 0x38, 0xef, 0x0d, 0x6d, 0xb6,
+    0xa5, 0x38, 0xf5, 0xc5, 0xa1, 0xc3, 0xec, 0xd0, 0xab, 0xb3, 0xc9, 0xf6,
+    0x38, 0xf6, 0x7a, 0xd3, 0xf5, 0x9e, 0xb6, 0x0f, 0xab, 0x43, 0x26, 0xd8,
+    0x48, 0xb5, 0x0a, 0x0e, 0x19, 0x04, 0x4f, 0x3f, 0x3a, 0x05, 0xf6, 0xf8,
+    0xad, 0x3f, 0xfb, 0x3d, 0xa3, 0xe6, 0xcf, 0xc0, 0x67, 0xab, 0x4d, 0xaa,
+    0x5a, 0x67, 0x2e, 0xb4, 0xfb, 0x1d, 0x90, 0xfb, 0x86, 0xb0, 0x21, 0x58,
+    0xf0, 0x8b, 0x53, 0x3b, 0x4f, 0x7b, 0x9a, 0xa5, 0xa7, 0xfe, 0x6c, 0x17,
+    0xeb, 0x04, 0x5a, 0xd5, 0xa4, 0x5f, 0x44, 0x30, 0x92, 0xf0, 0x86, 0x2c,
+    0x6e, 0xe0, 0x9f, 0x2a, 0x1b, 0xd9, 0x48, 0xa1, 0x97, 0xf6, 0x16, 0x04,
+    0x43, 0xfa, 0x5f, 0x49, 0xe1, 0xa3, 0xa8, 0xe7, 0x29, 0x30, 0x05, 0xc3,
+    0x28, 0x1e, 0xe8, 0x5c, 0x95, 0x63, 0xba, 0x73, 0xb8, 0xda, 0xe7, 0xfb,
+    0x3e, 0x2d, 0xc7, 0xe6, 0x96, 0x9f, 0x84, 0x19, 0xed, 0x3d, 0x69, 0xf5,
+    0x3f, 0xc7, 0xa4, 0xb4, 0xf8, 0x27, 0x1e, 0xde, 0x74, 0xa1, 0x91, 0x71,
+    0x86, 0xda, 0x2c, 0x08, 0xa6, 0x7f, 0xe0, 0xc7, 0x7a, 0x0b, 0x2e, 0x4c,
+    0x2b, 0x4e, 0xf2, 0x2f, 0x56, 0x8f, 0x9f, 0x11, 0xd0, 0xe4, 0x12, 0xa2,
+    0x05, 0x97, 0x15, 0x40, 0xa4, 0x8b, 0x86, 0xee, 0xd1, 0xe9, 0xff, 0x17,
+    0x96, 0x88, 0x23, 0x00, 0x0c, 0x94, 0xff, 0x6b, 0x7a, 0xbe, 0x60, 0x86,
+    0xb4, 0xff, 0x85, 0xb6, 0x3d, 0x73, 0x36, 0xe2, 0xd3, 0xff, 0xfb, 0x4d,
+    0xf0, 0x63, 0xb2, 0xbd, 0xf0, 0x7b, 0x42, 0x05, 0xa7, 0xcd, 0x83, 0xcf,
+    0x25, 0xa4, 0x75, 0xa7, 0xaf, 0x5b, 0x78, 0x39, 0xb8, 0x12, 0x88, 0xf5,
+    0x34, 0x7f, 0x9c, 0x68, 0xfb, 0x90, 0x97, 0x86, 0x4f, 0x30, 0xa3, 0x88,
+    0x9f, 0xff, 0xef, 0xd9, 0x84, 0xe5, 0x53, 0xee, 0xc7, 0xf7, 0x4c, 0x3d,
+    0x5a, 0x75, 0x82, 0xf5, 0xa1, 0x95, 0x7d, 0x1d, 0x77, 0x51, 0xf9, 0xd1,
+    0x46, 0xec, 0xd3, 0xf9, 0xee, 0x60, 0xd6, 0xb1, 0x69, 0xff, 0xdf, 0xe8,
+    0xe3, 0xb1, 0xc6, 0xfb, 0x5d, 0x69, 0xfd, 0x4e, 0x6b, 0x0f, 0x97, 0x5a,
+    0x30, 0xfe, 0x9d, 0xa4, 0x4f, 0xc4, 0x1f, 0x33, 0x0e, 0xb4, 0xfb, 0x3d,
+    0x2f, 0xdd, 0x69, 0xdc, 0xe6, 0xcb, 0x4f, 0xfd, 0xb7, 0x4b, 0x5e, 0x1d,
+    0x73, 0x44, 0x75, 0xa5, 0x70, 0x1f, 0x37, 0x07, 0x64, 0xd6, 0x22, 0xd6,
+    0xd8, 0x46, 0xc1, 0x26, 0x67, 0xa2, 0x3e, 0x43, 0x86, 0x7f, 0xc2, 0x41,
+    0x6d, 0x8e, 0xf6, 0x60, 0x96, 0x9d, 0xed, 0x7d, 0x69, 0xf0, 0x28, 0x71,
+    0xd5, 0x68, 0x63, 0xc4, 0xdc, 0x72, 0x71, 0xf6, 0x71, 0x69, 0xff, 0x8f,
+    0x73, 0xb7, 0xad, 0xfd, 0xd8, 0x0b, 0x4f, 0xf9, 0xa8, 0x73, 0x9c, 0x2b,
+    0x78, 0xb4, 0x32, 0x27, 0xc8, 0x7b, 0x74, 0x58, 0x65, 0x71, 0x2f, 0x8f,
+    0x7b, 0x0d, 0x6f, 0x08, 0x6e, 0x43, 0x06, 0x7f, 0xf3, 0xcb, 0x58, 0xe1,
+    0x39, 0xbb, 0xae, 0xf7, 0x5a, 0x7f, 0x16, 0xbd, 0xa1, 0x6d, 0x2d, 0x3e,
+    0x6b, 0x19, 0xd5, 0x96, 0x9f, 0xb7, 0x0b, 0x59, 0xb5, 0xd6, 0x9f, 0xff,
+    0xff, 0x7d, 0xb8, 0x35, 0xd2, 0xbb, 0x85, 0xfe, 0xb5, 0xf8, 0xdb, 0x30,
+    0x59, 0x75, 0xa7, 0xff, 0xff, 0xfd, 0x7b, 0xe7, 0x35, 0x47, 0xbf, 0xfe,
+    0x5b, 0x72, 0xa8, 0x3c, 0xc7, 0x37, 0xe3, 0x5b, 0xb3, 0x2d, 0x0c, 0x98,
+    0xfd, 0x42, 0x0a, 0x78, 0x15, 0xb5, 0xd6, 0x9a, 0xdb, 0x56, 0x8b, 0x9b,
+    0xab, 0x48, 0xa7, 0xc5, 0xaa, 0xcd, 0x24, 0x63, 0x45, 0x1b, 0x2a, 0xb1,
+    0x71, 0x43, 0x46, 0x2e, 0x81, 0x48, 0xc6, 0x9f, 0x78, 0x41, 0xce, 0xb6,
+    0xdb, 0x52, 0x9e, 0x7f, 0x33, 0xa9, 0x18, 0xbf, 0x9f, 0x67, 0xa4, 0x0b,
+    0xae, 0xef, 0xe9, 0x57, 0xcf, 0x90, 0x4c, 0x26, 0xfd, 0xd6, 0x9c, 0xed,
+    0xba, 0xb4, 0x31, 0xb3, 0x21, 0x69, 0xf8, 0x76, 0xbb, 0x99, 0xc5, 0xa7,
+    0xff, 0x87, 0x8e, 0x67, 0xf2, 0x8e, 0xda, 0x2f, 0x56, 0x9f, 0x59, 0xe7,
+    0x2c, 0xd9, 0x69, 0xf1, 0x5d, 0xac, 0x3a, 0xec, 0xfd, 0x9f, 0x35, 0x7c,
+    0x1b, 0xae, 0xcf, 0xd9, 0xa9, 0xeb, 0xb3, 0xf6, 0x7b, 0x77, 0xe5, 0xd7,
+    0x67, 0xec, 0x7a, 0x7a, 0x22, 0x45, 0x3e, 0x6c, 0xbe, 0x0a, 0xec, 0xfd,
+    0x85, 0xd9, 0xfb, 0x35, 0x71, 0x76, 0x7e, 0x9c, 0xb7, 0x93, 0xc4, 0xfe,
+    0x77, 0x48, 0x9e, 0xcf, 0x22, 0x02, 0xec, 0xfd, 0x85, 0xd9, 0xfb, 0x30,
+    0x19, 0x76, 0x7e, 0xcf, 0xf6, 0x02, 0xbf, 0x8e, 0xf3, 0xd5, 0xd9, 0xfb,
+    0x3f, 0x66, 0x8a, 0xfb, 0xd8, 0xbb, 0x3f, 0x60, 0x08, 0xa3, 0x12, 0x2b,
+    0xa3, 0x4f, 0x7e, 0xc6, 0xe2, 0xec, 0xfd, 0x85, 0xd9, 0xfb, 0x86, 0xbe,
+    0x6b, 0x6d, 0x5d, 0x9f, 0xb0, 0xf5, 0x61, 0xfe, 0x9a, 0x64, 0x21, 0x76,
+    0x84, 0xdf, 0xca, 0x0e, 0x61, 0x78, 0x5d, 0x71, 0x7a, 0xd2, 0x69, 0xec,
+    0x7b, 0x06, 0x9b, 0x3f, 0x46, 0x44, 0x8c, 0xff, 0xb3, 0xbe, 0xe7, 0xed,
+    0xad, 0x38, 0xb4, 0xcf, 0xb1, 0x28, 0xb1, 0x13, 0x1b, 0x20, 0x8a, 0x04,
+    0x7d, 0x72, 0x56, 0xa7, 0x19, 0x27, 0xff, 0xcf, 0xfb, 0x3b, 0xa7, 0x1b,
+    0xdd, 0x31, 0xe9, 0xc5, 0xa7, 0xf3, 0xad, 0x5c, 0xae, 0xe6, 0x2d, 0x1b,
+    0x22, 0x37, 0xeb, 0x10, 0xcb, 0xcc, 0xef, 0x59, 0xc1, 0xf2, 0x2e, 0xa9,
+    0xce, 0x3d, 0xe1, 0x75, 0x3f, 0xff, 0xc5, 0xaa, 0xd3, 0x3c, 0xd8, 0x06,
+    0x7d, 0xfd, 0xd3, 0x7d, 0x69, 0xff, 0x06, 0xdb, 0x0b, 0x6b, 0x5b, 0xf5,
+    0x69, 0xf8, 0x68, 0x3d, 0x53, 0xd6, 0x9d, 0x6d, 0xb6, 0xa5, 0x38, 0x26,
+    0x02, 0x46, 0x2f, 0xe7, 0xfc, 0x34, 0xf0, 0xbf, 0x8e, 0xeb, 0xeb, 0x4f,
+    0xf0, 0xd0, 0x3c, 0x3d, 0x81, 0xb2, 0xd0, 0xf4, 0xe5, 0x3d, 0x65, 0x3a,
+    0x00, 0x12, 0xc4, 0xaf, 0x87, 0xf3, 0xfe, 0x11, 0x2d, 0xdd, 0x0b, 0xf9,
+    0x37, 0x16, 0x9d, 0x6d, 0xb6, 0xa6, 0x21, 0x04, 0xfb, 0xfd, 0xaa, 0xea,
+    0x62, 0x10, 0x18, 0xd6, 0xce, 0xb6, 0xdb, 0x53, 0x10, 0x7a, 0x13, 0x10,
+    0x78, 0xc6, 0xb6, 0x47, 0xc4, 0x4c, 0xf5, 0xc6, 0x7f, 0xed, 0x33, 0xcb,
+    0x99, 0xae, 0xb1, 0xd6, 0x86, 0x3e, 0xa7, 0x65, 0x13, 0xee, 0x37, 0x18,
+    0xeb, 0x4f, 0x09, 0x30, 0x6b, 0x4e, 0x09, 0x80, 0xb4, 0x58, 0x6f, 0x0e,
+    0x41, 0x3e, 0xeb, 0x69, 0x8e, 0x94, 0xf8, 0x68, 0x47, 0x12, 0x9b, 0x3a,
+    0x94, 0xd6, 0xda, 0x94, 0x61, 0xfb, 0x5c, 0x9b, 0x84, 0x76, 0x8a, 0xcf,
+    0xe1, 0x09, 0x81, 0xac, 0x75, 0x48, 0xc6, 0xf2, 0x19, 0x37, 0xb2, 0x62,
+    0xa8, 0x6a, 0x4f, 0xfc, 0xc0, 0xbe, 0x67, 0xb4, 0x34, 0x1a, 0xd3, 0xff,
+    0xed, 0x9f, 0x7b, 0x5b, 0xfa, 0x62, 0xd3, 0x09, 0x2d, 0x1a, 0x44, 0xb5,
+    0x21, 0x4f, 0xeb, 0x84, 0x7b, 0xdb, 0x5b, 0x2d, 0x0c, 0xb9, 0x19, 0x8b,
+    0x05, 0x1b, 0xaf, 0xe3, 0x9e, 0xa8, 0x64, 0xdc, 0x8a, 0x75, 0xb6, 0xda,
+    0x94, 0xf0, 0x28, 0x7d, 0x48, 0xc5, 0xfc, 0xfc, 0x16, 0x7f, 0x31, 0xc5,
+    0xa1, 0xe7, 0xbb, 0x73, 0x09, 0xff, 0xe1, 0xdb, 0xc6, 0xc0, 0x61, 0xed,
+    0x58, 0x34, 0xb4, 0xff, 0xff, 0xff, 0x72, 0xe1, 0x5f, 0xc6, 0xa8, 0xb8,
+    0x5a, 0xe9, 0x78, 0x79, 0x6a, 0x87, 0x8f, 0xcf, 0xe2, 0xd3, 0xff, 0xd8,
+    0xc6, 0xf4, 0x5b, 0x7e, 0xe0, 0x65, 0xf5, 0xa7, 0x9d, 0x74, 0x07, 0x6b,
+    0x43, 0xcf, 0xda, 0x93, 0xe7, 0xfe, 0xcf, 0x80, 0xe5, 0x70, 0xae, 0xd8,
+    0xb4, 0xea, 0xf3, 0xdd, 0x68, 0x79, 0xf1, 0x52, 0x1c, 0xf1, 0x7b, 0x87,
+    0x5a, 0x19, 0x52, 0x23, 0xc8, 0xb1, 0x46, 0xa3, 0x0c, 0x18, 0x41, 0xee,
+    0x43, 0x3f, 0x79, 0xee, 0x43, 0xb3, 0xd6, 0x9f, 0xf5, 0x7f, 0xc8, 0xb5,
+    0x95, 0xb0, 0x16, 0x9f, 0xff, 0x17, 0x18, 0xf9, 0xb7, 0x18, 0xe1, 0x7e,
+    0x80, 0xb4, 0xff, 0x5d, 0xbf, 0xc6, 0x37, 0xa4, 0xb4, 0x3d, 0x11, 0xb7,
+    0x55, 0x9f, 0xc4, 0x1f, 0x1b, 0x4d, 0x75, 0xa7, 0xfc, 0x34, 0xe6, 0xab,
+    0xff, 0x2f, 0x56, 0x8c, 0x4e, 0x47, 0xa6, 0x25, 0x0c, 0xdf, 0x91, 0x9c,
+    0xca, 0x79, 0xe1, 0x63, 0x8b, 0x4f, 0xbf, 0xee, 0x60, 0xad, 0x3f, 0xf7,
+    0x9c, 0xb3, 0x4c, 0xee, 0xfa, 0x6d, 0x96, 0x8a, 0x3e, 0xfb, 0x93, 0x4f,
+    0xf6, 0x0f, 0xf2, 0xf8, 0x5a, 0x5a, 0x7f, 0xf7, 0x2f, 0x8e, 0x69, 0x9d,
+    0xe6, 0xb4, 0xcb, 0x4f, 0xda, 0xf4, 0x9d, 0xb7, 0xab, 0x46, 0x1f, 0xdd,
+    0x25, 0xcf, 0x67, 0x0a, 0xeb, 0x4f, 0xce, 0x99, 0xc1, 0x74, 0xac, 0xdd,
+    0x68, 0xb9, 0xed, 0xf0, 0x82, 0x3d, 0x4d, 0xbb, 0xa4, 0x23, 0x0b, 0x0e,
+    0x3d, 0xcf, 0xff, 0x15, 0xf3, 0xde, 0x5c, 0x83, 0xd5, 0x09, 0x2d, 0x3f,
+    0xff, 0x87, 0x99, 0xa2, 0x6e, 0x10, 0x19, 0xe6, 0xb6, 0xdb, 0x52, 0x9e,
+    0xf7, 0x30, 0x34, 0xa7, 0xa8, 0x15, 0xc5, 0xa7, 0x3c, 0x77, 0x54, 0x43,
+    0x33, 0xad, 0xb6, 0xd4, 0xa7, 0x60, 0xf5, 0x23, 0x17, 0xf3, 0xfe, 0xcb,
+    0x33, 0xda, 0x78, 0xb5, 0x8b, 0x40, 0x0f, 0x9c, 0x4a, 0x67, 0xf3, 0xc7,
+    0x39, 0xcd, 0xec, 0x5a, 0x75, 0x79, 0xd9, 0x68, 0x64, 0xf1, 0x6c, 0x61,
+    0xf4, 0x8b, 0x62, 0x0f, 0xc2, 0xbe, 0x88, 0x77, 0x34, 0x9e, 0x2e, 0x13,
+    0x2d, 0x3f, 0xb7, 0xcf, 0x80, 0x04, 0x2b, 0x4f, 0xff, 0x3c, 0xbd, 0xd0,
+    0x57, 0xcf, 0xf6, 0xab, 0xaa, 0x88, 0x32, 0x7f, 0xf7, 0xe9, 0xde, 0x0f,
+    0x74, 0x40, 0x0b, 0x8b, 0x43, 0x22, 0xa3, 0x75, 0xd8, 0xd2, 0x3f, 0x79,
+    0x0d, 0xa9, 0xb5, 0xba, 0xd3, 0xdf, 0x2b, 0x7c, 0xeb, 0x41, 0x1b, 0xdb,
+    0x8b, 0xcf, 0xef, 0x2c, 0xbf, 0x96, 0x7d, 0x96, 0x87, 0xa7, 0xb0, 0x51,
+    0x8e, 0x5d, 0x97, 0x84, 0x13, 0xff, 0xcc, 0x36, 0x78, 0x70, 0x87, 0x3d,
+    0xc1, 0x0d, 0x69, 0xcd, 0xf7, 0x16, 0x86, 0x5f, 0x98, 0xf5, 0x3b, 0x25,
+    0x00, 0x75, 0x0c, 0xa5, 0x09, 0xd4, 0xa4, 0x4d, 0xd0, 0xfc, 0x94, 0x67,
+    0xd4, 0x7a, 0xcb, 0xad, 0x3f, 0xfd, 0xd6, 0xbd, 0xd8, 0xf9, 0xc2, 0xbe,
+    0xa9, 0x69, 0xfc, 0x22, 0xcf, 0x3b, 0x12, 0xd3, 0xfb, 0x84, 0xec, 0xb8,
+    0xf6, 0x4a, 0x47, 0x5a, 0x7e, 0xc1, 0x0f, 0xec, 0x62, 0x3c, 0x30, 0x8c,
+    0xe3, 0x13, 0x03, 0x24, 0xdb, 0xb9, 0x4f, 0x7f, 0x7d, 0x9e, 0xb4, 0xfe,
+    0x17, 0x8e, 0x1d, 0xba, 0xb4, 0xe3, 0xfb, 0x8b, 0x43, 0x1f, 0x86, 0x12,
+    0x51, 0x84, 0xee, 0x15, 0x8b, 0x4f, 0xad, 0x2f, 0x5d, 0x49, 0x69, 0xff,
+    0x6f, 0xcb, 0x85, 0xf0, 0x1c, 0xae, 0xb4, 0xfe, 0xbb, 0x59, 0x82, 0x41,
+    0xad, 0x3f, 0xf3, 0x0d, 0x69, 0x80, 0x6f, 0xde, 0xe9, 0x47, 0xa8, 0xb5,
+    0xc4, 0x13, 0x99, 0x4f, 0xed, 0x9f, 0xb5, 0xcb, 0x8c, 0xb4, 0xe2, 0xda,
+    0xeb, 0x4b, 0x58, 0x7a, 0x04, 0x69, 0x3f, 0xfe, 0xcf, 0x7c, 0x51, 0x65,
+    0xda, 0xcc, 0x12, 0x0d, 0x69, 0xb2, 0xd5, 0xa1, 0x29, 0xfa, 0xe1, 0x37,
+    0xd8, 0xe9, 0x42, 0x50, 0x94, 0x25, 0x09, 0x43, 0xcf, 0x7c, 0x82, 0x80,
+    0x5b, 0xb8, 0x57, 0x90, 0x53, 0xa8, 0x54, 0xda, 0xc4, 0xa7, 0xea, 0xae,
+    0x38, 0xc7, 0x4b, 0xc1, 0x6b, 0x27, 0x41, 0x28, 0x4a, 0x12, 0x87, 0x96,
+    0x84, 0x15, 0x09, 0x42, 0x50, 0x94, 0x25, 0x09, 0x42, 0x51, 0x61, 0xbc,
+    0xf4, 0x28, 0x82, 0x80, 0x15, 0x70, 0xa7, 0x61, 0x50, 0x94, 0x25, 0x0f,
+    0x2d, 0x2e, 0x15, 0x09, 0x42, 0x50, 0x94, 0x25, 0x0f, 0x35, 0x00, 0x0a,
+    0xe0, 0x53, 0xa8, 0x54, 0x25, 0x09, 0x42, 0x50, 0x94, 0x58, 0x6a, 0x03,
+    0x0a, 0xf8, 0x56, 0x82, 0xa4, 0x1a, 0x50, 0x94, 0x25, 0x09, 0x42, 0x51,
+    0xe9, 0xa8, 0xd8, 0x28, 0x01, 0x5b, 0x85, 0x42, 0x50, 0x94, 0x25, 0x3e,
+    0xd3, 0x02, 0xf8, 0x94, 0x25, 0x0f, 0x3c, 0xee, 0x85, 0x68, 0x2a, 0x82,
+    0x80, 0x4d, 0x2e, 0xa5, 0x09, 0x42, 0x50, 0x94, 0x25, 0x0f, 0x35, 0x1b,
+    0x05, 0x10, 0x53, 0xb0, 0xa8, 0x4a, 0x12, 0x84, 0xa1, 0x28, 0x79, 0xa8,
+    0xf4, 0x2b, 0x41, 0x42, 0x15, 0x2d, 0x25, 0x09, 0x42, 0x52, 0x7a, 0x50,
+    0x96, 0xc5, 0x84, 0x25, 0x09, 0x42, 0x50, 0x94, 0x58, 0x7c, 0xcf, 0x0a,
+    0x0c, 0x6b, 0xa3, 0x4e, 0x05, 0x00, 0x2b, 0x81, 0x52, 0xc4, 0xa1, 0x28,
+    0x4a, 0x4f, 0x4a, 0x12, 0xd8, 0xb0, 0x84, 0xa1, 0x28, 0x63, 0xd2, 0x78,
+    0x51, 0x0d, 0x7c, 0x68, 0xe1, 0x50, 0x94, 0x25, 0x09, 0x42, 0x50, 0x94,
+    0x31, 0xb2, 0xd8, 0x2b, 0xe1, 0x47, 0x0a, 0x10, 0xa8, 0x4a, 0x12, 0x84,
+    0xa3, 0xe5, 0xf5, 0xc2, 0xb8, 0x15, 0x09, 0x42, 0x50, 0x94, 0x1c, 0xbe,
+    0x10, 0xae, 0x05, 0x48, 0xe9, 0x42, 0x50, 0x94, 0x00, 0xb4, 0xdc, 0x2a,
+    0x12, 0x84, 0xa1, 0x28, 0x4a, 0x18, 0xd4, 0x38, 0x15, 0xa0, 0xad, 0xc2,
+    0xa1, 0x97, 0xea, 0x6c, 0x71, 0x79, 0xef, 0xa5, 0x38, 0xb7, 0xd6, 0xcd,
+    0x92, 0x09, 0x9b, 0xce, 0x7a, 0xe1, 0xcf, 0xe1, 0x18, 0x74, 0x8d, 0x1c,
+    0x53, 0x28, 0x0e, 0xc5, 0xda, 0xec, 0xdc, 0x61, 0xdd, 0xe5, 0xdb, 0x2d,
+    0xa9, 0x7e, 0x45, 0x81, 0x12, 0x3a, 0xa4, 0xcf, 0x9e, 0x2d, 0x97, 0x48,
+    0xc9, 0xab, 0xce, 0x26, 0x3a, 0x53, 0xc5, 0xda, 0xfa, 0xd3, 0x8b, 0xdc,
+    0x5a, 0x46, 0xd9, 0x11, 0xbf, 0x38, 0xd0, 0xd7, 0x08, 0x24, 0xce, 0xd9,
+    0x48, 0xc1, 0x52, 0x80, 0xa7, 0xf6, 0x8a, 0xdf, 0x7e, 0xd6, 0x2d, 0x1b,
+    0x1f, 0x6b, 0x87, 0x13, 0x01, 0x96, 0x9f, 0xbf, 0x42, 0x13, 0x01, 0x69,
+    0xab, 0xeb, 0x48, 0x96, 0xe9, 0x6b, 0x2e, 0xad, 0x23, 0xad, 0x37, 0x91,
+    0x89, 0x12, 0x9f, 0x15, 0xd2, 0x0d, 0x0f, 0x04, 0x21, 0x3f, 0xda, 0x63,
+    0xe3, 0x8c, 0x36, 0x2d, 0x18, 0x89, 0x00, 0x2c, 0x4f, 0xc7, 0x2f, 0x2a,
+    0x10, 0x2d, 0x3f, 0xb6, 0x06, 0x0e, 0x6d, 0x6a, 0xd3, 0xff, 0xcd, 0xe2,
+    0xbf, 0xfa, 0x03, 0x1a, 0xdb, 0x6d, 0x5a, 0x19, 0x16, 0xb4, 0x5d, 0xb9,
+    0xa4, 0x58, 0xd8, 0x75, 0xbe, 0x32, 0x8f, 0x61, 0x3f, 0xd2, 0xcd, 0x87,
+    0x0a, 0x1c, 0x0e, 0x42, 0x00, 0xe4, 0xd5, 0x4b, 0x08, 0x18, 0xd2, 0x39,
+    0x0d, 0x79, 0xf1, 0xc8, 0x7a, 0xcb, 0x4f, 0xe6, 0x1e, 0x50, 0xef, 0x8b,
+    0x4f, 0xcf, 0x12, 0x7e, 0xb1, 0x69, 0xf5, 0x85, 0xf6, 0x7a, 0xd1, 0xf3,
+    0xd2, 0x12, 0xb9, 0xff, 0x69, 0xbe, 0x01, 0xcb, 0x68, 0x0b, 0x4e, 0xcc,
+    0x71, 0x69, 0x66, 0x8f, 0x60, 0x07, 0xb3, 0xf6, 0xff, 0xdc, 0xf4, 0x2b,
+    0x4f, 0x1d, 0xb2, 0xc5, 0xa7, 0xd8, 0xec, 0x5b, 0x65, 0xa0, 0x8f, 0x26,
+    0xe4, 0x33, 0xcc, 0x3c, 0xea, 0xd2, 0x6c, 0x4d, 0x60, 0x5e, 0x6e, 0x4f,
+    0xc7, 0x7f, 0x22, 0x19, 0xed, 0xeb, 0xef, 0x5a, 0x79, 0xb7, 0x74, 0x2e,
+    0x94, 0xf9, 0xe6, 0xb6, 0xdb, 0x56, 0x81, 0x3d, 0x2d, 0xc9, 0xe7, 0xab,
+    0x87, 0xe2, 0xd1, 0xea, 0x2d, 0xf1, 0xd0, 0x04, 0x50, 0xca, 0xcd, 0xce,
+    0x4a, 0x08, 0xf6, 0xb7, 0x8c, 0x22, 0x7d, 0xb8, 0x30, 0x7a, 0xb4, 0xfe,
+    0xe6, 0x04, 0xce, 0x15, 0xd6, 0x8f, 0x9e, 0xd3, 0xb2, 0x79, 0xfe, 0xb0,
+    0x71, 0xfa, 0xc0, 0x5d, 0x69, 0xef, 0x7d, 0x67, 0x6b, 0x4f, 0xff, 0x69,
+    0x8f, 0xd6, 0xe6, 0x7f, 0xb5, 0x5d, 0x54, 0x5f, 0x13, 0xab, 0xf6, 0x2a,
+    0x2f, 0xf8, 0x64, 0x41, 0xf5, 0x6a, 0x7f, 0xce, 0xa5, 0x83, 0xe8, 0x65,
+    0x9f, 0x5a, 0x75, 0x6c, 0xea, 0xb4, 0xfd, 0x5c, 0xbb, 0x65, 0x8b, 0x43,
+    0xb3, 0xcb, 0xb4, 0x7e, 0x71, 0x68, 0x96, 0x9f, 0xf9, 0xdf, 0x03, 0x61,
+    0x7e, 0x68, 0x8e, 0xb4, 0xfd, 0x96, 0x85, 0xaa, 0xe2, 0xd3, 0xff, 0xee,
+    0x04, 0xf6, 0x76, 0x42, 0x0f, 0x93, 0x1f, 0x12, 0x9e, 0xd0, 0x5b, 0x71,
+    0x68, 0xb1, 0x14, 0xf8, 0x5d, 0xd5, 0x59, 0xb9, 0x8b, 0x4f, 0xbe, 0x56,
+    0x51, 0xd5, 0x30, 0x9c, 0xf7, 0x37, 0x6a, 0x54, 0xc2, 0x73, 0x01, 0x95,
+    0x40, 0x9c, 0xfe, 0x1a, 0x0f, 0x8d, 0xf0, 0x2a, 0x81, 0x39, 0xfd, 0x7c,
+    0xd1, 0x5f, 0x7b, 0x15, 0x30, 0x9c, 0xd9, 0xea, 0xa6, 0x13, 0x9a, 0xdb,
+    0x57, 0x30, 0x9c, 0x62, 0x69, 0x9b, 0x1a, 0x11, 0x71, 0xc8, 0xae, 0x7e,
+    0xed, 0x06, 0xd2, 0x39, 0x71, 0x33, 0x09, 0x8c, 0x7c, 0xf2, 0x2d, 0x93,
+    0xf7, 0xb6, 0x3c, 0x88, 0x25, 0x6b, 0xd4, 0x35, 0x78, 0x76, 0x72, 0x51,
+    0x3c, 0xe1, 0x01, 0xd6, 0x9f, 0xe6, 0xdf, 0x82, 0x4e, 0xc2, 0x3a, 0xd3,
+    0x87, 0x2f, 0x87, 0xad, 0xf1, 0xb8, 0x65, 0xde, 0x0f, 0x4e, 0x3b, 0x0a,
+    0x8f, 0x91, 0x6a, 0x11, 0x7c, 0x97, 0x06, 0xee, 0x13, 0xf3, 0xef, 0x73,
+    0xe4, 0x1a, 0xd3, 0xf6, 0x98, 0x21, 0xd8, 0x0b, 0x4f, 0xcd, 0xcc, 0x70,
+    0x8e, 0xb4, 0xf8, 0x70, 0x2c, 0x71, 0x69, 0xfe, 0xd5, 0x1f, 0x44, 0xdb,
+    0x3d, 0x69, 0xf8, 0x21, 0x7f, 0x95, 0x58, 0xb4, 0x11, 0xf4, 0x80, 0xe2,
+    0x2c, 0x46, 0xe8, 0x96, 0x72, 0x12, 0x13, 0xfe, 0xca, 0xd3, 0x84, 0x3a,
+    0xcd, 0x96, 0x86, 0x64, 0x14, 0x64, 0xf0, 0x21, 0x3f, 0xf9, 0xca, 0x2a,
+    0x30, 0xb1, 0x35, 0x9f, 0xfc, 0x7e, 0x5c, 0x87, 0x67, 0xf0, 0xae, 0x4b,
+    0x4f, 0xff, 0xe1, 0xcd, 0xb2, 0xf4, 0x3a, 0x26, 0xe6, 0xb7, 0xa3, 0xad,
+    0x3f, 0x0e, 0xe7, 0x2d, 0x32, 0xd3, 0xff, 0xea, 0x1e, 0x55, 0x68, 0x5b,
+    0x97, 0xb7, 0x34, 0xb4, 0xff, 0xac, 0xa1, 0xbf, 0x34, 0x4d, 0x75, 0xa7,
+    0x7e, 0xf7, 0x5c, 0x40, 0x73, 0xff, 0xbe, 0xda, 0x6f, 0x19, 0xfe, 0xd5,
+    0x75, 0x51, 0x01, 0x98, 0xd4, 0xc5, 0x23, 0x30, 0x26, 0x68, 0x02, 0x68,
+    0x3c, 0x8c, 0x7a, 0x31, 0x39, 0x72, 0x8d, 0xb6, 0x7d, 0xc6, 0x07, 0x96,
+    0x2d, 0x3c, 0x3c, 0x06, 0xeb, 0x4f, 0xff, 0xcf, 0xcb, 0x97, 0xfe, 0x47,
+    0x0b, 0x9a, 0xcb, 0x78, 0xb4, 0x61, 0xff, 0x51, 0x14, 0xff, 0xff, 0x53,
+    0xf0, 0x5c, 0x7e, 0x6c, 0xf0, 0x98, 0x06, 0xb6, 0xdb, 0x52, 0x86, 0x4c,
+    0xcb, 0x50, 0xa7, 0x12, 0x09, 0xfc, 0xd9, 0xfe, 0xd5, 0x75, 0x51, 0x04,
+    0xcf, 0xf3, 0x73, 0x3f, 0xda, 0xae, 0xaa, 0x2f, 0x99, 0xf1, 0x3b, 0x1c,
+    0xbf, 0xa8, 0x80, 0xe9, 0xec, 0xfe, 0xdf, 0x5e, 0x5a, 0x2e, 0xe9, 0x69,
+    0xff, 0x59, 0x5b, 0x79, 0x67, 0x06, 0x9d, 0xad, 0x3f, 0xec, 0xf5, 0x9e,
+    0xda, 0xc0, 0x52, 0xd3, 0xad, 0xb6, 0xd4, 0xa7, 0xda, 0xce, 0xd7, 0xd2,
+    0x31, 0x7f, 0x3f, 0xff, 0x9c, 0xfb, 0x3b, 0xf0, 0x1d, 0x78, 0x09, 0xcb,
+    0xf8, 0xcd, 0xb8, 0xb4, 0x71, 0x14, 0x61, 0x1a, 0xc5, 0x89, 0xb2, 0x9d,
+    0x0c, 0x61, 0xfd, 0x3f, 0xf5, 0x87, 0x6d, 0xae, 0x39, 0x60, 0x4f, 0x5a,
+    0x7e, 0xf3, 0xe3, 0xf4, 0xdf, 0x5a, 0x7f, 0xf6, 0xc3, 0xe3, 0xba, 0x20,
+    0x01, 0xbe, 0xf5, 0xa1, 0x8f, 0xf0, 0x23, 0x09, 0xff, 0x6f, 0x76, 0xc1,
+    0xe3, 0xa3, 0x6f, 0x56, 0x9d, 0x6d, 0xb6, 0xa5, 0x3f, 0x82, 0x03, 0x0e,
+    0x6d, 0xc4, 0x8c, 0x5f, 0xcf, 0xff, 0xce, 0x87, 0x8e, 0xe8, 0xbd, 0xf7,
+    0x2d, 0xf1, 0xcb, 0xe5, 0x8b, 0x4a, 0xb4, 0x8a, 0xad, 0xd0, 0xa1, 0xeb,
+    0x85, 0xde, 0xa0, 0x94, 0x73, 0x9f, 0x36, 0x3c, 0x30, 0xc4, 0x8b, 0x91,
+    0x86, 0xcf, 0xfb, 0x45, 0x6f, 0xba, 0xce, 0x79, 0x62, 0xd3, 0xed, 0x67,
+    0x1c, 0x7a, 0xd3, 0xfe, 0xce, 0x37, 0xef, 0xa6, 0x1e, 0x2e, 0x20, 0x89,
+    0xfc, 0xd9, 0xfe, 0xd5, 0x75, 0x51, 0x04, 0x18, 0xf2, 0x67, 0xea, 0xd7,
+    0xfe, 0x56, 0xad, 0x3f, 0x79, 0xfd, 0xb6, 0x85, 0xeb, 0x40, 0x9e, 0xfe,
+    0xe5, 0xb1, 0xa4, 0xd0, 0x00, 0xe2, 0x30, 0xad, 0x9f, 0xe6, 0x1e, 0x05,
+    0x9a, 0xad, 0x96, 0x9f, 0xfe, 0xab, 0x79, 0x9a, 0x62, 0xe0, 0xe6, 0x89,
+    0x68, 0x7a, 0x21, 0x04, 0xe2, 0x7f, 0xb4, 0xdf, 0xe0, 0xb6, 0x6c, 0xb4,
+    0xff, 0xff, 0x15, 0x8c, 0xfb, 0xff, 0xe5, 0xb3, 0x8f, 0xaf, 0x9f, 0x36,
+    0x5a, 0x7b, 0x9a, 0xc1, 0xf5, 0x14, 0x1a, 0x37, 0x9f, 0x82, 0x3d, 0xed,
+    0xad, 0x96, 0x86, 0x3e, 0xae, 0x1d, 0x4f, 0x13, 0x85, 0x6a, 0xd3, 0xff,
+    0xed, 0xec, 0x16, 0xcd, 0x19, 0xb9, 0x9a, 0xdf, 0xeb, 0x4f, 0xb3, 0x97,
+    0x0a, 0xfe, 0x9f, 0xc0, 0x44, 0x53, 0xf7, 0x74, 0x5e, 0x44, 0x1a, 0xd3,
+    0xf1, 0xdb, 0xcf, 0xac, 0xb1, 0x69, 0xff, 0xff, 0xe2, 0xe5, 0x1e, 0x84,
+    0x0f, 0x2b, 0xee, 0x7d, 0x13, 0x73, 0x5b, 0xd1, 0xd6, 0x8f, 0x51, 0xba,
+    0x46, 0x14, 0x63, 0x3f, 0x08, 0x30, 0xed, 0xa5, 0xa7, 0x7c, 0x2b, 0xad,
+    0x3f, 0xea, 0x1e, 0xe7, 0xfb, 0x55, 0xd5, 0x44, 0x23, 0x0c, 0x7c, 0xbb,
+    0x8e, 0xcf, 0xfe, 0x6c, 0xd8, 0x2e, 0x10, 0xee, 0xfc, 0xba, 0xd3, 0xff,
+    0xd5, 0x56, 0x05, 0x9a, 0xa3, 0x9a, 0xdb, 0x6d, 0x5a, 0x3d, 0x44, 0xeb,
+    0x89, 0x53, 0xfd, 0xeb, 0x5e, 0xed, 0x66, 0x5a, 0xb4, 0x61, 0xef, 0xd1,
+    0x2c, 0xeb, 0x6d, 0xb5, 0x29, 0xfe, 0xc0, 0x57, 0xf1, 0xde, 0x7a, 0x91,
+    0x8b, 0xf9, 0xad, 0xb5, 0x29, 0xd6, 0xdb, 0x6a, 0x53, 0xf5, 0x59, 0xee,
+    0x9a, 0xe9, 0x18, 0xbf, 0x81, 0x45, 0xe5, 0xa9, 0x1e, 0x46, 0xf3, 0xee,
+    0x97, 0xa1, 0x1d, 0x23, 0x1b, 0x39, 0xd6, 0xdb, 0x6a, 0x53, 0xae, 0xdf,
+    0x48, 0xc5, 0xfc, 0x80, 0x48, 0x82, 0xe2, 0xc4, 0xfd, 0xe8, 0xb3, 0xeb,
+    0xab, 0x4f, 0xe0, 0xbf, 0xe9, 0x3b, 0x6f, 0x56, 0x9f, 0xfb, 0x54, 0xf1,
+    0xa0, 0xdc, 0x12, 0x71, 0x69, 0xfb, 0x58, 0xef, 0x39, 0x75, 0xa3, 0xa7,
+    0xe5, 0xc4, 0x48, 0xfa, 0x3d, 0xf4, 0x58, 0x30, 0xa9, 0x86, 0x4d, 0x4f,
+    0x23, 0x1f, 0x9d, 0xb7, 0x9a, 0x1d, 0x32, 0xd3, 0xff, 0xb3, 0xcf, 0x42,
+    0x0c, 0xeb, 0x69, 0x8e, 0xb4, 0xfd, 0xd2, 0xbe, 0x89, 0xc4, 0xa7, 0xf0,
+    0xe6, 0xcf, 0xb9, 0x06, 0xb4, 0xf5, 0x57, 0xc3, 0x5a, 0x3c, 0x1e, 0xa5,
+    0x86, 0x73, 0xcd, 0x47, 0x76, 0x94, 0xeb, 0x6d, 0xb5, 0x29, 0xff, 0xe0,
+    0x98, 0x19, 0x83, 0xcd, 0x13, 0x0d, 0x89, 0x18, 0xbf, 0x96, 0x75, 0x13,
+    0xa7, 0x41, 0x86, 0x4f, 0x81, 0xe5, 0x7b, 0x25, 0x14, 0x20, 0x75, 0x0c,
+    0x29, 0xff, 0xf1, 0xf3, 0xac, 0x35, 0xcb, 0xfb, 0xbd, 0x7d, 0xeb, 0x4f,
+    0x9b, 0x97, 0x77, 0x8b, 0x43, 0x1f, 0xef, 0x15, 0x67, 0xff, 0x89, 0xde,
+    0x0f, 0xa3, 0x56, 0xe0, 0xd0, 0x6b, 0x4f, 0xff, 0xf7, 0xba, 0x2b, 0x71,
+    0xd4, 0x8f, 0x5c, 0xbe, 0xef, 0xcd, 0xb8, 0xb4, 0x62, 0x2e, 0xe9, 0x3e,
+    0x19, 0xb6, 0xc6, 0xb1, 0x25, 0xf1, 0xfa, 0xfb, 0x1a, 0xd6, 0x4e, 0x71,
+    0x75, 0xdc, 0xa3, 0x82, 0x72, 0x17, 0x3f, 0x8c, 0xb0, 0xf0, 0x99, 0xd4,
+    0x63, 0xf4, 0x5e, 0x08, 0x48, 0x0c, 0x63, 0xd7, 0x96, 0x07, 0xc9, 0x41,
+    0x1b, 0xc3, 0x46, 0xd8, 0x6e, 0x4e, 0x76, 0xc2, 0xb4, 0xff, 0xf6, 0x09,
+    0xb8, 0x19, 0x6d, 0x7d, 0x60, 0x29, 0x69, 0x6c, 0xf3, 0xeb, 0xf4, 0x72,
+    0x7e, 0xd3, 0x85, 0xa2, 0x3a, 0xd3, 0xfe, 0x16, 0xe6, 0xa8, 0x15, 0xb5,
+    0xd6, 0x9c, 0xe6, 0xff, 0x5a, 0x7f, 0xd4, 0x5f, 0xcd, 0x8d, 0x6d, 0xb6,
+    0xad, 0x14, 0x7b, 0xf7, 0x1e, 0x9f, 0xfe, 0x16, 0x7f, 0x80, 0xb8, 0x43,
+    0xbb, 0xf2, 0xeb, 0x46, 0x26, 0x77, 0xd2, 0xdd, 0x42, 0x70, 0x04, 0x33,
+    0xf9, 0x85, 0xe3, 0x98, 0x05, 0xa7, 0xf3, 0xf3, 0xf7, 0x16, 0xb1, 0x69,
+    0xff, 0xec, 0xe3, 0x0f, 0x73, 0x9a, 0x2f, 0x83, 0xab, 0x4f, 0xe6, 0x3d,
+    0xef, 0x43, 0x62, 0xd3, 0xea, 0xbe, 0x0f, 0x16, 0x9d, 0xca, 0xf3, 0xad,
+    0x3f, 0xb9, 0xa2, 0x30, 0x28, 0x96, 0x8f, 0x51, 0xe9, 0xa4, 0xd1, 0x32,
+    0xe1, 0x2e, 0xe3, 0xf3, 0xfb, 0x70, 0x36, 0x8a, 0x9e, 0xb4, 0xff, 0x77,
+    0x38, 0xce, 0xc8, 0x40, 0xb4, 0xff, 0xfd, 0xbb, 0x72, 0xf8, 0x3e, 0x3e,
+    0xc5, 0xe8, 0xd3, 0xd6, 0x82, 0x44, 0x98, 0x9c, 0x4f, 0xff, 0xc3, 0x97,
+    0xdf, 0xc6, 0x6a, 0x87, 0x1c, 0x7b, 0x6c, 0xb4, 0xff, 0xb2, 0xfb, 0xe7,
+    0xfb, 0x55, 0xd5, 0x44, 0x0d, 0x3d, 0xcd, 0x53, 0xfc, 0x22, 0x98, 0x57,
+    0x21, 0x93, 0x02, 0xc8, 0x63, 0xcf, 0xfa, 0xbf, 0x82, 0x0b, 0xf2, 0xfb,
+    0x2d, 0x3f, 0xff, 0xff, 0x67, 0x35, 0x42, 0x1f, 0x8b, 0xfe, 0xab, 0x8e,
+    0xf3, 0xdf, 0x18, 0x7a, 0x1d, 0x9e, 0xb8, 0x82, 0xe7, 0xfd, 0x54, 0x1f,
+    0x6b, 0xdf, 0x01, 0xda, 0xb8, 0x82, 0xe7, 0xfe, 0xd1, 0x68, 0x98, 0x79,
+    0xe0, 0x3b, 0x57, 0x10, 0x5c, 0xfe, 0x62, 0x1e, 0x78, 0x0e, 0xd5, 0xc4,
+    0x17, 0x3f, 0x1f, 0x3d, 0xf0, 0x1d, 0xab, 0x88, 0x2e, 0x7f, 0xff, 0xa8,
+    0x44, 0x8f, 0xe2, 0xfd, 0xd1, 0x7c, 0x83, 0xb3, 0x2d, 0x5c, 0x41, 0x73,
+    0x6d, 0xe3, 0xd4, 0xe6, 0x7a, 0xa1, 0xf5, 0x3a, 0x42, 0x13, 0xf8, 0x65,
+    0x59, 0x7a, 0x3e, 0x19, 0x46, 0x93, 0xf8, 0x98, 0x3b, 0xf2, 0xfb, 0x2d,
+    0x3d, 0x5f, 0x05, 0x2d, 0x3f, 0xf6, 0x8b, 0x44, 0xc3, 0xcf, 0x01, 0xda,
+    0xb8, 0x82, 0xe7, 0xf9, 0xcb, 0xf4, 0xac, 0xf0, 0x1d, 0xab, 0x88, 0x2e,
+    0x7d, 0xcb, 0xb1, 0xfc, 0x75, 0x13, 0xe1, 0x29, 0xcf, 0xfe, 0xf1, 0xdd,
+    0x17, 0x5b, 0x97, 0xf0, 0x1d, 0xab, 0x88, 0x2e, 0x7f, 0xff, 0xe1, 0x12,
+    0x3f, 0x8d, 0xf3, 0xc5, 0xfb, 0xa2, 0xf9, 0x07, 0x66, 0x5a, 0xb8, 0x82,
+    0xe3, 0x13, 0x24, 0xd9, 0x0e, 0x97, 0x67, 0xfb, 0x45, 0xf2, 0x0e, 0xcc,
+    0xb5, 0x71, 0x05, 0xcf, 0xff, 0x55, 0x6c, 0xfb, 0xe8, 0xbd, 0xf5, 0xbe,
+    0xc9, 0x4f, 0xfb, 0x1e, 0xfd, 0xef, 0xf1, 0xb3, 0xc9, 0x71, 0x05, 0xc7,
+    0x51, 0xcf, 0xf4, 0x7b, 0xa8, 0x4f, 0xfb, 0xa5, 0xfe, 0x50, 0x2f, 0xe2,
+    0xd5, 0xc4, 0x17, 0x3f, 0x68, 0xb5, 0xa2, 0x02, 0xa0, 0x0b, 0x9f, 0x60,
+    0x3c, 0x07, 0x6a, 0xe2, 0x0b, 0x9b, 0x39, 0xd3, 0xf1, 0xd1, 0xcc, 0x6c,
+    0x8e, 0xcb, 0xc2, 0xfe, 0x7e, 0x3e, 0x7b, 0xe0, 0x3b, 0x57, 0x10, 0x5c,
+    0xff, 0xbb, 0xa2, 0xf9, 0x07, 0x66, 0x5a, 0xb8, 0x82, 0xe6, 0xcf, 0x14,
+    0x88, 0xcb, 0x9f, 0xcf, 0xed, 0xc8, 0xf4, 0x3b, 0x3d, 0x71, 0x05, 0xcf,
+    0xfb, 0x09, 0xde, 0x0e, 0x7b, 0x4f, 0x5c, 0x41, 0x67, 0x3c, 0x08, 0xf5,
+    0x78, 0x03, 0xe6, 0xe0, 0x34, 0x18, 0xf8, 0xef, 0x18, 0xbf, 0x23, 0x1c,
+    0xde, 0x16, 0xb6, 0xb7, 0xcf, 0x81, 0x70, 0x01, 0x95, 0x10, 0x59, 0x91,
+    0x1b, 0x3f, 0xec, 0x7e, 0xa9, 0xee, 0xae, 0xbb, 0xd8, 0xb4, 0xe3, 0xb3,
+    0xd6, 0x9f, 0x67, 0xba, 0xde, 0xd5, 0xa5, 0xfa, 0x3c, 0x51, 0x1b, 0x9c,
+    0x5e, 0x58, 0xb4, 0xea, 0xf8, 0x16, 0x96, 0xcc, 0x6e, 0x38, 0x3b, 0x3f,
+    0x65, 0x95, 0xa6, 0xf3, 0xad, 0x04, 0x8b, 0x5a, 0x5e, 0x12, 0x79, 0xd5,
+    0xfb, 0x16, 0x98, 0x0c, 0xb4, 0xf1, 0x31, 0xf1, 0x68, 0x5a, 0x7e, 0xa0,
+    0xf8, 0xdf, 0x02, 0xd1, 0xe9, 0xb7, 0x10, 0xa9, 0xff, 0xfc, 0xc5, 0xe8,
+    0xb6, 0xfd, 0xe6, 0x77, 0xd6, 0xe8, 0x47, 0x5a, 0x60, 0x32, 0xd3, 0x30,
+    0x6b, 0x4f, 0xf6, 0x72, 0xec, 0x70, 0xb1, 0xc5, 0xa7, 0xf5, 0xf3, 0x45,
+    0x7d, 0xec, 0x5a, 0x6b, 0x6d, 0x4a, 0x7f, 0x87, 0x1d, 0xd3, 0xee, 0x5e,
+    0xad, 0x1d, 0x4f, 0xcc, 0x87, 0x3e, 0x2a, 0x75, 0x6d, 0x10, 0x81, 0x89,
+    0xd0, 0x15, 0x11, 0x6b, 0x9c, 0xda, 0x68, 0x10, 0xc4, 0xeb, 0x6d, 0xb5,
+    0x29, 0x1d, 0x23, 0x17, 0xf3, 0xea, 0x72, 0xab, 0xe9, 0x19, 0x1b, 0x81,
+    0x42, 0xf6, 0x7f, 0x6d, 0xc6, 0xcd, 0x65, 0x8b, 0x43, 0x36, 0x71, 0xb9,
+    0x1b, 0x28, 0x68, 0x5b, 0x17, 0x94, 0x64, 0xdf, 0x4b, 0xd4, 0x78, 0xf5,
+    0x49, 0x7f, 0x14, 0x6b, 0xc6, 0x81, 0xbc, 0xaf, 0xc7, 0x69, 0x73, 0xd9,
+    0xd6, 0xe2, 0xd3, 0xd8, 0x7c, 0xe2, 0xd3, 0xff, 0x6b, 0x7b, 0x37, 0x36,
+    0x8b, 0xb5, 0xf5, 0xa7, 0xaa, 0xc0, 0x9e, 0xb4, 0x32, 0x2a, 0xb6, 0x20,
+    0xe1, 0x03, 0xaa, 0x3c, 0xfc, 0x3b, 0xfa, 0x7a, 0x7a, 0xd3, 0xff, 0xdb,
+    0x3c, 0x5b, 0xc1, 0xc5, 0x83, 0xe1, 0x58, 0xb4, 0xfe, 0xbf, 0x1d, 0xe0,
+    0xe7, 0xab, 0x43, 0x22, 0xd0, 0x8b, 0xa9, 0x4a, 0x75, 0x78, 0x09, 0x69,
+    0xff, 0xe1, 0x7f, 0x8c, 0xf4, 0xaf, 0xb7, 0x37, 0xab, 0xad, 0x3e, 0xf1,
+    0xa6, 0xfb, 0xd6, 0x8f, 0x08, 0x9a, 0xc1, 0xeb, 0x54, 0xe7, 0xeb, 0x1c,
+    0x7f, 0x99, 0xfb, 0x16, 0x99, 0xf6, 0x2d, 0x3e, 0xd6, 0x13, 0xee, 0xb4,
+    0xff, 0xf6, 0x98, 0x23, 0x70, 0x68, 0x17, 0xbb, 0x01, 0x29, 0xfc, 0x0c,
+    0xff, 0x6a, 0xba, 0xb8, 0x81, 0x27, 0x70, 0xac, 0x5a, 0x1e, 0x8c, 0xff,
+    0x49, 0xbe, 0x9e, 0x73, 0xe9, 0x9d, 0x5e, 0xb4, 0xf7, 0x2c, 0xa1, 0x5a,
+    0x7b, 0x6b, 0xd7, 0x16, 0x8b, 0x0f, 0x73, 0x06, 0x74, 0x43, 0x3f, 0x86,
+    0xad, 0xbd, 0xd8, 0x0b, 0x4e, 0xb6, 0xdb, 0x57, 0x57, 0xd4, 0xea, 0x1f,
+    0x53, 0x57, 0xd0, 0xc6, 0xb2, 0x3d, 0x44, 0xb8, 0x17, 0xa7, 0xff, 0xd8,
+    0x24, 0x19, 0xaf, 0xcd, 0x6f, 0x4f, 0x7b, 0x2d, 0x16, 0x1f, 0xc8, 0x64,
+    0x93, 0xd9, 0xed, 0x3d, 0x69, 0xf5, 0x08, 0x91, 0xd6, 0x8f, 0x36, 0xad,
+    0x79, 0xe6, 0xd9, 0x0e, 0x62, 0x84, 0xd5, 0x46, 0x7e, 0x02, 0x41, 0x21,
+    0x9f, 0x17, 0x1b, 0x97, 0x4a, 0x7b, 0xad, 0xcb, 0xa5, 0x35, 0xb6, 0xa5,
+    0x0f, 0x3d, 0xfc, 0x26, 0xb4, 0x86, 0x6c, 0xb5, 0x23, 0x1a, 0xf9, 0xff,
+    0xf6, 0x71, 0xbb, 0x98, 0x3c, 0xd1, 0x30, 0xd8, 0xb4, 0x00, 0xfd, 0xed,
+    0x26, 0x9f, 0xff, 0xcc, 0xec, 0x84, 0x1e, 0x39, 0x7c, 0xee, 0xa8, 0x79,
+    0x75, 0xa7, 0xcf, 0xd6, 0xed, 0xf5, 0xa7, 0xfe, 0xa3, 0xfd, 0x9d, 0x93,
+    0xb1, 0xde, 0xeb, 0x46, 0xc7, 0xdf, 0xa2, 0x89, 0xff, 0x66, 0x39, 0xfc,
+    0xdc, 0xed, 0x75, 0xa1, 0xc3, 0xe1, 0xf9, 0x1c, 0xe7, 0xd7, 0xd6, 0x9f,
+    0x3f, 0x39, 0x9e, 0xa5, 0x22, 0x70, 0xf0, 0xb8, 0x37, 0x3d, 0xc0, 0xf3,
+    0x4b, 0x4c, 0x06, 0x5a, 0x60, 0x32, 0xd3, 0xed, 0xdf, 0x82, 0x62, 0x35,
+    0x40, 0x15, 0x86, 0x44, 0x48, 0xa6, 0x4f, 0xff, 0x60, 0xd6, 0xd7, 0x0c,
+    0x3a, 0xf1, 0xd3, 0x81, 0x69, 0xff, 0xb9, 0xac, 0x38, 0x4c, 0x0c, 0xdb,
+    0x8b, 0x4f, 0xed, 0xba, 0x5f, 0x09, 0xbd, 0x5a, 0x78, 0x07, 0xa7, 0xf8,
+    0x46, 0x6d, 0xd4, 0xf8, 0x8b, 0x3b, 0xcb, 0x36, 0x5a, 0x78, 0x1f, 0x2f,
+    0xad, 0x0c, 0x88, 0x9a, 0x49, 0xb4, 0x7e, 0x7a, 0xfb, 0xed, 0xc5, 0xa7,
+    0x5b, 0x6d, 0xa9, 0x4f, 0xb0, 0x31, 0xde, 0xe9, 0x18, 0xbf, 0x9f, 0x61,
+    0xad, 0xb6, 0xd5, 0xa1, 0x8f, 0x87, 0x86, 0xf3, 0xff, 0x60, 0xe5, 0xfb,
+    0xa2, 0xeb, 0x0a, 0xd3, 0xd6, 0xd0, 0xbd, 0x69, 0xfe, 0xe3, 0x6c, 0x0a,
+    0xd6, 0x89, 0x69, 0x69, 0x68, 0xc3, 0xc8, 0xe9, 0xc4, 0xeb, 0x6d, 0xb5,
+    0x29, 0xf8, 0xa8, 0x3d, 0x17, 0x12, 0x31, 0x7f, 0x3e, 0xc0, 0x66, 0x38,
+    0xb4, 0xaf, 0xe1, 0x14, 0x3f, 0x40, 0x13, 0xb9, 0xb7, 0x7f, 0xa9, 0xa0,
+    0xe4, 0x61, 0x52, 0x2d, 0x27, 0x70, 0x31, 0xc0, 0xcf, 0x57, 0xcb, 0x4b,
+    0x43, 0x2f, 0x6e, 0x3c, 0x8f, 0x23, 0x32, 0x0d, 0x97, 0xf0, 0xb1, 0xd4,
+    0x6e, 0xf4, 0x5f, 0x78, 0x52, 0x72, 0x3d, 0x9f, 0x22, 0xe9, 0xf9, 0x8f,
+    0xff, 0xd7, 0x16, 0x9f, 0xfe, 0x23, 0xec, 0xfb, 0xf8, 0xc1, 0x1c, 0x20,
+    0x2d, 0x1a, 0x3f, 0xbe, 0x16, 0x48, 0xce, 0x94, 0x2b, 0x0a, 0xdd, 0x39,
+    0x4f, 0x9a, 0x50, 0x3c, 0xd6, 0x54, 0xd3, 0x9a, 0xd6, 0x4a, 0x4c, 0x7c,
+    0xae, 0xcf, 0x65, 0xc7, 0xe5, 0x78, 0x10, 0x1c, 0x7a, 0x9d, 0x97, 0x31,
+    0xb4, 0xbd, 0xa2, 0x96, 0x16, 0xe4, 0xfa, 0xa7, 0xe7, 0xa1, 0x0f, 0x2c,
+    0x9f, 0x54, 0x98, 0xaa, 0xac, 0x5d, 0x41, 0x2f, 0xf8, 0x69, 0x19, 0xb7,
+    0xad, 0xcb, 0xb9, 0x5a, 0xa1, 0xef, 0x1b, 0xe3, 0xb8, 0x7a, 0x5b, 0x0c,
+    0x7f, 0x29, 0x72, 0x01, 0x52, 0x16, 0x5d, 0x63, 0x26, 0x83, 0x42, 0xbc,
+    0x7d, 0xf8, 0xac, 0xc0, 0x9f, 0xc6, 0xcf, 0xf6, 0xab, 0xaa, 0x8b, 0x8e,
+    0x7f, 0x1b, 0x3f, 0xda, 0xae, 0xaa, 0x2e, 0xb9, 0xff, 0x8d, 0x4f, 0x36,
+    0x7f, 0xb5, 0x5d, 0x54, 0x4a, 0x30, 0xd0, 0xb2, 0xa4, 0x79, 0xcf, 0xa7,
+    0xc1, 0x9f, 0x74, 0xf8, 0xa1, 0xf5, 0xe7, 0x40, 0xac, 0x57, 0xba, 0x5c,
+    0xe3, 0x87, 0xce, 0xa7, 0xd3, 0xff, 0x8c, 0x7a, 0x79, 0xb3, 0xfd, 0xaa,
+    0xea, 0xa2, 0x5a, 0x9f, 0x7f, 0xb5, 0x5d, 0x54, 0x46, 0xf3, 0xfe, 0xa7,
+    0x9b, 0x3f, 0xda, 0xae, 0xaa, 0x25, 0xf9, 0x1b, 0x0f, 0xf0, 0xe6, 0x73,
+    0xf8, 0xd9, 0xfe, 0xd5, 0x75, 0x51, 0x55, 0xce, 0x17, 0x5b, 0x56, 0x9f,
+    0xe0, 0xf0, 0x73, 0x6e, 0x51, 0xd6, 0x9b, 0xd2, 0x5a, 0x7e, 0xcf, 0xf6,
+    0xab, 0xaa, 0x89, 0x02, 0x3c, 0x1e, 0x71, 0x85, 0xa7, 0xd7, 0xa1, 0xad,
+    0x96, 0x87, 0x9e, 0x56, 0xc4, 0x93, 0xfd, 0x9f, 0xb0, 0xec, 0x2f, 0xba,
+    0xd3, 0xff, 0xb1, 0xcd, 0x51, 0xf9, 0xa6, 0xe6, 0xe7, 0x5a, 0x3d, 0x4e,
+    0x54, 0x31, 0xfa, 0x86, 0x80, 0x91, 0x84, 0x71, 0x3f, 0xf0, 0xe5, 0x86,
+    0xf2, 0x61, 0x1c, 0xe2, 0xd0, 0x64, 0x4a, 0xfd, 0x46, 0x7f, 0x1b, 0x3f,
+    0xda, 0xae, 0xaa, 0x2c, 0x89, 0xfc, 0x6c, 0xff, 0x6a, 0xba, 0xa8, 0xb5,
+    0xe7, 0xf1, 0xb3, 0xfd, 0xaa, 0xea, 0xa2, 0xe4, 0x9f, 0x7f, 0xb5, 0x5d,
+    0x54, 0x5d, 0x93, 0xfe, 0xa7, 0x9b, 0x3f, 0xda, 0xae, 0xaa, 0x28, 0xe9,
+    0x1b, 0x0f, 0xf0, 0xe6, 0x72, 0x7a, 0xd3, 0xef, 0xf6, 0xab, 0xaa, 0x8a,
+    0x56, 0x7f, 0xff, 0xfb, 0x4d, 0x63, 0x68, 0x9d, 0xd7, 0xba, 0x23, 0x77,
+    0x44, 0xe6, 0x9a, 0xcc, 0x5a, 0x67, 0x9b, 0x11, 0x66, 0xe1, 0x9c, 0xc6,
+    0x3e, 0xc8, 0xf2, 0xa8, 0x61, 0xc5, 0x8b, 0xc0, 0xcf, 0x86, 0x8e, 0xc4,
+    0xe5, 0x29, 0xa0, 0xe4, 0x60, 0x3e, 0xb9, 0xf7, 0x21, 0x74, 0xee, 0x31,
+    0x99, 0xfe, 0x79, 0xb3, 0xfd, 0xaa, 0xea, 0xa2, 0x38, 0x9f, 0xe2, 0x36,
+    0x7f, 0xb5, 0x5d, 0x54, 0x56, 0xb2, 0x35, 0x22, 0x1f, 0x88, 0x93, 0xff,
+    0x8c, 0x7a, 0x79, 0xb3, 0xfd, 0xaa, 0xea, 0xa2, 0x5b, 0x9b, 0x36, 0x5a,
+    0x7f, 0x7b, 0x87, 0x3b, 0x15, 0xd6, 0x8d, 0x8f, 0x20, 0x85, 0xa7, 0x6b,
+    0xd7, 0xad, 0x39, 0xe7, 0xea, 0xd3, 0xff, 0xf6, 0xab, 0x60, 0x7b, 0xaa,
+    0x7e, 0x5c, 0x77, 0xa0, 0x96, 0x85, 0x44, 0x37, 0x3f, 0xea, 0x79, 0xb3,
+    0xfd, 0xaa, 0xea, 0xa2, 0x60, 0x9b, 0xb8, 0xb4, 0xdb, 0x81, 0x28, 0x23,
+    0x59, 0xf1, 0x59, 0xfc, 0x39, 0xce, 0x37, 0xee, 0xb4, 0x8c, 0xc9, 0xca,
+    0xd8, 0x45, 0xe8, 0xee, 0x0e, 0x75, 0x74, 0xe2, 0xfc, 0x75, 0x08, 0x82,
+    0x71, 0xf7, 0xfa, 0x53, 0xfe, 0xa7, 0x9b, 0x3f, 0xda, 0xae, 0xaa, 0x26,
+    0x39, 0x18, 0x8f, 0x98, 0xe3, 0xb3, 0xf3, 0x5f, 0xc7, 0x33, 0x4b, 0x4e,
+    0x61, 0xb1, 0x69, 0xff, 0xff, 0xe7, 0xdf, 0x59, 0xbd, 0xb7, 0xd6, 0x77,
+    0x2f, 0xe3, 0x36, 0x7d, 0xc8, 0x49, 0x69, 0xee, 0xd5, 0x75, 0x51, 0x58,
+    0xcf, 0xfb, 0xcb, 0x38, 0x39, 0xbb, 0x0f, 0x16, 0x80, 0xd3, 0x35, 0xe9,
+    0x76, 0xc3, 0x7f, 0x84, 0x07, 0x0b, 0x67, 0xff, 0x30, 0xf0, 0x3d, 0xd8,
+    0x73, 0xad, 0xf5, 0xa7, 0xfb, 0xdd, 0x65, 0xf6, 0x7b, 0x69, 0x69, 0xfe,
+    0x6d, 0x9e, 0xe3, 0xeb, 0xf6, 0x2d, 0x18, 0x7e, 0xa4, 0x75, 0x3f, 0xec,
+    0xf7, 0xe5, 0xbd, 0x80, 0xbb, 0xd6, 0x9f, 0xff, 0xf8, 0x77, 0xb3, 0x3b,
+    0xe0, 0x77, 0x75, 0xf1, 0x9b, 0x3f, 0x37, 0x10, 0x5d, 0x69, 0xfd, 0xe6,
+    0xec, 0x71, 0xfe, 0x67, 0xec, 0x5a, 0x7f, 0xf6, 0x39, 0xaa, 0x3f, 0x34,
+    0xdc, 0xdc, 0xeb, 0x4e, 0xd1, 0x1b, 0x15, 0x3c, 0xf5, 0x4b, 0x50, 0xbd,
+    0x12, 0x0e, 0x20, 0xf9, 0x3e, 0x04, 0x85, 0x30, 0x40, 0x5a, 0x6d, 0xdc,
+    0x5a, 0x7d, 0x43, 0x66, 0xf7, 0x5a, 0x00, 0x7a, 0xe2, 0x2f, 0x71, 0x89,
+    0xd7, 0x0a, 0xeb, 0x4f, 0x6d, 0x63, 0x06, 0xb4, 0x7a, 0x78, 0x3b, 0x8e,
+    0xcf, 0x8f, 0x82, 0xcf, 0x5a, 0x79, 0xbf, 0x42, 0xb4, 0xf5, 0xee, 0xc0,
+    0x5a, 0x18, 0xf9, 0x74, 0x4b, 0x68, 0xfc, 0xf9, 0x9e, 0x0d, 0xde, 0xb4,
+    0xe6, 0x17, 0xad, 0x0e, 0x1e, 0x17, 0x0a, 0x27, 0x68, 0x23, 0xad, 0x3f,
+    0x31, 0xf0, 0x48, 0x35, 0xa5, 0x75, 0xa0, 0x8d, 0xdd, 0x15, 0xcc, 0x06,
+    0x4a, 0x6b, 0x6d, 0x4a, 0x08, 0xd6, 0xda, 0x2b, 0x3f, 0xa9, 0xe3, 0x9c,
+    0xd1, 0x24, 0x63, 0x43, 0x3d, 0xed, 0x6d, 0x75, 0xa7, 0x30, 0xb8, 0xb4,
+    0xc2, 0xcb, 0x43, 0x86, 0xbf, 0xe3, 0x73, 0xff, 0x06, 0x43, 0xdb, 0xb1,
+    0xeb, 0x6e, 0x2d, 0x38, 0x18, 0xea, 0xb4, 0x06, 0x7c, 0x5f, 0x44, 0x90,
+    0x6b, 0x4d, 0xf0, 0xd6, 0x82, 0x35, 0x01, 0x08, 0xcf, 0xfe, 0xe3, 0x3c,
+    0xb9, 0xac, 0xdb, 0x9b, 0xb2, 0xd2, 0xc5, 0xa0, 0x8f, 0x67, 0xc9, 0x2a,
+    0x19, 0x3b, 0xfc, 0x52, 0x28, 0x42, 0x69, 0x2e, 0x9e, 0xa1, 0x69, 0x1d,
+    0x69, 0x6b, 0x85, 0xd3, 0xb0, 0xa9, 0xf8, 0x0d, 0xac, 0x77, 0x4b, 0x4f,
+    0xc5, 0xcc, 0xd5, 0x06, 0xb4, 0xeb, 0x6d, 0xb5, 0x29, 0xff, 0xb3, 0xbe,
+    0xb5, 0x81, 0x66, 0xab, 0x64, 0x8c, 0x5f, 0xcf, 0x17, 0xdd, 0x7d, 0x5a,
+    0x5f, 0x5a, 0x7c, 0x72, 0xe0, 0x29, 0x68, 0xb0, 0xf6, 0xfc, 0xe4, 0xbb,
+    0x88, 0x4f, 0xee, 0x95, 0xc7, 0x1d, 0xd2, 0xd3, 0x67, 0x16, 0x8d, 0x8f,
+    0x1f, 0x46, 0x53, 0xdc, 0x1c, 0x7a, 0xd3, 0xff, 0x8a, 0xfa, 0xcf, 0x47,
+    0x1d, 0x8e, 0x5d, 0x68, 0xf9, 0xf4, 0xf0, 0x82, 0x46, 0x65, 0xf3, 0x0b,
+    0x1b, 0xfd, 0x84, 0x4e, 0x38, 0x91, 0x1f, 0xd6, 0x0e, 0xdb, 0xa8, 0xff,
+    0xe9, 0x98, 0x05, 0x0e, 0x81, 0x68, 0xa5, 0xde, 0x16, 0x1c, 0x7c, 0x0a,
+    0x11, 0x93, 0xef, 0xf6, 0xab, 0xaa, 0x8a, 0xde, 0x7f, 0xd4, 0xf3, 0x67,
+    0xfb, 0x55, 0xd5, 0x44, 0xe1, 0x23, 0x61, 0xfe, 0x1c, 0xce, 0x6d, 0xf4,
+    0xb4, 0xfb, 0xfd, 0xaa, 0xea, 0xa2, 0xd1, 0x9f, 0x9a, 0x87, 0x7f, 0x71,
+    0x69, 0x88, 0x35, 0xa7, 0xff, 0xd6, 0x37, 0x1b, 0xdf, 0xb6, 0xaa, 0xe3,
+    0x80, 0x5a, 0x7f, 0xcd, 0xb5, 0x79, 0xf4, 0x35, 0xe7, 0xb1, 0x68, 0x64,
+    0x4d, 0x69, 0x52, 0x58, 0xe2, 0x34, 0xaf, 0x0b, 0x09, 0x19, 0xd2, 0x4d,
+    0xdb, 0x05, 0xce, 0x67, 0xa8, 0x7f, 0x4f, 0x76, 0xab, 0xaa, 0x8b, 0x6a,
+    0x7e, 0xd3, 0x1d, 0x8b, 0xd5, 0xa3, 0xe7, 0xb3, 0xc2, 0xd9, 0xfe, 0x6f,
+    0xf8, 0xbb, 0x6a, 0x89, 0x68, 0xc3, 0xda, 0xb4, 0x8a, 0x7e, 0x0e, 0xbf,
+    0xee, 0xe2, 0xb4, 0xfa, 0xb6, 0x78, 0x57, 0x5a, 0x46, 0x0c, 0xf6, 0x1d,
+    0x97, 0xc1, 0x91, 0x4a, 0x07, 0xa9, 0xfc, 0x6c, 0xff, 0x6a, 0xba, 0xa8,
+    0xb9, 0x67, 0xf1, 0xb3, 0xfd, 0xaa, 0xea, 0xa2, 0xed, 0x86, 0x6d, 0x17,
+    0x6c, 0x28, 0x7c, 0xa3, 0x2f, 0x61, 0xbe, 0x1c, 0xbd, 0x52, 0xa4, 0x02,
+    0xf9, 0xe3, 0x69, 0xd4, 0x73, 0xa3, 0x1d, 0x2d, 0xc8, 0xf8, 0x7d, 0x3f,
+    0x8d, 0x9f, 0xed, 0x57, 0x55, 0x15, 0x3c, 0xc5, 0xc5, 0xa7, 0xbb, 0x55,
+    0xd5, 0x45, 0x73, 0x3f, 0x8d, 0x9f, 0xed, 0x57, 0x55, 0x16, 0x74, 0x7c,
+    0xfa, 0xf4, 0x5b, 0x3f, 0xfd, 0x9c, 0x6b, 0xf8, 0xde, 0xfc, 0x67, 0x1c,
+    0x25, 0xa7, 0xfd, 0xa2, 0xff, 0xba, 0xc2, 0x10, 0xd6, 0x9e, 0xa1, 0x6f,
+    0x56, 0x9f, 0x7f, 0xb5, 0x5d, 0x54, 0x48, 0x53, 0xfc, 0x5b, 0x5f, 0x82,
+    0xc7, 0xba, 0xd3, 0x3c, 0xd8, 0x7d, 0x60, 0x33, 0x9e, 0x74, 0xb4, 0xc7,
+    0x5a, 0x7f, 0x66, 0xaf, 0x7c, 0xfd, 0x8b, 0x48, 0xde, 0xaa, 0x44, 0xc8,
+    0x40, 0x11, 0x13, 0x8a, 0x67, 0x3e, 0xa8, 0x45, 0xdc, 0xb7, 0x84, 0xd3,
+    0xff, 0x8c, 0x7a, 0x79, 0xb3, 0xfd, 0xaa, 0xea, 0xa2, 0x7c, 0x8e, 0xab,
+    0x59, 0xf3, 0xca, 0x82, 0xd4, 0x20, 0xa7, 0xdf, 0xed, 0x57, 0x55, 0x15,
+    0x94, 0xff, 0xa9, 0xe6, 0xcf, 0xf6, 0xab, 0xaa, 0x89, 0xba, 0x62, 0x36,
+    0x1f, 0xe1, 0xcc, 0xe7, 0xff, 0x18, 0xf4, 0xf3, 0x67, 0xfb, 0x55, 0xd5,
+    0x44, 0xad, 0x3f, 0xe2, 0xbe, 0xe7, 0x12, 0x77, 0xbd, 0x2d, 0x3f, 0x85,
+    0xbf, 0x8e, 0xe8, 0xeb, 0x43, 0xcf, 0xc8, 0x90, 0x27, 0xdf, 0xed, 0x57,
+    0x55, 0x12, 0xe4, 0xff, 0x15, 0x3f, 0x82, 0xc7, 0xba, 0xd3, 0xce, 0xc8,
+    0x59, 0x69, 0xf1, 0x8f, 0x4f, 0x33, 0x22, 0xaf, 0x08, 0x74, 0x67, 0x46,
+    0xd3, 0xff, 0x1a, 0x9e, 0x6c, 0xff, 0x6a, 0xba, 0xa8, 0x8e, 0xe7, 0xfb,
+    0x9a, 0xc7, 0x9a, 0x86, 0xeb, 0x4f, 0xde, 0x60, 0xb7, 0x70, 0x56, 0x9b,
+    0x7d, 0x2d, 0x3f, 0x3a, 0x23, 0x9a, 0xae, 0x2d, 0x3f, 0xb2, 0xdb, 0xb0,
+    0xf2, 0xeb, 0x4f, 0xbf, 0xda, 0xae, 0xaa, 0x2a, 0x19, 0x9f, 0x8b, 0x4f,
+    0x6b, 0x99, 0x62, 0xd3, 0xec, 0xb2, 0x85, 0xda, 0xd3, 0xff, 0xff, 0xf9,
+    0x9f, 0xe3, 0x9a, 0x26, 0xbf, 0x8c, 0xdf, 0xac, 0xef, 0xc6, 0x7f, 0xf8,
+    0xef, 0x7a, 0xd2, 0xd1, 0x88, 0xe2, 0x12, 0x2b, 0x94, 0x4f, 0xff, 0xf6,
+    0xf5, 0xe7, 0x2b, 0x35, 0x45, 0xc6, 0xd1, 0x72, 0xf9, 0xea, 0xd2, 0x33,
+    0xa2, 0xa9, 0xa9, 0xd2, 0x2f, 0xf3, 0x05, 0xec, 0x30, 0xc3, 0x2e, 0x99,
+    0xf2, 0x1e, 0xfe, 0x45, 0xd3, 0xef, 0xf6, 0xab, 0xaa, 0x8a, 0xa2, 0x7f,
+    0xd4, 0xf3, 0x67, 0xfb, 0x55, 0xd5, 0x44, 0xd7, 0x23, 0x61, 0xfe, 0x1c,
+    0xce, 0x7f, 0x1b, 0x3f, 0xda, 0xae, 0xaa, 0x2a, 0xc9, 0xff, 0x1b, 0x4d,
+    0xb7, 0x1b, 0x55, 0xe7, 0x5a, 0x7f, 0xe3, 0x53, 0xcd, 0x9f, 0xed, 0x57,
+    0x55, 0x12, 0x24, 0xfb, 0xfd, 0xaa, 0xea, 0xa2, 0xd2, 0x9f, 0xf5, 0x3c,
+    0xd9, 0xfe, 0xd5, 0x75, 0x51, 0x3e, 0xc8, 0xd8, 0x7f, 0x87, 0x33, 0x9f,
+    0xfc, 0x63, 0xd3, 0xcd, 0x9f, 0xed, 0x57, 0x55, 0x14, 0x24, 0xfb, 0x45,
+    0x63, 0x7d, 0x69, 0xf7, 0xfb, 0x55, 0xd5, 0x45, 0x1f, 0x3f, 0xe1, 0x67,
+    0x18, 0x59, 0xcd, 0x32, 0xd3, 0xff, 0xf6, 0x7b, 0xa6, 0x08, 0xdc, 0x1a,
+    0x05, 0xee, 0xc0, 0x4a, 0x7c, 0x63, 0xd3, 0xcc, 0xc8, 0xf1, 0xc2, 0x7e,
+    0x19, 0xf9, 0x1e, 0x43, 0x32, 0x3f, 0xec, 0x8d, 0xc9, 0xea, 0xf8, 0x9e,
+    0x1c, 0xaa, 0x1e, 0xc6, 0x19, 0xb1, 0x39, 0x1f, 0x38, 0x85, 0xa8, 0x65,
+    0x80, 0x9f, 0x91, 0xa3, 0x4f, 0xe3, 0x67, 0xfb, 0x55, 0xd5, 0x44, 0x45,
+    0x3f, 0x67, 0xfb, 0x55, 0xd5, 0x44, 0x57, 0x3f, 0xde, 0x73, 0x67, 0xfb,
+    0x55, 0xd5, 0x45, 0x71, 0x06, 0x44, 0x05, 0x1c, 0x4f, 0x66, 0xab, 0x8b,
+    0x4f, 0xec, 0x2f, 0x80, 0x1b, 0xdd, 0x69, 0x3a, 0x22, 0x7a, 0x77, 0x20,
+    0x9f, 0xff, 0xb9, 0x72, 0xd5, 0x13, 0xc8, 0x79, 0xbe, 0xbf, 0x8b, 0x4f,
+    0xbf, 0xda, 0xae, 0xaa, 0x29, 0xe9, 0xef, 0x03, 0x4f, 0x5a, 0x7d, 0x59,
+    0xa2, 0x3a, 0xd2, 0xcb, 0x9e, 0x3b, 0xb2, 0x28, 0xf3, 0x13, 0x28, 0x62,
+    0xcc, 0x59, 0x17, 0xa9, 0xff, 0xd4, 0xf3, 0x7a, 0x35, 0x6d, 0xee, 0xc0,
+    0x5a, 0x0c, 0x88, 0xaf, 0x50, 0x27, 0x1b, 0xdc, 0x5a, 0x7f, 0xfd, 0xa6,
+    0xfe, 0x3c, 0xab, 0x99, 0xe9, 0x6f, 0xd5, 0xa7, 0xcc, 0xf0, 0x6e, 0xf5,
+    0xa7, 0xbb, 0x55, 0xd5, 0x45, 0x67, 0x0e, 0x1e, 0xaf, 0xca, 0x27, 0xeb,
+    0x0e, 0xc2, 0xfb, 0xad, 0x39, 0xac, 0x25, 0xa7, 0xdc, 0x00, 0x42, 0xf5,
+    0xa7, 0x6f, 0x57, 0x5a, 0x7d, 0x8e, 0x59, 0xb8, 0x16, 0x91, 0xbd, 0x4e,
+    0x0b, 0x21, 0x53, 0xf2, 0x3d, 0x16, 0xd0, 0xd8, 0x94, 0x04, 0x39, 0x3f,
+    0xf1, 0xa9, 0xe6, 0xcf, 0xf6, 0xab, 0xaa, 0x89, 0x16, 0x7e, 0xcf, 0xf6,
+    0xab, 0xaa, 0x8b, 0x26, 0x7f, 0xf7, 0x2e, 0x15, 0xcd, 0x96, 0x10, 0xbe,
+    0xeb, 0x41, 0x91, 0x07, 0x87, 0x13, 0xf8, 0xd9, 0xfe, 0xd5, 0x75, 0x51,
+    0x6c, 0x4e, 0xcb, 0xe2, 0xd3, 0xdd, 0xaa, 0xea, 0xa2, 0xdb, 0x9e, 0xbd,
+    0x95, 0xf5, 0xa3, 0xe7, 0x9f, 0xc2, 0xd9, 0x19, 0xe8, 0x8b, 0xc6, 0x99,
+    0xd6, 0x68, 0x96, 0x9f, 0xf7, 0x99, 0xe6, 0x3a, 0x7e, 0x6b, 0x05, 0x80,
+    0xb4, 0xfc, 0xc2, 0xff, 0x77, 0x3a, 0xd3, 0xef, 0xf6, 0xab, 0xaa, 0x8b,
+    0xc2, 0x7b, 0x9e, 0x59, 0xa5, 0xa7, 0xfe, 0x60, 0x8f, 0xb3, 0xf9, 0x83,
+    0xcb, 0xad, 0x3e, 0xc1, 0x03, 0xab, 0x2d, 0x3e, 0x60, 0xb7, 0xab, 0xad,
+    0x3b, 0x8c, 0x05, 0xa4, 0x6f, 0x31, 0x39, 0xef, 0x34, 0x8e, 0x58, 0x9b,
+    0x85, 0xdb, 0x19, 0xe8, 0x90, 0x08, 0xa2, 0x51, 0xc2, 0x89, 0xc5, 0x9b,
+    0x2d, 0x3e, 0xff, 0x6a, 0xba, 0xa8, 0xbd, 0x27, 0xfc, 0x35, 0xc7, 0xb0,
+    0x7c, 0x2b, 0x16, 0x9f, 0x61, 0xf5, 0x5e, 0xad, 0x23, 0x7a, 0x8b, 0x3c,
+    0x1b, 0x08, 0xcd, 0xd4, 0xfa, 0x19, 0x94, 0x4b, 0x64, 0x2f, 0xb2, 0x51,
+    0x3f, 0x49, 0x0a, 0x39, 0xef, 0xb7, 0x9e, 0x1a, 0x40, 0x22, 0x18, 0x64,
+    0xef, 0x1e, 0x35, 0xb1, 0xa2, 0xcd, 0xbe, 0x96, 0x9e, 0xcd, 0x57, 0x16,
+    0x9f, 0xd8, 0x5f, 0x00, 0x37, 0xba, 0xd2, 0x74, 0x44, 0xf4, 0xee, 0x41,
+    0x3e, 0x2e, 0x36, 0xd6, 0x2d, 0x3e, 0xff, 0x6a, 0xba, 0xa8, 0x88, 0xe7,
+    0xff, 0xb5, 0xbd, 0xef, 0x87, 0x1c, 0x77, 0xe1, 0x9d, 0x32, 0xd3, 0xfe,
+    0x7b, 0x59, 0xfc, 0xe7, 0x0b, 0x8b, 0x4f, 0xf6, 0x7f, 0x2f, 0x94, 0x36,
+    0x2d, 0x3f, 0xff, 0xcd, 0xaa, 0x2e, 0x36, 0x87, 0x39, 0xa2, 0xd6, 0x15,
+    0xab, 0x4d, 0x61, 0xd2, 0x9a, 0xdb, 0x52, 0x9f, 0xf1, 0xbb, 0xa2, 0x73,
+    0x4d, 0x61, 0x80, 0x6b, 0xed, 0x17, 0x9e, 0x76, 0xdc, 0x65, 0xa1, 0xe7,
+    0xf4, 0x4b, 0x13, 0xf7, 0x9c, 0x73, 0x55, 0xc5, 0xa7, 0xe6, 0x0f, 0x04,
+    0x83, 0x5a, 0x7e, 0xce, 0x3a, 0xf3, 0x34, 0xb4, 0x62, 0x22, 0x84, 0xbe,
+    0xe5, 0x93, 0xff, 0xf7, 0x4d, 0xfa, 0x12, 0xe1, 0xbe, 0xdc, 0x1a, 0x02,
+    0xd0, 0xe9, 0x2b, 0xfa, 0xf3, 0x1a, 0x98, 0xb3, 0x0a, 0x3a, 0x67, 0xb2,
+    0xc9, 0x1f, 0x7c, 0xda, 0xa3, 0x0b, 0xe4, 0x2a, 0xdd, 0x97, 0x4f, 0xbf,
+    0xda, 0xae, 0xaa, 0x22, 0xe9, 0xf7, 0x00, 0x10, 0xbd, 0x29, 0x1b, 0x0f,
+    0x6e, 0x8c, 0xe0, 0xc9, 0x97, 0xbe, 0x30, 0x99, 0xff, 0x8f, 0x4f, 0x36,
+    0x7f, 0xb5, 0x5d, 0x54, 0x4c, 0xd3, 0x5d, 0xeb, 0x4f, 0x9d, 0x3b, 0xa3,
+    0x76, 0xe2, 0xd0, 0xe9, 0xcf, 0x23, 0xcd, 0x62, 0xd3, 0xb6, 0x6b, 0xad,
+    0x3b, 0xa4, 0x75, 0xa6, 0xf2, 0xf3, 0x6b, 0x4f, 0xfe, 0xd3, 0x1e, 0xb9,
+    0x9b, 0x00, 0xe1, 0x69, 0x69, 0xfb, 0x99, 0x66, 0x01, 0xc5, 0xa7, 0xfb,
+    0xdf, 0x18, 0x35, 0xf0, 0x79, 0x2d, 0x1e, 0x6d, 0x1a, 0xa4, 0x3e, 0xe2,
+    0x5e, 0x8b, 0xa7, 0xdd, 0xad, 0x13, 0x8b, 0x4f, 0xff, 0x81, 0xb3, 0xf5,
+    0xbb, 0x7c, 0xda, 0x2e, 0xd7, 0xd6, 0x9f, 0xf9, 0xd4, 0xb8, 0x5d, 0x2f,
+    0x79, 0x9d, 0x5a, 0x7f, 0xff, 0xb7, 0xa1, 0xe8, 0xe7, 0xba, 0xdf, 0xc6,
+    0x99, 0xff, 0x6b, 0x16, 0x86, 0x4c, 0x1f, 0x15, 0xf4, 0x8d, 0x3f, 0xfe,
+    0xf4, 0x86, 0xcc, 0xb9, 0x56, 0x8d, 0x6d, 0xb6, 0xa5, 0x3f, 0x6c, 0xfb,
+    0x83, 0x77, 0x16, 0x9e, 0xed, 0x57, 0x55, 0x16, 0x7c, 0xff, 0x8b, 0x4c,
+    0xf2, 0xe3, 0x72, 0xeb, 0x4f, 0xff, 0x17, 0xf5, 0x5e, 0x31, 0xd8, 0xe5,
+    0xf0, 0x56, 0x9d, 0x6d, 0xb6, 0xa5, 0x3f, 0xea, 0x7d, 0xc7, 0x3b, 0xee,
+    0x7d, 0x23, 0x17, 0xf3, 0xff, 0x36, 0xcf, 0x1d, 0xc1, 0xe3, 0xa7, 0x02,
+    0xd3, 0xfc, 0xda, 0x2f, 0x46, 0xa9, 0xc5, 0xa7, 0xf8, 0x87, 0xd0, 0xbd,
+    0xdf, 0x97, 0x5a, 0x3a, 0xa9, 0x9d, 0xc5, 0x8f, 0x98, 0x9c, 0xb7, 0x47,
+    0x80, 0x6e, 0xba, 0x67, 0x12, 0x1d, 0x9b, 0xcf, 0xf7, 0xea, 0xdd, 0x13,
+    0x7d, 0x96, 0x9f, 0xff, 0xff, 0x60, 0x2f, 0x98, 0x21, 0x85, 0xf1, 0x6c,
+    0xd1, 0xae, 0x39, 0x61, 0xf0, 0xeb, 0x4f, 0x9d, 0xd6, 0x98, 0x25, 0xa3,
+    0x11, 0x54, 0x50, 0x81, 0x9d, 0x76, 0xb1, 0x69, 0xde, 0x59, 0xa5, 0xa1,
+    0xe7, 0xc1, 0x72, 0x6e, 0x0e, 0x4e, 0xd6, 0xf6, 0xad, 0x38, 0x1b, 0xf5,
+    0x69, 0xdc, 0xc0, 0x96, 0x8f, 0x4f, 0x5f, 0x61, 0xe2, 0x1d, 0x9f, 0xbe,
+    0x4e, 0xf0, 0x6e, 0xb4, 0xfb, 0x42, 0xd9, 0xf5, 0x27, 0xfc, 0x5f, 0x7e,
+    0x7e, 0xcd, 0xeb, 0xd5, 0x44, 0x1a, 0x63, 0x4b, 0x3e, 0xae, 0x91, 0xd9,
+    0x69, 0xf9, 0xfa, 0x1a, 0xdb, 0x8b, 0x4b, 0x3a, 0x7a, 0x42, 0x4b, 0x3f,
+    0xf6, 0x0e, 0xdc, 0xcf, 0x95, 0x94, 0x75, 0xa6, 0x21, 0x5a, 0x7e, 0xab,
+    0x79, 0x9a, 0xe3, 0x1e, 0xb8, 0x68, 0x70, 0xc9, 0xe1, 0xbd, 0x4b, 0x21,
+    0x5e, 0x2f, 0xb3, 0xf7, 0xf3, 0xdb, 0xe9, 0x96, 0x9f, 0xff, 0xdb, 0x8d,
+    0x07, 0xe0, 0x21, 0xae, 0x5c, 0xb6, 0xd1, 0x5a, 0xb4, 0xff, 0x8f, 0x9c,
+    0xb8, 0x57, 0xa7, 0xe2, 0xd3, 0xf5, 0xee, 0xdf, 0xe3, 0x2c, 0x63, 0x7d,
+    0x3d, 0xac, 0x27, 0x6b, 0x4f, 0xd7, 0x2f, 0xe6, 0xff, 0x5a, 0x09, 0x11,
+    0x7a, 0x3c, 0xe1, 0x14, 0xc7, 0x74, 0x55, 0x17, 0xe4, 0xff, 0xcf, 0xe6,
+    0xef, 0x79, 0xf9, 0xc6, 0x3a, 0xd3, 0xff, 0x16, 0x0e, 0x65, 0xfc, 0x3e,
+    0xe7, 0x5a, 0x36, 0x44, 0x4d, 0xd1, 0xa7, 0x06, 0xdf, 0x5a, 0x7e, 0xf5,
+    0x81, 0xfc, 0xd9, 0x68, 0x31, 0xe5, 0x1c, 0x72, 0x62, 0x71, 0x69, 0xdc,
+    0x2b, 0x16, 0x9c, 0x2d, 0xd5, 0xa3, 0xc1, 0xe6, 0x1c, 0x58, 0x47, 0x21,
+    0x93, 0xec, 0xf4, 0xbf, 0x21, 0x62, 0x4d, 0xd4, 0xdd, 0x3d, 0x5c, 0x6d,
+    0x96, 0x9f, 0xff, 0xf3, 0x68, 0x8e, 0x67, 0x1f, 0x5f, 0x0b, 0x45, 0xb5,
+    0xfa, 0x56, 0x2d, 0x0e, 0x22, 0x41, 0xd4, 0x86, 0x7e, 0xaf, 0xb6, 0x82,
+    0xf5, 0x69, 0xeb, 0x6b, 0x2e, 0xb4, 0xff, 0x3c, 0xf4, 0xfe, 0x5d, 0x83,
+    0x5a, 0x18, 0xf6, 0xa8, 0x86, 0x7b, 0x2e, 0x42, 0xb4, 0x52, 0x31, 0xc6,
+    0x11, 0x1b, 0x90, 0x4f, 0x05, 0xbd, 0x5d, 0x69, 0xe0, 0x03, 0x36, 0x5a,
+    0x7e, 0x75, 0xe6, 0x50, 0xf5, 0x69, 0xfe, 0xb8, 0x0b, 0x6d, 0x9f, 0x9c,
+    0x5a, 0x7e, 0x6d, 0xae, 0x72, 0xf3, 0xad, 0x1f, 0x45, 0xde, 0x88, 0xb8,
+    0x5c, 0xec, 0xea, 0x19, 0x31, 0xdc, 0x86, 0xf4, 0xce, 0x6e, 0xb4, 0x8e,
+    0xb4, 0x6c, 0x6a, 0x1d, 0x01, 0x89, 0xfd, 0x55, 0xb3, 0xc5, 0xbd, 0x5a,
+    0x7f, 0xf0, 0x93, 0x5c, 0x69, 0xfe, 0x2f, 0x9f, 0x5a, 0x7f, 0xff, 0xda,
+    0x2d, 0xb9, 0x9b, 0x73, 0xff, 0x6e, 0x00, 0x21, 0x7e, 0xb1, 0x69, 0xef,
+    0x7d, 0xa1, 0x5a, 0x7f, 0xd5, 0xae, 0x95, 0x78, 0xbd, 0x69, 0x69, 0xfe,
+    0xd1, 0x50, 0x33, 0xda, 0x7a, 0xd0, 0xc9, 0xd3, 0x7a, 0x4f, 0x86, 0x5d,
+    0x48, 0x26, 0xed, 0x11, 0x70, 0xfa, 0x7f, 0xec, 0x1d, 0xb9, 0x9f, 0x2b,
+    0x28, 0xeb, 0x4f, 0xb3, 0x8f, 0x3e, 0x96, 0x9b, 0xc6, 0x2d, 0x3d, 0x71,
+    0x63, 0xad, 0x0c, 0x6d, 0xf6, 0x17, 0x86, 0x46, 0x15, 0xd0, 0xf7, 0x5e,
+    0x96, 0x96, 0x9a, 0xef, 0x5a, 0x00, 0x69, 0xb7, 0x10, 0x9f, 0xac, 0x71,
+    0xfe, 0x67, 0xec, 0x5a, 0x7f, 0x07, 0xac, 0xe6, 0x8b, 0x8b, 0x4c, 0x5f,
+    0x5a, 0x3c, 0xd9, 0xff, 0x11, 0xb6, 0x8c, 0xe7, 0xfe, 0xf5, 0xbd, 0xfb,
+    0x70, 0xba, 0x5e, 0xad, 0x3f, 0x6b, 0x7b, 0x1c, 0xd1, 0x2d, 0x3c, 0x23,
+    0x9c, 0x5a, 0x3d, 0x44, 0xa6, 0x91, 0x78, 0x61, 0x23, 0x79, 0xb6, 0xd4,
+    0xb1, 0xd2, 0x30, 0x74, 0xe3, 0x8d, 0x0f, 0x0b, 0x10, 0xfd, 0x8c, 0xbb,
+    0x25, 0x4b, 0x07, 0x08, 0x3d, 0xa3, 0x41, 0x28, 0x43, 0x39, 0x1f, 0x9f,
+    0xd0, 0x0e, 0x5b, 0xa9, 0x63, 0x55, 0x0d, 0xd0, 0x43, 0xb8, 0x63, 0x51,
+    0xbc, 0x7e, 0xbc, 0x8c, 0x96, 0xd5, 0x6f, 0x28, 0x50, 0x05, 0x0c, 0x88,
+    0x33, 0x6e, 0xc1, 0xaa, 0xd7, 0x0e, 0x7f, 0xf1, 0x8f, 0x4f, 0x36, 0x7f,
+    0xb5, 0x5d, 0x54, 0x4d, 0x93, 0xf8, 0xd9, 0xfe, 0xd5, 0x75, 0x51, 0x56,
+    0xcf, 0xe7, 0xbf, 0x7e, 0x0b, 0x3d, 0x69, 0xec, 0xd5, 0x71, 0x69, 0x3a,
+    0x38, 0x7a, 0x62, 0x67, 0x3e, 0xff, 0x6a, 0xba, 0xa8, 0xad, 0x27, 0xff,
+    0xba, 0xdf, 0xc0, 0x51, 0xe9, 0xec, 0x5d, 0x5a, 0x7f, 0xf9, 0xf7, 0xc1,
+    0x63, 0xd6, 0x73, 0x8c, 0x75, 0xa6, 0xe7, 0x19, 0x13, 0x14, 0x99, 0x3f,
+    0x99, 0xd8, 0x5c, 0x16, 0x02, 0xd3, 0xf5, 0x99, 0xa2, 0xc3, 0xad, 0x3e,
+    0x73, 0x3d, 0x3f, 0x9d, 0x69, 0xf8, 0x5a, 0xdd, 0x9f, 0x75, 0xa5, 0x8e,
+    0x1e, 0xdb, 0xa9, 0x6c, 0xfe, 0x7e, 0x72, 0x84, 0x1b, 0xad, 0x23, 0x79,
+    0x8a, 0x8e, 0xf0, 0xac, 0xa1, 0x97, 0xa2, 0xda, 0x34, 0x18, 0x43, 0xf0,
+    0xae, 0x7f, 0x1b, 0x3f, 0xda, 0xae, 0xaa, 0x2c, 0x09, 0xf7, 0xfb, 0x55,
+    0xd5, 0x44, 0xeb, 0x3f, 0xff, 0xb4, 0xd6, 0x7b, 0x87, 0x35, 0xef, 0x9a,
+    0x2b, 0xef, 0x62, 0xd3, 0xe3, 0x1e, 0x9e, 0x6c, 0x44, 0xbb, 0x86, 0x73,
+    0xf9, 0xf7, 0x30, 0x61, 0xb1, 0xd6, 0x9f, 0x7f, 0xb5, 0x5d, 0x54, 0x5b,
+    0x33, 0xfe, 0x03, 0x5c, 0xda, 0x2e, 0xd7, 0xd6, 0x91, 0xb0, 0xfc, 0x28,
+    0xce, 0x7b, 0xb5, 0x5d, 0x54, 0x5c, 0xd2, 0x3a, 0xd1, 0xf3, 0x7b, 0x69,
+    0x6c, 0xce, 0x1d, 0x69, 0x1b, 0x0d, 0xcd, 0xa4, 0x53, 0xef, 0xf6, 0xab,
+    0xaa, 0x8b, 0xbe, 0x7f, 0x3c, 0xd7, 0xff, 0xca, 0xd5, 0xa4, 0x6c, 0x3e,
+    0x7a, 0x33, 0x9e, 0x30, 0x7e, 0x81, 0x68, 0x66, 0xfa, 0x0b, 0x2b, 0x78,
+    0xae, 0x99, 0x6c, 0xaa, 0x52, 0xb3, 0x3e, 0xee, 0x78, 0x6a, 0xd2, 0x00,
+    0x21, 0x4b, 0x78, 0x4e, 0x72, 0x11, 0xc1, 0x13, 0x4f, 0xaf, 0x73, 0xd3,
+    0xd6, 0x9f, 0xfb, 0x6e, 0xef, 0x5b, 0x73, 0x30, 0x43, 0x5a, 0x70, 0xd1,
+    0x98, 0xfb, 0x78, 0x4f, 0x3f, 0x86, 0xcc, 0x75, 0xe3, 0x06, 0xb4, 0xfb,
+    0xfd, 0xaa, 0xea, 0xa2, 0x57, 0x9f, 0xf0, 0xd5, 0xbe, 0xe9, 0xac, 0xcb,
+    0x56, 0x9f, 0xff, 0x9f, 0x84, 0x0c, 0x39, 0x72, 0xec, 0x7a, 0xdb, 0x8b,
+    0x4f, 0x6f, 0x5f, 0x7a, 0xd3, 0xff, 0xf8, 0xb9, 0x47, 0xa1, 0x06, 0xad,
+    0xa1, 0xb3, 0xa5, 0x62, 0xd1, 0xea, 0x20, 0xa8, 0x8a, 0x3d, 0x4c, 0xfb,
+    0x10, 0x35, 0x0d, 0xb9, 0xff, 0x72, 0x9f, 0x7d, 0x37, 0xc2, 0xf5, 0x69,
+    0xff, 0xb8, 0x4e, 0xcb, 0x8e, 0x3d, 0x87, 0x8b, 0x4e, 0xa7, 0x99, 0x95,
+    0x31, 0x61, 0xb5, 0xe3, 0x71, 0xe1, 0xb0, 0x48, 0x13, 0xff, 0xb3, 0x46,
+    0x1c, 0xf4, 0x87, 0x99, 0xa5, 0xa7, 0x71, 0xbd, 0x4a, 0x7f, 0xf6, 0xa8,
+    0xb8, 0xcf, 0x2f, 0xd9, 0xb8, 0x12, 0x9f, 0xd5, 0xd3, 0x7b, 0xf7, 0x40,
+    0xcc, 0x7c, 0xd7, 0x1c, 0x91, 0xba, 0xaf, 0xc8, 0xf2, 0xa4, 0xf8, 0xc4,
+    0xee, 0x15, 0xb3, 0xff, 0x8c, 0x7a, 0x79, 0xb3, 0xfd, 0xaa, 0xea, 0xa2,
+    0x61, 0x9f, 0xfc, 0x2c, 0xec, 0x5b, 0x63, 0x79, 0xb7, 0x4f, 0x77, 0xad,
+    0x3f, 0xfb, 0xf4, 0x03, 0x07, 0xc7, 0xda, 0xd7, 0x7a, 0xd3, 0x61, 0xbd,
+    0x45, 0x18, 0x4a, 0xf3, 0xff, 0x3a, 0x39, 0xb3, 0xf7, 0xae, 0x0b, 0x3d,
+    0x69, 0xfc, 0xd5, 0x67, 0x03, 0xaf, 0xad, 0x3e, 0xaf, 0xbe, 0x8e, 0xb4,
+    0x09, 0xec, 0xee, 0x67, 0x3f, 0x1d, 0xb0, 0x79, 0xe4, 0xb4, 0xae, 0xb4,
+    0xf9, 0xb0, 0x79, 0xe4, 0xb4, 0xfd, 0xa2, 0xe5, 0xeb, 0x6f, 0x07, 0xcc,
+    0xe1, 0x71, 0xc4, 0x27, 0xff, 0xfc, 0x39, 0x6b, 0xaf, 0x33, 0x5e, 0x07,
+    0x2c, 0x2c, 0x1d, 0x9f, 0x75, 0xa7, 0xff, 0x9b, 0x83, 0x40, 0xd6, 0x17,
+    0xbb, 0xf2, 0xeb, 0x4f, 0xce, 0xc2, 0xe0, 0xb0, 0x16, 0x9f, 0xfc, 0xdc,
+    0x03, 0x3f, 0x36, 0xe5, 0x9b, 0xda, 0xb4, 0x31, 0xfe, 0x11, 0x7c, 0xfd,
+    0x72, 0x0c, 0xf5, 0xc5, 0xa7, 0xff, 0xfd, 0xfc, 0x76, 0xc3, 0xcf, 0x01,
+    0x0b, 0x6a, 0x8b, 0x8d, 0xcb, 0xad, 0x1b, 0x22, 0x6b, 0xe5, 0xb3, 0xde,
+    0x1d, 0xba, 0xd8, 0xb4, 0x61, 0xe7, 0x06, 0x49, 0x3f, 0xfe, 0xd0, 0xe7,
+    0x34, 0x59, 0xb7, 0x31, 0xdb, 0x5d, 0x69, 0xcc, 0x00, 0x96, 0x8c, 0x3f,
+    0x11, 0x55, 0x9e, 0xa0, 0xbd, 0xc5, 0xa4, 0x6f, 0x31, 0x72, 0x5f, 0xd8,
+    0x51, 0x76, 0x11, 0x0e, 0x2a, 0xfd, 0xc3, 0x50, 0xcb, 0x18, 0xc2, 0x39,
+    0x09, 0x3d, 0xc8, 0x27, 0xff, 0xbe, 0x5b, 0x3e, 0xe5, 0xcd, 0x37, 0xf8,
+    0xcb, 0x4f, 0xbf, 0xda, 0xae, 0xaa, 0x2a, 0xe9, 0xfe, 0x79, 0xb3, 0xfd,
+    0xaa, 0xea, 0xa2, 0x3c, 0x91, 0xbd, 0x46, 0x36, 0x27, 0xd1, 0x9c, 0xfe,
+    0x36, 0x7f, 0xb5, 0x5d, 0x54, 0x58, 0x33, 0xf8, 0xd9, 0xfe, 0xd5, 0x75,
+    0x51, 0x65, 0x4f, 0xe3, 0x67, 0xfb, 0x55, 0xd5, 0x45, 0xa7, 0x3f, 0xb2,
+    0xfe, 0x3f, 0xfd, 0xf4, 0xb4, 0xf7, 0x6a, 0xba, 0xa8, 0xb7, 0x27, 0xfe,
+    0x6c, 0xfe, 0x0f, 0x8d, 0x66, 0xd6, 0xad, 0x1f, 0x3f, 0x2b, 0x96, 0xc8,
+    0x56, 0x9f, 0xf8, 0xbd, 0xd6, 0xf5, 0x7c, 0xc1, 0x0d, 0x68, 0xc3, 0xd3,
+    0xd0, 0x7c, 0xff, 0x30, 0xee, 0x76, 0xbf, 0x09, 0x69, 0xfd, 0x55, 0x67,
+    0xad, 0x9f, 0x5a, 0x16, 0x9d, 0xbd, 0x71, 0x69, 0xb7, 0x65, 0xa1, 0xe6,
+    0xcb, 0x83, 0x90, 0xb4, 0xf6, 0xdd, 0x2f, 0xad, 0x3c, 0x4c, 0x73, 0x62,
+    0x22, 0x76, 0x3c, 0x39, 0x0f, 0x02, 0xa7, 0xfd, 0x4f, 0x36, 0x7f, 0xb5,
+    0x5d, 0x54, 0x50, 0xf3, 0xf9, 0xbe, 0x06, 0xee, 0x1d, 0x69, 0xff, 0x8f,
+    0x5e, 0xb7, 0xba, 0x21, 0x23, 0xad, 0x3f, 0xf6, 0xef, 0xd5, 0x7f, 0x6e,
+    0x31, 0x58, 0xb4, 0xff, 0xb7, 0xf8, 0x3f, 0x43, 0xcc, 0x02, 0xd3, 0xfd,
+    0x82, 0x35, 0xc0, 0x9b, 0xab, 0x4f, 0xab, 0x6b, 0xf0, 0x96, 0x8d, 0x1e,
+    0xed, 0xcd, 0xa7, 0xe1, 0xf3, 0x33, 0xed, 0x75, 0xa7, 0xff, 0xec, 0xf7,
+    0x4c, 0x11, 0xb8, 0x34, 0x0b, 0xdd, 0x80, 0x94, 0xfe, 0xd5, 0x01, 0xc1,
+    0x6f, 0x56, 0x91, 0x9e, 0xba, 0x03, 0x90, 0xa8, 0xeb, 0xa9, 0x10, 0xb8,
+    0x6f, 0xf8, 0x5d, 0x9d, 0x4f, 0x49, 0x34, 0x62, 0x04, 0x3b, 0xa3, 0x72,
+    0x13, 0x7b, 0x91, 0x79, 0x18, 0x04, 0xb7, 0x3f, 0x8d, 0x9f, 0xed, 0x57,
+    0x55, 0x17, 0x9c, 0x33, 0x3a, 0x55, 0xea, 0x7e, 0xc3, 0xe3, 0x27, 0x31,
+    0xf6, 0x8d, 0xbb, 0xe6, 0xa7, 0x3e, 0xd1, 0xf0, 0xce, 0x9f, 0xbb, 0x87,
+    0x3c, 0xfe, 0x36, 0x7f, 0xb5, 0x5d, 0x54, 0x52, 0xd3, 0xef, 0xf6, 0xab,
+    0xaa, 0x8b, 0x0a, 0x7f, 0xfc, 0xd8, 0x3e, 0xb6, 0x9b, 0x6e, 0x60, 0xd1,
+    0xd6, 0x91, 0xb1, 0x10, 0xa7, 0x33, 0x9f, 0xc6, 0xcf, 0xf6, 0xab, 0xaa,
+    0x8b, 0x2e, 0x78, 0xc1, 0xf9, 0xad, 0xd3, 0x2d, 0x38, 0xc1, 0x1d, 0x69,
+    0x5f, 0xa7, 0x9d, 0xb9, 0x8c, 0xfa, 0xbf, 0x81, 0xd8, 0xb4, 0xfe, 0xb3,
+    0x6b, 0xb7, 0xbc, 0x25, 0xa7, 0xcd, 0x8e, 0xda, 0xeb, 0x4c, 0x2d, 0x47,
+    0xb9, 0x69, 0xac, 0xf5, 0x3d, 0xfe, 0xad, 0x3f, 0x57, 0xdb, 0x95, 0xa5,
+    0xa6, 0x6b, 0xad, 0x1e, 0x9f, 0x16, 0x88, 0x9d, 0x95, 0xcf, 0xc5, 0x57,
+    0x05, 0xf7, 0x5a, 0x7f, 0xbe, 0xcf, 0xe5, 0x6a, 0xbd, 0x5a, 0x4f, 0x5a,
+    0x4f, 0x5a, 0x4f, 0x5a, 0x18, 0xd8, 0x06, 0x20, 0x42, 0x13, 0xff, 0xee,
+    0x5c, 0xbb, 0x83, 0xf6, 0x1c, 0xf7, 0x03, 0x5a, 0x5b, 0x2d, 0x35, 0xf7,
+    0x5a, 0x30, 0xfe, 0xee, 0xa7, 0xc1, 0x19, 0x89, 0x96, 0x9f, 0x85, 0x8e,
+    0x2d, 0x8b, 0x4c, 0xf6, 0x5a, 0x3d, 0x3d, 0x27, 0x05, 0x37, 0x29, 0x9f,
+    0xff, 0xfe, 0xd3, 0x72, 0xe5, 0x7b, 0xb7, 0x34, 0x4d, 0xf0, 0x1e, 0x9e,
+    0xfe, 0x06, 0xb4, 0xcc, 0x75, 0xa7, 0xff, 0xe7, 0xb0, 0xee, 0xf7, 0xb7,
+    0x35, 0x87, 0x09, 0x80, 0xb4, 0xdd, 0x33, 0x2e, 0x24, 0xd8, 0x53, 0xec,
+    0x21, 0x32, 0x11, 0xdd, 0x32, 0xf9, 0x6d, 0x34, 0x0c, 0x2a, 0x2f, 0x08,
+    0x0e, 0x19, 0x79, 0x3e, 0x84, 0x2b, 0x3f, 0xf8, 0xc7, 0xa7, 0x9b, 0x3f,
+    0xda, 0xae, 0xaa, 0x28, 0xc9, 0xf3, 0xb6, 0xfb, 0x01, 0x69, 0xf0, 0xd0,
+    0x18, 0x25, 0xa4, 0x66, 0x3c, 0xed, 0x14, 0x43, 0xd7, 0xd5, 0x3f, 0x0c,
+    0x33, 0x94, 0x54, 0xe6, 0xad, 0xe1, 0x95, 0xc8, 0x51, 0xcf, 0xfc, 0x6a,
+    0x79, 0xb3, 0xfd, 0xaa, 0xea, 0xa2, 0x39, 0x9f, 0xfc, 0x63, 0xd3, 0xcd,
+    0x9f, 0xed, 0x57, 0x55, 0x13, 0x94, 0xfe, 0x36, 0x7f, 0xb5, 0x5d, 0x54,
+    0x59, 0x93, 0xfd, 0xe6, 0xaf, 0x70, 0xed, 0xb3, 0x1d, 0x69, 0xfe, 0x07,
+    0xdb, 0x9a, 0xad, 0x9e, 0xb4, 0xfe, 0xcb, 0xff, 0xf9, 0xb5, 0xd6, 0x91,
+    0x9d, 0x32, 0x2b, 0x59, 0x05, 0xe7, 0x33, 0xf8, 0xd9, 0xfe, 0xd5, 0x75,
+    0x51, 0x6e, 0xcf, 0xfe, 0x31, 0xe9, 0xe6, 0xcf, 0xf6, 0xab, 0xaa, 0x8a,
+    0x42, 0x7f, 0xe3, 0x53, 0xcd, 0x9f, 0xed, 0x57, 0x55, 0x12, 0x94, 0x58,
+    0xaa, 0xb1, 0xc4, 0xf3, 0xaa, 0x82, 0x1d, 0x62, 0x77, 0xc3, 0xe7, 0x55,
+    0x59, 0xff, 0x53, 0xcd, 0x9f, 0xed, 0x57, 0x55, 0x13, 0xb4, 0xff, 0xf8,
+    0xbd, 0xdc, 0xec, 0xeb, 0x5e, 0x8b, 0x0e, 0x75, 0x69, 0x18, 0xe8, 0xa0,
+    0xa4, 0x99, 0xff, 0xa8, 0xfa, 0xce, 0xd6, 0x98, 0x27, 0xad, 0x3f, 0xf0,
+    0xe6, 0xaa, 0xcc, 0xb8, 0xd6, 0xcb, 0x4d, 0xe4, 0x6f, 0x51, 0x0b, 0x74,
+    0x38, 0x3a, 0x38, 0x3c, 0xa1, 0x5b, 0x3e, 0xff, 0x6a, 0xba, 0xa8, 0x8b,
+    0x27, 0xfd, 0x4f, 0x36, 0x7f, 0xb5, 0x5d, 0x54, 0x4b, 0xb3, 0xff, 0xf6,
+    0x7b, 0xa6, 0x08, 0xdc, 0x1a, 0x05, 0xee, 0xc0, 0x4a, 0x46, 0xc4, 0x6b,
+    0x9c, 0xcf, 0xc9, 0x26, 0x7f, 0xf1, 0x8f, 0x4f, 0x36, 0x7f, 0xb5, 0x5d,
+    0x54, 0x4c, 0x53, 0xef, 0xf6, 0xab, 0xaa, 0x8a, 0xa6, 0x58, 0xb4, 0x61,
+    0xe1, 0x06, 0x67, 0x3f, 0xff, 0xfb, 0xf5, 0xad, 0x9f, 0x9c, 0x36, 0xaa,
+    0xff, 0x2b, 0x79, 0xa2, 0xfb, 0xd6, 0x83, 0x22, 0x6e, 0x88, 0xa7, 0xff,
+    0x18, 0xf4, 0xf3, 0x67, 0xfb, 0x55, 0xd5, 0x44, 0xe9, 0x3f, 0x8a, 0xbe,
+    0xcf, 0xa7, 0x6b, 0x4f, 0x9c, 0x67, 0x1a, 0xeb, 0x4f, 0xd6, 0xe1, 0x3b,
+    0xc1, 0x5a, 0x08, 0xf5, 0x6e, 0x51, 0x38, 0xb4, 0xcb, 0x18, 0xd0, 0xcf,
+    0xfd, 0xbd, 0xf8, 0xdb, 0x1b, 0x77, 0x08, 0xeb, 0x41, 0xcf, 0xcb, 0x45,
+    0x53, 0xfe, 0xa7, 0x9b, 0x3f, 0xda, 0xae, 0xaa, 0x27, 0x79, 0xf7, 0x37,
+    0xa3, 0x92, 0x52, 0x37, 0xa9, 0xd6, 0x64, 0x63, 0x47, 0x22, 0xa4, 0x99,
+    0xff, 0xc6, 0x3d, 0x3c, 0xd9, 0xfe, 0xd5, 0x75, 0x51, 0x42, 0xcf, 0xfe,
+    0x31, 0xe9, 0xe6, 0xcf, 0xf6, 0xab, 0xaa, 0x8a, 0x4a, 0x7f, 0xff, 0x65,
+    0xcc, 0x16, 0x39, 0xaa, 0x3f, 0x34, 0xdc, 0xdc, 0xeb, 0x45, 0x8b, 0x9c,
+    0x6f, 0x38, 0xec, 0x66, 0x5f, 0x22, 0x3c, 0xa0, 0x10, 0x24, 0xee, 0xab,
+    0xe4, 0xab, 0x3f, 0x8d, 0x9f, 0xed, 0x57, 0x55, 0x11, 0x24, 0xff, 0xe3,
+    0x1e, 0x9e, 0x6c, 0xff, 0x6a, 0xba, 0xa8, 0x97, 0xa7, 0xbf, 0xbf, 0x2e,
+    0xb4, 0xfb, 0xe0, 0x39, 0x5d, 0x69, 0xc0, 0x6e, 0x2d, 0x3f, 0xf5, 0x39,
+    0x76, 0x77, 0x5a, 0x6d, 0x9c, 0x5a, 0x3d, 0x45, 0x61, 0x11, 0xb8, 0x4f,
+    0xf1, 0xb9, 0xfe, 0x2a, 0x1d, 0xf8, 0xe3, 0x06, 0xb4, 0xfb, 0xfd, 0xaa,
+    0xea, 0xa2, 0x97, 0x9f, 0x0f, 0x2c, 0xcb, 0x56, 0x9f, 0xe0, 0x5f, 0xed,
+    0xb3, 0xc8, 0xeb, 0x4f, 0xf5, 0x59, 0xe2, 0xcd, 0xdc, 0x6f, 0x3a, 0xd3,
+    0x63, 0xd8, 0xfe, 0xf7, 0x39, 0x9f, 0xbe, 0x06, 0xee, 0x1d, 0x69, 0x9f,
+    0x8b, 0x4e, 0x60, 0x5d, 0x68, 0x63, 0xdc, 0xf4, 0xb2, 0xd1, 0x59, 0xff,
+    0x88, 0xf5, 0xe8, 0x4e, 0x3d, 0x87, 0x65, 0xa7, 0xae, 0x56, 0xf1, 0x68,
+    0xd1, 0xf4, 0x71, 0x1a, 0x7f, 0xab, 0x54, 0xe1, 0x7d, 0xac, 0x5a, 0x7c,
+    0xea, 0x47, 0x6b, 0xad, 0x3e, 0xa7, 0x79, 0xfb, 0xad, 0x26, 0xf4, 0xf4,
+    0x4e, 0x53, 0x3e, 0x20, 0xee, 0x0e, 0xad, 0x23, 0x32, 0xb6, 0x9f, 0x4f,
+    0xb0, 0xe7, 0x63, 0x37, 0x21, 0x47, 0xa8, 0x44, 0xd4, 0x26, 0x2e, 0x45,
+    0xc8, 0x44, 0xf9, 0x14, 0x4f, 0xe3, 0x67, 0xfb, 0x55, 0xd5, 0x45, 0x39,
+    0x3f, 0xe2, 0xfd, 0x5f, 0x59, 0x83, 0xd5, 0xa7, 0xfe, 0x0c, 0xb6, 0xb8,
+    0xe7, 0xba, 0xab, 0x56, 0x9f, 0xf6, 0x69, 0xbf, 0x86, 0xb6, 0xdb, 0x52,
+    0x98, 0xad, 0x5a, 0x6b, 0x0d, 0xea, 0x35, 0xf8, 0x77, 0xe4, 0x8c, 0xea,
+    0x81, 0x3e, 0xff, 0x6a, 0xba, 0xa8, 0xaf, 0x27, 0xff, 0xec, 0xf7, 0x4c,
+    0x11, 0xb8, 0x34, 0x0b, 0xdd, 0x80, 0x94, 0x8d, 0x88, 0x8e, 0xf2, 0x33,
+    0x9f, 0xf8, 0xd4, 0xf3, 0x67, 0xfb, 0x55, 0xd5, 0x44, 0x8f, 0x38, 0x80,
+    0xcb, 0x4e, 0xee, 0x1d, 0x23, 0x17, 0x53, 0xef, 0xf6, 0xab, 0xaa, 0x89,
+    0x22, 0x78, 0xd4, 0xf3, 0x31, 0xee, 0xe1, 0x54, 0xff, 0xc6, 0xa7, 0x9b,
+    0x3f, 0xda, 0xae, 0xaa, 0x24, 0xa9, 0xf7, 0xfb, 0x55, 0xd5, 0x45, 0xe3,
+    0x3e, 0xbd, 0xf9, 0x9d, 0x5a, 0x7f, 0x9e, 0x6c, 0xff, 0x6a, 0xba, 0xa8,
+    0x93, 0x64, 0x6c, 0x44, 0xf7, 0xcc, 0xe8, 0x9e, 0x19, 0x93, 0x1f, 0x61,
+    0xf3, 0xe7, 0x1a, 0xbd, 0x85, 0x51, 0x46, 0x2a, 0xe4, 0x37, 0xce, 0x57,
+    0xa8, 0x63, 0x70, 0xdf, 0x78, 0x76, 0xc3, 0x47, 0xe7, 0x77, 0x64, 0x76,
+    0xaf, 0x96, 0x25, 0xec, 0xa4, 0x1c, 0xbc, 0xb8, 0xe0, 0xe5, 0x34, 0xf6,
+    0xd6, 0x40, 0xed, 0x48, 0xda, 0x29, 0xeb, 0x6f, 0x3c, 0xa0, 0xf7, 0x2b,
+    0x57, 0x0f, 0xd3, 0x19, 0x4f, 0x8b, 0x3a, 0x1d, 0x4f, 0x5f, 0x55, 0x6a,
+    0xfe, 0x09, 0xc2, 0x87, 0x42, 0x17, 0xc3, 0x49, 0x2b, 0xbd, 0x2b, 0xb7,
+    0x96, 0x91, 0xbb, 0x7a, 0xcf, 0x05, 0xdd, 0x20, 0x12, 0xd9, 0x63, 0x9e,
+    0x51, 0xf7, 0x85, 0x3b, 0xca, 0xeb, 0x4a, 0x15, 0x80,
+};
+
+static const unsigned kPreloadedHSTSBits = 129955;
+
+static const unsigned kHSTSRootPosition = 129364;
diff --git a/src/common/src/tpkp_common.cpp b/src/common/src/tpkp_common.cpp
new file mode 100644 (file)
index 0000000..5c0d9ac
--- /dev/null
@@ -0,0 +1,259 @@
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ *    Licensed under the Apache License, Version 2.0 (the "License");
+ *    you may not use this file except in compliance with the License.
+ *    You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *    Unless required by applicable law or agreed to in writing, software
+ *    distributed under the License is distributed on an "AS IS" BASIS,
+ *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *    See the License for the specific language governing permissions and
+ *    limitations under the License.
+ */
+/*
+ * @file        tpkp_common.cpp
+ * @author      Kyungwook Tak (k.tak@samsung.com)
+ * @version     1.0
+ * @brief       Https Public Key Pinning common implementation.
+ */
+
+#include <sys/syscall.h>
+#include <unistd.h>
+
+#include <cstring>
+#include <cctype>
+#include <new>
+#include <algorithm>
+#include <iostream>
+
+#include "net/http/transport_security_state.h"
+#include "net/http/transport_security_state_static.h"
+#include "url/third_party/mozilla/url_parse.h"
+
+#include "tpkp_common.h"
+
+namespace {
+
+template <typename T>
+inline size_t _arraySize(const T &t)
+{
+       return sizeof(t) / sizeof(*t);
+}
+
+inline std::string _toLower(const std::string &host)
+{
+       std::string lowerHost;
+       std::for_each(
+               host.begin(),
+               host.end(),
+               [&lowerHost](const std::string::value_type &ch)
+               {
+                       lowerHost.push_back(std::tolower(ch));
+               });
+
+       return lowerHost;
+}
+
+} // anonymous namespace
+
+namespace TPKP {
+
+pid_t getThreadId()
+{
+       return syscall(SYS_gettid);
+}
+
+Exception::Exception(tpkp_e code, const std::string &message)
+       : m_code(code)
+       , m_message(message)
+{}
+
+const char *Exception::what(void) const noexcept
+{
+       return m_message.c_str();
+}
+
+tpkp_e Exception::code(void) const noexcept
+{
+       return m_code;
+}
+
+tpkp_e ExceptionSafe(const std::function<void()> &func)
+{
+       try {
+               func();
+               return TPKP_E_NONE;
+       } catch (const Exception &e) {
+               SLOGE("Exception: %s", e.what());
+               return e.code();
+       } catch (const std::bad_alloc &e) {
+               SLOGE("bad_alloc std exception: %s", e.what());
+               return TPKP_E_MEMORY;
+       } catch (const std::exception &e) {
+               SLOGE("std exception: %s", e.what());
+               return TPKP_E_STD_EXCEPTION;
+       } catch (...) {
+               SLOGE("Unhandled exception occured!");
+               return TPKP_E_INTERNAL;
+       }
+}
+
+class Context::Impl {
+public:
+       Impl() = delete;
+       virtual ~Impl();
+       explicit Impl(const std::string &url);
+
+       void addPubkeyHash(HashAlgo algo, const RawBuffer &hashBuf);
+       bool checkPubkeyPins(void);
+       bool hasPins(void);
+
+private:
+       std::string m_url;
+       std::string m_host;
+       net::PreloadResult m_preloaded;
+       HashValueVector m_hashes;
+
+       bool LoadPreloadedPins(void);
+       bool HashesIntersect(const char *const *hashesArr);
+
+       class HashValuesEqual {
+       public:
+               explicit HashValuesEqual(const char *chash);
+               bool operator()(const HashValue &other) const;
+       private:
+               const char *m_chash;
+       };
+};
+
+Context::Impl::Impl(const std::string &url) : m_url(url)
+{
+       url::Parsed parsed;
+       url::ParseStandardURL(m_url.c_str(), m_url.length(), &parsed);
+       TPKP_CHECK_THROW_EXCEPTION(parsed.host.is_valid(),
+               TPKP_E_INVALID_URL, "Failed to parse url: " << url);
+
+       m_host = _toLower(m_url.substr(
+                       static_cast<size_t>(parsed.host.begin),
+                       static_cast<size_t>(parsed.host.len)));
+
+       SLOGD("HPKP ready to check on host[%s]", m_host.c_str());
+
+       LoadPreloadedPins();
+       if (!m_preloaded.has_pins) {
+               SLOGD("no pins on static pubkey list.");
+               return;
+       }
+}
+
+Context::Impl::~Impl() {}
+
+void Context::Impl::addPubkeyHash(HashAlgo algo, const RawBuffer &hashBuf)
+{
+       m_hashes.emplace_back(algo, hashBuf);
+}
+
+bool Context::Impl::checkPubkeyPins(void)
+{
+       if (!hasPins()) {
+               SLOGD("no pins on static pubkey list.");
+               return true;
+       }
+
+       const Pinset &pinset = kPinsets[m_preloaded.pinset_id];
+
+       if (HashesIntersect(pinset.rejected_pins)) {
+               SLOGE("pubkey is in rejected pin!");
+               return false;
+       }
+
+       if (!HashesIntersect(pinset.accepted_pins)) {
+               SLOGE("pubkey cannot be found in accepted pins!");
+               return false;
+       }
+
+       SLOGD("pubkey is pinned one!");
+
+       return true;
+}
+
+bool Context::Impl::hasPins(void)
+{
+       return m_preloaded.has_pins;
+}
+
+bool Context::Impl::LoadPreloadedPins(void)
+{
+       m_preloaded.has_pins = false;
+       if (!net::DecodeHSTSPreload(m_host, &m_preloaded))
+               return false;
+
+       size_t arrsize = _arraySize(kPinsets);
+       if (m_preloaded.pinset_id >= static_cast<uint32>(arrsize))
+               return false;
+
+       return true;
+}
+
+bool Context::Impl::HashesIntersect(const char *const *hashesArr)
+{
+       if (!hashesArr)
+               return false;
+
+       for (; *hashesArr != nullptr; hashesArr++) {
+               if (std::find_if(
+                               m_hashes.begin(),
+                               m_hashes.end(),
+                               HashValuesEqual{*hashesArr}) != m_hashes.end()) {
+                       SLOGD("hash intersect found!");
+                       return true;
+               }
+       }
+
+       return false;
+}
+
+Context::Impl::HashValuesEqual::HashValuesEqual(const char *chash) : m_chash(chash) {}
+
+bool Context::Impl::HashValuesEqual::operator()(const HashValue &other) const
+{
+       size_t len = other.hash.size();
+
+       /*
+        * hash from decode preloaded value is base64 encoded,
+        * so it can be get length by strlen.
+        */
+       if (strlen(m_chash) != len)
+               return false;
+
+       for (size_t i = 0; i < len; i++) {
+               if (m_chash[i] != other.hash[i])
+                       return false;
+       }
+
+       return true;
+}
+
+Context::Context(const std::string &url) : pImpl(new Impl{url}) {}
+Context::~Context() {}
+
+void Context::addPubkeyHash(HashAlgo algo, const RawBuffer &hashBuf)
+{
+       SLOGD("add public key hash of algo[%d]", algo);
+       pImpl->addPubkeyHash(algo, hashBuf);
+}
+
+bool Context::checkPubkeyPins(void)
+{
+       return pImpl->checkPubkeyPins();
+}
+
+bool Context::hasPins(void)
+{
+       return pImpl->hasPins();
+}
+
+}
diff --git a/src/common/url/third_party/mozilla/url_parse.h b/src/common/url/third_party/mozilla/url_parse.h
new file mode 100644 (file)
index 0000000..22747db
--- /dev/null
@@ -0,0 +1,393 @@
+/*
+ * Copyright 2014 The Chromium Authors. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+
+ *    * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *    * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *    * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#pragma once
+
+#include <string>
+
+#include "base/strings/string16.h"
+#include "url/url_export.h"
+
+namespace url {
+
+// Deprecated, but WebKit/WebCore/platform/KURLGooglePrivate.h and
+// KURLGoogle.cpp still rely on this type.
+typedef base::char16 UTF16Char;
+
+// Component ------------------------------------------------------------------
+
+// Represents a substring for URL parsing.
+struct Component {
+  Component() : begin(0), len(-1) {}
+
+  // Normal constructor: takes an offset and a length.
+  Component(int b, int l) : begin(b), len(l) {}
+
+  int end() const {
+    return begin + len;
+  }
+
+  // Returns true if this component is valid, meaning the length is given. Even
+  // valid components may be empty to record the fact that they exist.
+  bool is_valid() const {
+    return (len != -1);
+  }
+
+  // Returns true if the given component is specified on false, the component
+  // is either empty or invalid.
+  bool is_nonempty() const {
+    return (len > 0);
+  }
+
+  void reset() {
+    begin = 0;
+    len = -1;
+  }
+
+  bool operator==(const Component& other) const {
+    return begin == other.begin && len == other.len;
+  }
+
+  int begin;  // Byte offset in the string of this component.
+  int len;    // Will be -1 if the component is unspecified.
+};
+
+// Helper that returns a component created with the given begin and ending
+// points. The ending point is non-inclusive.
+inline Component MakeRange(int begin, int end) {
+  return Component(begin, end - begin);
+}
+
+// Parsed ---------------------------------------------------------------------
+
+// A structure that holds the identified parts of an input URL. This structure
+// does NOT store the URL itself. The caller will have to store the URL text
+// and its corresponding Parsed structure separately.
+//
+// Typical usage would be:
+//
+//    Parsed parsed;
+//    Component scheme;
+//    if (!ExtractScheme(url, url_len, &scheme))
+//      return I_CAN_NOT_FIND_THE_SCHEME_DUDE;
+//
+//    if (IsStandardScheme(url, scheme))  // Not provided by this component
+//      ParseStandardURL(url, url_len, &parsed);
+//    else if (IsFileURL(url, scheme))    // Not provided by this component
+//      ParseFileURL(url, url_len, &parsed);
+//    else
+//      ParsePathURL(url, url_len, &parsed);
+//
+struct URL_EXPORT Parsed {
+  // Identifies different components.
+  enum ComponentType {
+    SCHEME,
+    USERNAME,
+    PASSWORD,
+    HOST,
+    PORT,
+    PATH,
+    QUERY,
+    REF,
+  };
+
+  // The default constructor is sufficient for the components, but inner_parsed_
+  // requires special handling.
+  Parsed();
+  Parsed(const Parsed&);
+  Parsed& operator=(const Parsed&);
+  ~Parsed();
+
+  // Returns the length of the URL (the end of the last component).
+  //
+  // Note that for some invalid, non-canonical URLs, this may not be the length
+  // of the string. For example "http://": the parsed structure will only
+  // contain an entry for the four-character scheme, and it doesn't know about
+  // the "://". For all other last-components, it will return the real length.
+  int Length() const;
+
+  // Returns the number of characters before the given component if it exists,
+  // or where the component would be if it did exist. This will return the
+  // string length if the component would be appended to the end.
+  //
+  // Note that this can get a little funny for the port, query, and ref
+  // components which have a delimiter that is not counted as part of the
+  // component. The |include_delimiter| flag controls if you want this counted
+  // as part of the component or not when the component exists.
+  //
+  // This example shows the difference between the two flags for two of these
+  // delimited components that is present (the port and query) and one that
+  // isn't (the reference). The components that this flag affects are marked
+  // with a *.
+  //                 0         1         2
+  //                 012345678901234567890
+  // Example input:  http://foo:80/?query
+  //              include_delim=true,  ...=false  ("<-" indicates different)
+  //      SCHEME: 0                    0
+  //    USERNAME: 5                    5
+  //    PASSWORD: 5                    5
+  //        HOST: 7                    7
+  //       *PORT: 10                   11 <-
+  //        PATH: 13                   13
+  //      *QUERY: 14                   15 <-
+  //        *REF: 20                   20
+  //
+  int CountCharactersBefore(ComponentType type, bool include_delimiter) const;
+
+  // Scheme without the colon: "http://foo"/ would have a scheme of "http".
+  // The length will be -1 if no scheme is specified ("foo.com"), or 0 if there
+  // is a colon but no scheme (":foo"). Note that the scheme is not guaranteed
+  // to start at the beginning of the string if there are preceeding whitespace
+  // or control characters.
+  Component scheme;
+
+  // Username. Specified in URLs with an @ sign before the host. See |password|
+  Component username;
+
+  // Password. The length will be -1 if unspecified, 0 if specified but empty.
+  // Not all URLs with a username have a password, as in "http://me@host/".
+  // The password is separated form the username with a colon, as in
+  // "http://me:secret@host/"
+  Component password;
+
+  // Host name.
+  Component host;
+
+  // Port number.
+  Component port;
+
+  // Path, this is everything following the host name, stopping at the query of
+  // ref delimiter (if any). Length will be -1 if unspecified. This includes
+  // the preceeding slash, so the path on http://www.google.com/asdf" is
+  // "/asdf". As a result, it is impossible to have a 0 length path, it will
+  // be -1 in cases like "http://host?foo".
+  // Note that we treat backslashes the same as slashes.
+  Component path;
+
+  // Stuff between the ? and the # after the path. This does not include the
+  // preceeding ? character. Length will be -1 if unspecified, 0 if there is
+  // a question mark but no query string.
+  Component query;
+
+  // Indicated by a #, this is everything following the hash sign (not
+  // including it). If there are multiple hash signs, we'll use the last one.
+  // Length will be -1 if there is no hash sign, or 0 if there is one but
+  // nothing follows it.
+  Component ref;
+
+  // The URL spec from the character after the scheme: until the end of the
+  // URL, regardless of the scheme. This is mostly useful for 'opaque' non-
+  // hierarchical schemes like data: and javascript: as a convient way to get
+  // the string with the scheme stripped off.
+  Component GetContent() const;
+
+  // This is used for nested URL types, currently only filesystem.  If you
+  // parse a filesystem URL, the resulting Parsed will have a nested
+  // inner_parsed_ to hold the parsed inner URL's component information.
+  // For all other url types [including the inner URL], it will be NULL.
+  Parsed* inner_parsed() const {
+    return inner_parsed_;
+  }
+
+  void set_inner_parsed(const Parsed& inner_parsed) {
+    if (!inner_parsed_)
+      inner_parsed_ = new Parsed(inner_parsed);
+    else
+      *inner_parsed_ = inner_parsed;
+  }
+
+  void clear_inner_parsed() {
+    if (inner_parsed_) {
+      delete inner_parsed_;
+      inner_parsed_ = NULL;
+    }
+  }
+
+ private:
+  Parsed* inner_parsed_;  // This object is owned and managed by this struct.
+};
+
+// Initialization functions ---------------------------------------------------
+//
+// These functions parse the given URL, filling in all of the structure's
+// components. These functions can not fail, they will always do their best
+// at interpreting the input given.
+//
+// The string length of the URL MUST be specified, we do not check for NULLs
+// at any point in the process, and will actually handle embedded NULLs.
+//
+// IMPORTANT: These functions do NOT hang on to the given pointer or copy it
+// in any way. See the comment above the struct.
+//
+// The 8-bit versions require UTF-8 encoding.
+
+// StandardURL is for when the scheme is known to be one that has an
+// authority (host) like "http". This function will not handle weird ones
+// like "about:" and "javascript:", or do the right thing for "file:" URLs.
+URL_EXPORT void ParseStandardURL(const char* url,
+                                 int url_len,
+                                 Parsed* parsed);
+URL_EXPORT void ParseStandardURL(const base::char16* url,
+                                 int url_len,
+                                 Parsed* parsed);
+
+// PathURL is for when the scheme is known not to have an authority (host)
+// section but that aren't file URLs either. The scheme is parsed, and
+// everything after the scheme is considered as the path. This is used for
+// things like "about:" and "javascript:"
+URL_EXPORT void ParsePathURL(const char* url,
+                             int url_len,
+                             bool trim_path_end,
+                             Parsed* parsed);
+URL_EXPORT void ParsePathURL(const base::char16* url,
+                             int url_len,
+                             bool trim_path_end,
+                             Parsed* parsed);
+
+// FileURL is for file URLs. There are some special rules for interpreting
+// these.
+URL_EXPORT void ParseFileURL(const char* url, int url_len, Parsed* parsed);
+URL_EXPORT void ParseFileURL(const base::char16* url,
+                             int url_len,
+                             Parsed* parsed);
+
+// Filesystem URLs are structured differently than other URLs.
+URL_EXPORT void ParseFileSystemURL(const char* url,
+                                   int url_len,
+                                   Parsed* parsed);
+URL_EXPORT void ParseFileSystemURL(const base::char16* url,
+                                   int url_len,
+                                   Parsed* parsed);
+
+// MailtoURL is for mailto: urls. They are made up scheme,path,query
+URL_EXPORT void ParseMailtoURL(const char* url, int url_len, Parsed* parsed);
+URL_EXPORT void ParseMailtoURL(const base::char16* url,
+                               int url_len,
+                               Parsed* parsed);
+
+// Helper functions -----------------------------------------------------------
+
+// Locates the scheme according to the URL  parser's rules. This function is
+// designed so the caller can find the scheme and call the correct Init*
+// function according to their known scheme types.
+//
+// It also does not perform any validation on the scheme.
+//
+// This function will return true if the scheme is found and will put the
+// scheme's range into *scheme. False means no scheme could be found. Note
+// that a URL beginning with a colon has a scheme, but it is empty, so this
+// function will return true but *scheme will = (0,0).
+//
+// The scheme is found by skipping spaces and control characters at the
+// beginning, and taking everything from there to the first colon to be the
+// scheme. The character at scheme.end() will be the colon (we may enhance
+// this to handle full width colons or something, so don't count on the
+// actual character value). The character at scheme.end()+1 will be the
+// beginning of the rest of the URL, be it the authority or the path (or the
+// end of the string).
+//
+// The 8-bit version requires UTF-8 encoding.
+URL_EXPORT bool ExtractScheme(const char* url,
+                              int url_len,
+                              Component* scheme);
+URL_EXPORT bool ExtractScheme(const base::char16* url,
+                              int url_len,
+                              Component* scheme);
+
+// Returns true if ch is a character that terminates the authority segment
+// of a URL.
+URL_EXPORT bool IsAuthorityTerminator(base::char16 ch);
+
+// Does a best effort parse of input |spec|, in range |auth|. If a particular
+// component is not found, it will be set to invalid.
+URL_EXPORT void ParseAuthority(const char* spec,
+                               const Component& auth,
+                               Component* username,
+                               Component* password,
+                               Component* hostname,
+                               Component* port_num);
+URL_EXPORT void ParseAuthority(const base::char16* spec,
+                               const Component& auth,
+                               Component* username,
+                               Component* password,
+                               Component* hostname,
+                               Component* port_num);
+
+// Computes the integer port value from the given port component. The port
+// component should have been identified by one of the init functions on
+// |Parsed| for the given input url.
+//
+// The return value will be a positive integer between 0 and 64K, or one of
+// the two special values below.
+enum SpecialPort { PORT_UNSPECIFIED = -1, PORT_INVALID = -2 };
+URL_EXPORT int ParsePort(const char* url, const Component& port);
+URL_EXPORT int ParsePort(const base::char16* url, const Component& port);
+
+// Extracts the range of the file name in the given url. The path must
+// already have been computed by the parse function, and the matching URL
+// and extracted path are provided to this function. The filename is
+// defined as being everything from the last slash/backslash of the path
+// to the end of the path.
+//
+// The file name will be empty if the path is empty or there is nothing
+// following the last slash.
+//
+// The 8-bit version requires UTF-8 encoding.
+URL_EXPORT void ExtractFileName(const char* url,
+                                const Component& path,
+                                Component* file_name);
+URL_EXPORT void ExtractFileName(const base::char16* url,
+                                const Component& path,
+                                Component* file_name);
+
+// Extract the first key/value from the range defined by |*query|. Updates
+// |*query| to start at the end of the extracted key/value pair. This is
+// designed for use in a loop: you can keep calling it with the same query
+// object and it will iterate over all items in the query.
+//
+// Some key/value pairs may have the key, the value, or both be empty (for
+// example, the query string "?&"). These will be returned. Note that an empty
+// last parameter "foo.com?" or foo.com?a&" will not be returned, this case
+// is the same as "done."
+//
+// The initial query component should not include the '?' (this is the default
+// for parsed URLs).
+//
+// If no key/value are found |*key| and |*value| will be unchanged and it will
+// return false.
+URL_EXPORT bool ExtractQueryKeyValue(const char* url,
+                                     Component* query,
+                                     Component* key,
+                                     Component* value);
+URL_EXPORT bool ExtractQueryKeyValue(const base::char16* url,
+                                     Component* query,
+                                     Component* key,
+                                     Component* value);
+
+}  // namespace url
diff --git a/src/common/url/url_constants.cc b/src/common/url/url_constants.cc
new file mode 100644 (file)
index 0000000..fbbb72f
--- /dev/null
@@ -0,0 +1,53 @@
+/*
+ * Copyright 2014 The Chromium Authors. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+
+ *    * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *    * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *    * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include "url/url_constants.h"
+
+namespace url {
+
+const char kAboutBlankURL[] = "about:blank";
+
+const char kAboutScheme[] = "about";
+const char kBlobScheme[] = "blob";
+const char kContentScheme[] = "content";
+const char kDataScheme[] = "data";
+const char kFileScheme[] = "file";
+const char kFileSystemScheme[] = "filesystem";
+const char kFtpScheme[] = "ftp";
+const char kGopherScheme[] = "gopher";
+const char kHttpScheme[] = "http";
+const char kHttpsScheme[] = "https";
+const char kJavaScriptScheme[] = "javascript";
+const char kMailToScheme[] = "mailto";
+const char kWsScheme[] = "ws";
+const char kWssScheme[] = "wss";
+
+const char kStandardSchemeSeparator[] = "://";
+
+}  // namespace url
diff --git a/src/common/url/url_constants.h b/src/common/url/url_constants.h
new file mode 100644 (file)
index 0000000..242601e
--- /dev/null
@@ -0,0 +1,57 @@
+/*
+ * Copyright 2014 The Chromium Authors. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+
+ *    * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *    * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *    * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#pragma once
+
+#include "url/url_export.h"
+
+namespace url {
+
+URL_EXPORT extern const char kAboutBlankURL[];
+
+URL_EXPORT extern const char kAboutScheme[];
+URL_EXPORT extern const char kBlobScheme[];
+// The content scheme is specific to Android for identifying a stored file.
+URL_EXPORT extern const char kContentScheme[];
+URL_EXPORT extern const char kDataScheme[];
+URL_EXPORT extern const char kFileScheme[];
+URL_EXPORT extern const char kFileSystemScheme[];
+URL_EXPORT extern const char kFtpScheme[];
+URL_EXPORT extern const char kGopherScheme[];
+URL_EXPORT extern const char kHttpScheme[];
+URL_EXPORT extern const char kHttpsScheme[];
+URL_EXPORT extern const char kJavaScriptScheme[];
+URL_EXPORT extern const char kMailToScheme[];
+URL_EXPORT extern const char kWsScheme[];
+URL_EXPORT extern const char kWssScheme[];
+
+// Used to separate a standard scheme and the hostname: "://".
+URL_EXPORT extern const char kStandardSchemeSeparator[];
+
+}  // namespace url
diff --git a/src/common/url/url_export.h b/src/common/url/url_export.h
new file mode 100644 (file)
index 0000000..36b1955
--- /dev/null
@@ -0,0 +1,55 @@
+/*
+ * Copyright 2014 The Chromium Authors. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+
+ *    * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *    * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *    * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#pragma once
+
+#if defined(COMPONENT_BUILD)
+#if defined(WIN32)
+
+#if defined(URL_IMPLEMENTATION)
+#define URL_EXPORT __declspec(dllexport)
+#else
+#define URL_EXPORT __declspec(dllimport)
+#endif  // defined(URL_IMPLEMENTATION)
+
+#else  // !defined(WIN32)
+
+#if defined(URL_IMPLEMENTATION)
+#define URL_EXPORT __attribute__((visibility("default")))
+#else
+#define URL_EXPORT
+#endif  // defined(URL_IMPLEMENTATION)
+
+#endif  // defined(WIN32)
+
+#else  // !defined(COMPONENT_BUILD)
+
+#define URL_EXPORT
+
+#endif  // define(COMPONENT_BUILD)
diff --git a/src/common/url/url_file.h b/src/common/url/url_file.h
new file mode 100644 (file)
index 0000000..cc42d6e
--- /dev/null
@@ -0,0 +1,105 @@
+/*
+ * Copyright 2014 The Chromium Authors. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+
+ *    * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *    * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *    * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+// Provides shared functions used by the internals of the parser and
+// canonicalizer for file URLs. Do not use outside of these modules.
+#pragma once
+
+#include "url/url_parse_internal.h"
+
+namespace url {
+
+#ifdef WIN32
+
+// We allow both "c:" and "c|" as drive identifiers.
+inline bool IsWindowsDriveSeparator(base::char16 ch) {
+  return ch == ':' || ch == '|';
+}
+inline bool IsWindowsDriveLetter(base::char16 ch) {
+  return (ch >= 'A' && ch <= 'Z') || (ch >= 'a' && ch <= 'z');
+}
+
+#endif  // WIN32
+
+// Returns the index of the next slash in the input after the given index, or
+// spec_len if the end of the input is reached.
+template<typename CHAR>
+inline int FindNextSlash(const CHAR* spec, int begin_index, int spec_len) {
+  int idx = begin_index;
+  while (idx < spec_len && !IsURLSlash(spec[idx]))
+    idx++;
+  return idx;
+}
+
+#ifdef WIN32
+
+// Returns true if the start_offset in the given spec looks like it begins a
+// drive spec, for example "c:". This function explicitly handles start_offset
+// values that are equal to or larger than the spec_len to simplify callers.
+//
+// If this returns true, the spec is guaranteed to have a valid drive letter
+// plus a colon starting at |start_offset|.
+template<typename CHAR>
+inline bool DoesBeginWindowsDriveSpec(const CHAR* spec, int start_offset,
+                                      int spec_len) {
+  int remaining_len = spec_len - start_offset;
+  if (remaining_len < 2)
+    return false;  // Not enough room.
+  if (!IsWindowsDriveLetter(spec[start_offset]))
+    return false;  // Doesn't start with a valid drive letter.
+  if (!IsWindowsDriveSeparator(spec[start_offset + 1]))
+    return false;  // Isn't followed with a drive separator.
+  return true;
+}
+
+// Returns true if the start_offset in the given text looks like it begins a
+// UNC path, for example "\\". This function explicitly handles start_offset
+// values that are equal to or larger than the spec_len to simplify callers.
+//
+// When strict_slashes is set, this function will only accept backslashes as is
+// standard for Windows. Otherwise, it will accept forward slashes as well
+// which we use for a lot of URL handling.
+template<typename CHAR>
+inline bool DoesBeginUNCPath(const CHAR* text,
+                             int start_offset,
+                             int len,
+                             bool strict_slashes) {
+  int remaining_len = len - start_offset;
+  if (remaining_len < 2)
+    return false;
+
+  if (strict_slashes)
+    return text[start_offset] == '\\' && text[start_offset + 1] == '\\';
+  return IsURLSlash(text[start_offset]) && IsURLSlash(text[start_offset + 1]);
+}
+
+#endif  // WIN32
+
+}  // namespace url
diff --git a/src/common/url/url_parse.cc b/src/common/url/url_parse.cc
new file mode 100644 (file)
index 0000000..d1861a5
--- /dev/null
@@ -0,0 +1,932 @@
+/* Based on nsURLParsers.cc from Mozilla
+ * -------------------------------------
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is mozilla.org code.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Darin Fisher (original author)
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include <stdlib.h>
+
+#include "base/logging.h"
+#include "url/url_parse_internal.h"
+#include "url/url_util.h"
+#include "url/url_util_internal.h"
+#include "url/third_party/mozilla/url_parse.h"
+
+
+namespace url {
+
+namespace {
+
+// Returns true if the given character is a valid digit to use in a port.
+inline bool IsPortDigit(base::char16 ch) {
+  return ch >= '0' && ch <= '9';
+}
+
+// Returns the offset of the next authority terminator in the input starting
+// from start_offset. If no terminator is found, the return value will be equal
+// to spec_len.
+template<typename CHAR>
+int FindNextAuthorityTerminator(const CHAR* spec,
+                                int start_offset,
+                                int spec_len) {
+  for (int i = start_offset; i < spec_len; i++) {
+    if (IsAuthorityTerminator(spec[i]))
+      return i;
+  }
+  return spec_len;  // Not found.
+}
+
+template<typename CHAR>
+void ParseUserInfo(const CHAR* spec,
+                   const Component& user,
+                   Component* username,
+                   Component* password) {
+  // Find the first colon in the user section, which separates the username and
+  // password.
+  int colon_offset = 0;
+  while (colon_offset < user.len && spec[user.begin + colon_offset] != ':')
+    colon_offset++;
+
+  if (colon_offset < user.len) {
+    // Found separator: <username>:<password>
+    *username = Component(user.begin, colon_offset);
+    *password = MakeRange(user.begin + colon_offset + 1,
+                          user.begin + user.len);
+  } else {
+    // No separator, treat everything as the username
+    *username = user;
+    *password = Component();
+  }
+}
+
+template<typename CHAR>
+void ParseServerInfo(const CHAR* spec,
+                     const Component& serverinfo,
+                     Component* hostname,
+                     Component* port_num) {
+  if (serverinfo.len == 0) {
+    // No server info, host name is empty.
+    hostname->reset();
+    port_num->reset();
+    return;
+  }
+
+  // If the host starts with a left-bracket, assume the entire host is an
+  // IPv6 literal.  Otherwise, assume none of the host is an IPv6 literal.
+  // This assumption will be overridden if we find a right-bracket.
+  //
+  // Our IPv6 address canonicalization code requires both brackets to exist,
+  // but the ability to locate an incomplete address can still be useful.
+  int ipv6_terminator = spec[serverinfo.begin] == '[' ? serverinfo.end() : -1;
+  int colon = -1;
+
+  // Find the last right-bracket, and the last colon.
+  for (int i = serverinfo.begin; i < serverinfo.end(); i++) {
+    switch (spec[i]) {
+      case ']':
+        ipv6_terminator = i;
+        break;
+      case ':':
+        colon = i;
+        break;
+    }
+  }
+
+  if (colon > ipv6_terminator) {
+    // Found a port number: <hostname>:<port>
+    *hostname = MakeRange(serverinfo.begin, colon);
+    if (hostname->len == 0)
+      hostname->reset();
+    *port_num = MakeRange(colon + 1, serverinfo.end());
+  } else {
+    // No port: <hostname>
+    *hostname = serverinfo;
+    port_num->reset();
+  }
+}
+
+// Given an already-identified auth section, breaks it into its consituent
+// parts. The port number will be parsed and the resulting integer will be
+// filled into the given *port variable, or -1 if there is no port number or it
+// is invalid.
+template<typename CHAR>
+void DoParseAuthority(const CHAR* spec,
+                      const Component& auth,
+                      Component* username,
+                      Component* password,
+                      Component* hostname,
+                      Component* port_num) {
+  DCHECK(auth.is_valid(), "We should always get an authority");
+  if (auth.len == 0) {
+    username->reset();
+    password->reset();
+    hostname->reset();
+    port_num->reset();
+    return;
+  }
+
+  // Search backwards for @, which is the separator between the user info and
+  // the server info.
+  int i = auth.begin + auth.len - 1;
+  while (i > auth.begin && spec[i] != '@')
+    i--;
+
+  if (spec[i] == '@') {
+    // Found user info: <user-info>@<server-info>
+    ParseUserInfo(spec, Component(auth.begin, i - auth.begin),
+                  username, password);
+    ParseServerInfo(spec, MakeRange(i + 1, auth.begin + auth.len),
+                    hostname, port_num);
+  } else {
+    // No user info, everything is server info.
+    username->reset();
+    password->reset();
+    ParseServerInfo(spec, auth, hostname, port_num);
+  }
+}
+
+template<typename CHAR>
+void ParsePath(const CHAR* spec,
+               const Component& path,
+               Component* filepath,
+               Component* query,
+               Component* ref) {
+  // path = [/]<segment1>/<segment2>/<...>/<segmentN>;<param>?<query>#<ref>
+
+  // Special case when there is no path.
+  if (path.len == -1) {
+    filepath->reset();
+    query->reset();
+    ref->reset();
+    return;
+  }
+  DCHECK(path.len > 0, "We should never have 0 length paths");
+
+  // Search for first occurrence of either ? or #.
+  int path_end = path.begin + path.len;
+
+  int query_separator = -1;  // Index of the '?'
+  int ref_separator = -1;    // Index of the '#'
+  for (int i = path.begin; i < path_end; i++) {
+    switch (spec[i]) {
+      case '?':
+        // Only match the query string if it precedes the reference fragment
+        // and when we haven't found one already.
+        if (ref_separator < 0 && query_separator < 0)
+          query_separator = i;
+        break;
+      case '#':
+        // Record the first # sign only.
+        if (ref_separator < 0)
+          ref_separator = i;
+        break;
+    }
+  }
+
+  // Markers pointing to the character after each of these corresponding
+  // components. The code below words from the end back to the beginning,
+  // and will update these indices as it finds components that exist.
+  int file_end, query_end;
+
+  // Ref fragment: from the # to the end of the path.
+  if (ref_separator >= 0) {
+    file_end = query_end = ref_separator;
+    *ref = MakeRange(ref_separator + 1, path_end);
+  } else {
+    file_end = query_end = path_end;
+    ref->reset();
+  }
+
+  // Query fragment: everything from the ? to the next boundary (either the end
+  // of the path or the ref fragment).
+  if (query_separator >= 0) {
+    file_end = query_separator;
+    *query = MakeRange(query_separator + 1, query_end);
+  } else {
+    query->reset();
+  }
+
+  // File path: treat an empty file path as no file path.
+  if (file_end != path.begin)
+    *filepath = MakeRange(path.begin, file_end);
+  else
+    filepath->reset();
+}
+
+template<typename CHAR>
+bool DoExtractScheme(const CHAR* url,
+                     int url_len,
+                     Component* scheme) {
+  // Skip leading whitespace and control characters.
+  int begin = 0;
+  while (begin < url_len && ShouldTrimFromURL(url[begin]))
+    begin++;
+  if (begin == url_len)
+    return false;  // Input is empty or all whitespace.
+
+  // Find the first colon character.
+  for (int i = begin; i < url_len; i++) {
+    if (url[i] == ':') {
+      *scheme = MakeRange(begin, i);
+      return true;
+    }
+  }
+  return false;  // No colon found: no scheme
+}
+
+// Fills in all members of the Parsed structure except for the scheme.
+//
+// |spec| is the full spec being parsed, of length |spec_len|.
+// |after_scheme| is the character immediately following the scheme (after the
+//   colon) where we'll begin parsing.
+//
+// Compatability data points. I list "host", "path" extracted:
+// Input                IE6             Firefox                Us
+// -----                --------------  --------------         --------------
+// http://foo.com/      "foo.com", "/"  "foo.com", "/"         "foo.com", "/"
+// http:foo.com/        "foo.com", "/"  "foo.com", "/"         "foo.com", "/"
+// http:/foo.com/       fail(*)         "foo.com", "/"         "foo.com", "/"
+// http:\foo.com/       fail(*)         "\foo.com", "/"(fail)  "foo.com", "/"
+// http:////foo.com/    "foo.com", "/"  "foo.com", "/"         "foo.com", "/"
+//
+// (*) Interestingly, although IE fails to load these URLs, its history
+// canonicalizer handles them, meaning if you've been to the corresponding
+// "http://foo.com/" link, it will be colored.
+template <typename CHAR>
+void DoParseAfterScheme(const CHAR* spec,
+                        int spec_len,
+                        int after_scheme,
+                        Parsed* parsed) {
+  int num_slashes = CountConsecutiveSlashes(spec, after_scheme, spec_len);
+  int after_slashes = after_scheme + num_slashes;
+
+  // First split into two main parts, the authority (username, password, host,
+  // and port) and the full path (path, query, and reference).
+  Component authority;
+  Component full_path;
+
+  // Found "//<some data>", looks like an authority section. Treat everything
+  // from there to the next slash (or end of spec) to be the authority. Note
+  // that we ignore the number of slashes and treat it as the authority.
+  int end_auth = FindNextAuthorityTerminator(spec, after_slashes, spec_len);
+  authority = Component(after_slashes, end_auth - after_slashes);
+
+  if (end_auth == spec_len)  // No beginning of path found.
+    full_path = Component();
+  else  // Everything starting from the slash to the end is the path.
+    full_path = Component(end_auth, spec_len - end_auth);
+
+  // Now parse those two sub-parts.
+  DoParseAuthority(spec, authority, &parsed->username, &parsed->password,
+                   &parsed->host, &parsed->port);
+  ParsePath(spec, full_path, &parsed->path, &parsed->query, &parsed->ref);
+}
+
+// The main parsing function for standard URLs. Standard URLs have a scheme,
+// host, path, etc.
+template<typename CHAR>
+void DoParseStandardURL(const CHAR* spec, int spec_len, Parsed* parsed) {
+  DCHECK(spec_len >= 0, "");
+
+  // Strip leading & trailing spaces and control characters.
+  int begin = 0;
+
+  int after_scheme;
+  if (DoExtractScheme(spec, spec_len, &parsed->scheme)) {
+    after_scheme = parsed->scheme.end() + 1;  // Skip past the colon.
+  } else {
+    // Say there's no scheme when there is no colon. We could also say that
+    // everything is the scheme. Both would produce an invalid URL, but this way
+    // seems less wrong in more cases.
+    parsed->scheme.reset();
+    after_scheme = begin;
+  }
+  DoParseAfterScheme(spec, spec_len, after_scheme, parsed);
+}
+
+template<typename CHAR>
+void DoParseFileSystemURL(const CHAR* spec, int spec_len, Parsed* parsed) {
+  DCHECK(spec_len >= 0, "");
+
+  // Get the unused parts of the URL out of the way.
+  parsed->username.reset();
+  parsed->password.reset();
+  parsed->host.reset();
+  parsed->port.reset();
+  parsed->path.reset();   // May use this; reset for convenience.
+  parsed->ref.reset();    // May use this; reset for convenience.
+  parsed->query.reset();  // May use this; reset for convenience.
+  parsed->clear_inner_parsed();  // May use this; reset for convenience.
+
+  // Strip leading & trailing spaces and control characters.
+  int begin = 0;
+  TrimURL(spec, &begin, &spec_len);
+
+  // Handle empty specs or ones that contain only whitespace or control chars.
+  if (begin == spec_len) {
+    parsed->scheme.reset();
+    return;
+  }
+
+  int inner_start = -1;
+
+  // Extract the scheme.  We also handle the case where there is no scheme.
+  if (DoExtractScheme(&spec[begin], spec_len - begin, &parsed->scheme)) {
+    // Offset the results since we gave ExtractScheme a substring.
+    parsed->scheme.begin += begin;
+
+    if (parsed->scheme.end() == spec_len - 1)
+      return;
+
+    inner_start = parsed->scheme.end() + 1;
+  } else {
+    // No scheme found; that's not valid for filesystem URLs.
+    parsed->scheme.reset();
+    return;
+  }
+
+  Component inner_scheme;
+  const CHAR* inner_spec = &spec[inner_start];
+  int inner_spec_len = spec_len - inner_start;
+
+  if (DoExtractScheme(inner_spec, inner_spec_len, &inner_scheme)) {
+    // Offset the results since we gave ExtractScheme a substring.
+    inner_scheme.begin += inner_start;
+
+    if (inner_scheme.end() == spec_len - 1)
+      return;
+  } else {
+    // No scheme found; that's not valid for filesystem URLs.
+    // The best we can do is return "filesystem://".
+    return;
+  }
+
+  Parsed inner_parsed;
+
+  if (CompareSchemeComponent(spec, inner_scheme, kFileScheme)) {
+    // File URLs are special.
+    ParseFileURL(inner_spec, inner_spec_len, &inner_parsed);
+  } else if (CompareSchemeComponent(spec, inner_scheme, kFileSystemScheme)) {
+    // Filesystem URLs don't nest.
+    return;
+  } else if (IsStandard(spec, inner_scheme)) {
+    // All "normal" URLs.
+    DoParseStandardURL(inner_spec, inner_spec_len, &inner_parsed);
+  } else {
+    return;
+  }
+
+  // All members of inner_parsed need to be offset by inner_start.
+  // If we had any scheme that supported nesting more than one level deep,
+  // we'd have to recurse into the inner_parsed's inner_parsed when
+  // adjusting by inner_start.
+  inner_parsed.scheme.begin += inner_start;
+  inner_parsed.username.begin += inner_start;
+  inner_parsed.password.begin += inner_start;
+  inner_parsed.host.begin += inner_start;
+  inner_parsed.port.begin += inner_start;
+  inner_parsed.query.begin += inner_start;
+  inner_parsed.ref.begin += inner_start;
+  inner_parsed.path.begin += inner_start;
+
+  // Query and ref move from inner_parsed to parsed.
+  parsed->query = inner_parsed.query;
+  inner_parsed.query.reset();
+  parsed->ref = inner_parsed.ref;
+  inner_parsed.ref.reset();
+
+  parsed->set_inner_parsed(inner_parsed);
+  if (!inner_parsed.scheme.is_valid() || !inner_parsed.path.is_valid() ||
+      inner_parsed.inner_parsed()) {
+    return;
+  }
+
+  // The path in inner_parsed should start with a slash, then have a filesystem
+  // type followed by a slash.  From the first slash up to but excluding the
+  // second should be what it keeps; the rest goes to parsed.  If the path ends
+  // before the second slash, it's still pretty clear what the user meant, so
+  // we'll let that through.
+  if (!IsURLSlash(spec[inner_parsed.path.begin])) {
+    return;
+  }
+  int inner_path_end = inner_parsed.path.begin + 1;  // skip the leading slash
+  while (inner_path_end < spec_len &&
+      !IsURLSlash(spec[inner_path_end]))
+    ++inner_path_end;
+  parsed->path.begin = inner_path_end;
+  int new_inner_path_length = inner_path_end - inner_parsed.path.begin;
+  parsed->path.len = inner_parsed.path.len - new_inner_path_length;
+  parsed->inner_parsed()->path.len = new_inner_path_length;
+}
+
+// Initializes a path URL which is merely a scheme followed by a path. Examples
+// include "about:foo" and "javascript:alert('bar');"
+template<typename CHAR>
+void DoParsePathURL(const CHAR* spec, int spec_len,
+                    bool trim_path_end,
+                    Parsed* parsed) {
+  // Get the non-path and non-scheme parts of the URL out of the way, we never
+  // use them.
+  parsed->username.reset();
+  parsed->password.reset();
+  parsed->host.reset();
+  parsed->port.reset();
+  parsed->path.reset();
+  parsed->query.reset();
+  parsed->ref.reset();
+
+  // Strip leading & trailing spaces and control characters.
+  int scheme_begin = 0;
+  TrimURL(spec, &scheme_begin, &spec_len, trim_path_end);
+
+  // Handle empty specs or ones that contain only whitespace or control chars.
+  if (scheme_begin == spec_len) {
+    parsed->scheme.reset();
+    parsed->path.reset();
+    return;
+  }
+
+  int path_begin;
+  // Extract the scheme, with the path being everything following. We also
+  // handle the case where there is no scheme.
+  if (ExtractScheme(&spec[scheme_begin], spec_len - scheme_begin,
+                    &parsed->scheme)) {
+    // Offset the results since we gave ExtractScheme a substring.
+    parsed->scheme.begin += scheme_begin;
+    path_begin = parsed->scheme.end() + 1;
+  } else {
+    // No scheme case.
+    parsed->scheme.reset();
+    path_begin = scheme_begin;
+  }
+
+  if (path_begin == spec_len)
+    return;
+
+  ParsePath(spec,
+            MakeRange(path_begin, spec_len),
+            &parsed->path,
+            &parsed->query,
+            &parsed->ref);
+}
+
+template<typename CHAR>
+void DoParseMailtoURL(const CHAR* spec, int spec_len, Parsed* parsed) {
+  DCHECK(spec_len >= 0, "");
+
+  // Get the non-path and non-scheme parts of the URL out of the way, we never
+  // use them.
+  parsed->username.reset();
+  parsed->password.reset();
+  parsed->host.reset();
+  parsed->port.reset();
+  parsed->ref.reset();
+  parsed->query.reset();  // May use this; reset for convenience.
+
+  // Strip leading & trailing spaces and control characters.
+  int begin = 0;
+  TrimURL(spec, &begin, &spec_len);
+
+  // Handle empty specs or ones that contain only whitespace or control chars.
+  if (begin == spec_len) {
+    parsed->scheme.reset();
+    parsed->path.reset();
+    return;
+  }
+
+  int path_begin = -1;
+  int path_end = -1;
+
+  // Extract the scheme, with the path being everything following. We also
+  // handle the case where there is no scheme.
+  if (ExtractScheme(&spec[begin], spec_len - begin, &parsed->scheme)) {
+    // Offset the results since we gave ExtractScheme a substring.
+    parsed->scheme.begin += begin;
+
+    if (parsed->scheme.end() != spec_len - 1) {
+      path_begin = parsed->scheme.end() + 1;
+      path_end = spec_len;
+    }
+  } else {
+    // No scheme found, just path.
+    parsed->scheme.reset();
+    path_begin = begin;
+    path_end = spec_len;
+  }
+
+  // Split [path_begin, path_end) into a path + query.
+  for (int i = path_begin; i < path_end; ++i) {
+    if (spec[i] == '?') {
+      parsed->query = MakeRange(i + 1, path_end);
+      path_end = i;
+      break;
+    }
+  }
+
+  // For compatability with the standard URL parser, treat no path as
+  // -1, rather than having a length of 0
+  if (path_begin == path_end) {
+    parsed->path.reset();
+  } else {
+    parsed->path = MakeRange(path_begin, path_end);
+  }
+}
+
+// Converts a port number in a string to an integer. We'd like to just call
+// sscanf but our input is not NULL-terminated, which sscanf requires. Instead,
+// we copy the digits to a small stack buffer (since we know the maximum number
+// of digits in a valid port number) that we can NULL terminate.
+template<typename CHAR>
+int DoParsePort(const CHAR* spec, const Component& component) {
+  // Easy success case when there is no port.
+  const int kMaxDigits = 5;
+  if (!component.is_nonempty())
+    return PORT_UNSPECIFIED;
+
+  // Skip over any leading 0s.
+  Component digits_comp(component.end(), 0);
+  for (int i = 0; i < component.len; i++) {
+    if (spec[component.begin + i] != '0') {
+      digits_comp = MakeRange(component.begin + i, component.end());
+      break;
+    }
+  }
+  if (digits_comp.len == 0)
+    return 0;  // All digits were 0.
+
+  // Verify we don't have too many digits (we'll be copying to our buffer so
+  // we need to double-check).
+  if (digits_comp.len > kMaxDigits)
+    return PORT_INVALID;
+
+  // Copy valid digits to the buffer.
+  char digits[kMaxDigits + 1];  // +1 for null terminator
+  for (int i = 0; i < digits_comp.len; i++) {
+    CHAR ch = spec[digits_comp.begin + i];
+    if (!IsPortDigit(ch)) {
+      // Invalid port digit, fail.
+      return PORT_INVALID;
+    }
+    digits[i] = static_cast<char>(ch);
+  }
+
+  // Null-terminate the string and convert to integer. Since we guarantee
+  // only digits, atoi's lack of error handling is OK.
+  digits[digits_comp.len] = 0;
+  int port = atoi(digits);
+  if (port > 65535)
+    return PORT_INVALID;  // Out of range.
+  return port;
+}
+
+template<typename CHAR>
+void DoExtractFileName(const CHAR* spec,
+                       const Component& path,
+                       Component* file_name) {
+  // Handle empty paths: they have no file names.
+  if (!path.is_nonempty()) {
+    file_name->reset();
+    return;
+  }
+
+  // Extract the filename range from the path which is between
+  // the last slash and the following semicolon.
+  int file_end = path.end();
+  for (int i = path.end() - 1; i >= path.begin; i--) {
+    if (spec[i] == ';') {
+      file_end = i;
+    } else if (IsURLSlash(spec[i])) {
+      // File name is everything following this character to the end
+      *file_name = MakeRange(i + 1, file_end);
+      return;
+    }
+  }
+
+  // No slash found, this means the input was degenerate (generally paths
+  // will start with a slash). Let's call everything the file name.
+  *file_name = MakeRange(path.begin, file_end);
+  return;
+}
+
+template<typename CHAR>
+bool DoExtractQueryKeyValue(const CHAR* spec,
+                            Component* query,
+                            Component* key,
+                            Component* value) {
+  if (!query->is_nonempty())
+    return false;
+
+  int start = query->begin;
+  int cur = start;
+  int end = query->end();
+
+  // We assume the beginning of the input is the beginning of the "key" and we
+  // skip to the end of it.
+  key->begin = cur;
+  while (cur < end && spec[cur] != '&' && spec[cur] != '=')
+    cur++;
+  key->len = cur - key->begin;
+
+  // Skip the separator after the key (if any).
+  if (cur < end && spec[cur] == '=')
+    cur++;
+
+  // Find the value part.
+  value->begin = cur;
+  while (cur < end && spec[cur] != '&')
+    cur++;
+  value->len = cur - value->begin;
+
+  // Finally skip the next separator if any
+  if (cur < end && spec[cur] == '&')
+    cur++;
+
+  // Save the new query
+  *query = MakeRange(cur, end);
+  return true;
+}
+
+}  // namespace
+
+Parsed::Parsed() : inner_parsed_(NULL) {
+}
+
+Parsed::Parsed(const Parsed& other) :
+    scheme(other.scheme),
+    username(other.username),
+    password(other.password),
+    host(other.host),
+    port(other.port),
+    path(other.path),
+    query(other.query),
+    ref(other.ref),
+    inner_parsed_(NULL) {
+  if (other.inner_parsed_)
+    set_inner_parsed(*other.inner_parsed_);
+}
+
+Parsed& Parsed::operator=(const Parsed& other) {
+  if (this != &other) {
+    scheme = other.scheme;
+    username = other.username;
+    password = other.password;
+    host = other.host;
+    port = other.port;
+    path = other.path;
+    query = other.query;
+    ref = other.ref;
+    if (other.inner_parsed_)
+      set_inner_parsed(*other.inner_parsed_);
+    else
+      clear_inner_parsed();
+  }
+  return *this;
+}
+
+Parsed::~Parsed() {
+  delete inner_parsed_;
+}
+
+int Parsed::Length() const {
+  if (ref.is_valid())
+    return ref.end();
+  return CountCharactersBefore(REF, false);
+}
+
+int Parsed::CountCharactersBefore(ComponentType type,
+                                  bool include_delimiter) const {
+  if (type == SCHEME)
+    return scheme.begin;
+
+  // There will be some characters after the scheme like "://" and we don't
+  // know how many. Search forwards for the next thing until we find one.
+  int cur = 0;
+  if (scheme.is_valid())
+    cur = scheme.end() + 1;  // Advance over the ':' at the end of the scheme.
+
+  if (username.is_valid()) {
+    if (type <= USERNAME)
+      return username.begin;
+    cur = username.end() + 1;  // Advance over the '@' or ':' at the end.
+  }
+
+  if (password.is_valid()) {
+    if (type <= PASSWORD)
+      return password.begin;
+    cur = password.end() + 1;  // Advance over the '@' at the end.
+  }
+
+  if (host.is_valid()) {
+    if (type <= HOST)
+      return host.begin;
+    cur = host.end();
+  }
+
+  if (port.is_valid()) {
+    if (type < PORT || (type == PORT && include_delimiter))
+      return port.begin - 1;  // Back over delimiter.
+    if (type == PORT)
+      return port.begin;  // Don't want delimiter counted.
+    cur = port.end();
+  }
+
+  if (path.is_valid()) {
+    if (type <= PATH)
+      return path.begin;
+    cur = path.end();
+  }
+
+  if (query.is_valid()) {
+    if (type < QUERY || (type == QUERY && include_delimiter))
+      return query.begin - 1;  // Back over delimiter.
+    if (type == QUERY)
+      return query.begin;  // Don't want delimiter counted.
+    cur = query.end();
+  }
+
+  if (ref.is_valid()) {
+    if (type == REF && !include_delimiter)
+      return ref.begin;  // Back over delimiter.
+
+    // When there is a ref and we get here, the component we wanted was before
+    // this and not found, so we always know the beginning of the ref is right.
+    return ref.begin - 1;  // Don't want delimiter counted.
+  }
+
+  return cur;
+}
+
+Component Parsed::GetContent() const {
+  const int begin = CountCharactersBefore(USERNAME, false);
+  const int len = Length() - begin;
+  // For compatability with the standard URL parser, we treat no content as
+  // -1, rather than having a length of 0 (we normally wouldn't care so
+  // much for these non-standard URLs).
+  return len ? Component(begin, len) : Component();
+}
+
+bool ExtractScheme(const char* url, int url_len, Component* scheme) {
+  return DoExtractScheme(url, url_len, scheme);
+}
+
+bool ExtractScheme(const base::char16* url, int url_len, Component* scheme) {
+  return DoExtractScheme(url, url_len, scheme);
+}
+
+// This handles everything that may be an authority terminator, including
+// backslash. For special backslash handling see DoParseAfterScheme.
+bool IsAuthorityTerminator(base::char16 ch) {
+  return IsURLSlash(ch) || ch == '?' || ch == '#';
+}
+
+void ExtractFileName(const char* url,
+                     const Component& path,
+                     Component* file_name) {
+  DoExtractFileName(url, path, file_name);
+}
+
+void ExtractFileName(const base::char16* url,
+                     const Component& path,
+                     Component* file_name) {
+  DoExtractFileName(url, path, file_name);
+}
+
+bool ExtractQueryKeyValue(const char* url,
+                          Component* query,
+                          Component* key,
+                          Component* value) {
+  return DoExtractQueryKeyValue(url, query, key, value);
+}
+
+bool ExtractQueryKeyValue(const base::char16* url,
+                          Component* query,
+                          Component* key,
+                          Component* value) {
+  return DoExtractQueryKeyValue(url, query, key, value);
+}
+
+void ParseAuthority(const char* spec,
+                    const Component& auth,
+                    Component* username,
+                    Component* password,
+                    Component* hostname,
+                    Component* port_num) {
+  DoParseAuthority(spec, auth, username, password, hostname, port_num);
+}
+
+void ParseAuthority(const base::char16* spec,
+                    const Component& auth,
+                    Component* username,
+                    Component* password,
+                    Component* hostname,
+                    Component* port_num) {
+  DoParseAuthority(spec, auth, username, password, hostname, port_num);
+}
+
+int ParsePort(const char* url, const Component& port) {
+  return DoParsePort(url, port);
+}
+
+int ParsePort(const base::char16* url, const Component& port) {
+  return DoParsePort(url, port);
+}
+
+void ParseStandardURL(const char* url, int url_len, Parsed* parsed) {
+  DoParseStandardURL(url, url_len, parsed);
+}
+
+void ParseStandardURL(const base::char16* url, int url_len, Parsed* parsed) {
+  DoParseStandardURL(url, url_len, parsed);
+}
+
+void ParsePathURL(const char* url,
+                  int url_len,
+                  bool trim_path_end,
+                  Parsed* parsed) {
+  DoParsePathURL(url, url_len, trim_path_end, parsed);
+}
+
+void ParsePathURL(const base::char16* url,
+                  int url_len,
+                  bool trim_path_end,
+                  Parsed* parsed) {
+  DoParsePathURL(url, url_len, trim_path_end, parsed);
+}
+
+void ParseFileSystemURL(const char* url, int url_len, Parsed* parsed) {
+  DoParseFileSystemURL(url, url_len, parsed);
+}
+
+void ParseFileSystemURL(const base::char16* url, int url_len, Parsed* parsed) {
+  DoParseFileSystemURL(url, url_len, parsed);
+}
+
+void ParseMailtoURL(const char* url, int url_len, Parsed* parsed) {
+  DoParseMailtoURL(url, url_len, parsed);
+}
+
+void ParseMailtoURL(const base::char16* url, int url_len, Parsed* parsed) {
+  DoParseMailtoURL(url, url_len, parsed);
+}
+
+void ParsePathInternal(const char* spec,
+                       const Component& path,
+                       Component* filepath,
+                       Component* query,
+                       Component* ref) {
+  ParsePath(spec, path, filepath, query, ref);
+}
+
+void ParsePathInternal(const base::char16* spec,
+                       const Component& path,
+                       Component* filepath,
+                       Component* query,
+                       Component* ref) {
+  ParsePath(spec, path, filepath, query, ref);
+}
+
+void ParseAfterScheme(const char* spec,
+                      int spec_len,
+                      int after_scheme,
+                      Parsed* parsed) {
+  DoParseAfterScheme(spec, spec_len, after_scheme, parsed);
+}
+
+void ParseAfterScheme(const base::char16* spec,
+                      int spec_len,
+                      int after_scheme,
+                      Parsed* parsed) {
+  DoParseAfterScheme(spec, spec_len, after_scheme, parsed);
+}
+
+}  // namespace url
diff --git a/src/common/url/url_parse_file.cc b/src/common/url/url_parse_file.cc
new file mode 100644 (file)
index 0000000..09ef8a0
--- /dev/null
@@ -0,0 +1,247 @@
+/*
+ * Copyright 2014 The Chromium Authors. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+
+ *    * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *    * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *    * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include "base/logging.h"
+#include "url/third_party/mozilla/url_parse.h"
+#include "url/url_file.h"
+#include "url/url_parse_internal.h"
+
+// Interesting IE file:isms...
+//
+//  INPUT                      OUTPUT
+//  =========================  ==============================
+//  file:/foo/bar              file:///foo/bar
+//      The result here seems totally invalid!?!? This isn't UNC.
+//
+//  file:/
+//  file:// or any other number of slashes
+//      IE6 doesn't do anything at all if you click on this link. No error:
+//      nothing. IE6's history system seems to always color this link, so I'm
+//      guessing that it maps internally to the empty URL.
+//
+//  C:\                        file:///C:/
+//      When on a file: URL source page, this link will work. When over HTTP,
+//      the file: URL will appear in the status bar but the link will not work
+//      (security restriction for all file URLs).
+//
+//  file:foo/                  file:foo/     (invalid?!?!?)
+//  file:/foo/                 file:///foo/  (invalid?!?!?)
+//  file://foo/                file://foo/   (UNC to server "foo")
+//  file:///foo/               file:///foo/  (invalid, seems to be a file)
+//  file:////foo/              file://foo/   (UNC to server "foo")
+//      Any more than four slashes is also treated as UNC.
+//
+//  file:C:/                   file://C:/
+//  file:/C:/                  file://C:/
+//      The number of slashes after "file:" don't matter if the thing following
+//      it looks like an absolute drive path. Also, slashes and backslashes are
+//      equally valid here.
+
+namespace url {
+
+namespace {
+
+// A subcomponent of DoInitFileURL, the input of this function should be a UNC
+// path name, with the index of the first character after the slashes following
+// the scheme given in |after_slashes|. This will initialize the host, path,
+// query, and ref, and leave the other output components untouched
+// (DoInitFileURL handles these for us).
+template<typename CHAR>
+void DoParseUNC(const CHAR* spec,
+                int after_slashes,
+                int spec_len,
+               Parsed* parsed) {
+  int next_slash = FindNextSlash(spec, after_slashes, spec_len);
+  if (next_slash == spec_len) {
+    // No additional slash found, as in "file://foo", treat the text as the
+    // host with no path (this will end up being UNC to server "foo").
+    int host_len = spec_len - after_slashes;
+    if (host_len)
+      parsed->host = Component(after_slashes, host_len);
+    else
+      parsed->host.reset();
+    parsed->path.reset();
+    return;
+  }
+
+#ifdef WIN32
+  // See if we have something that looks like a path following the first
+  // component. As in "file://localhost/c:/", we get "c:/" out. We want to
+  // treat this as a having no host but the path given. Works on Windows only.
+  if (DoesBeginWindowsDriveSpec(spec, next_slash + 1, spec_len)) {
+    parsed->host.reset();
+    ParsePathInternal(spec, MakeRange(next_slash, spec_len),
+                      &parsed->path, &parsed->query, &parsed->ref);
+    return;
+  }
+#endif
+
+  // Otherwise, everything up until that first slash we found is the host name,
+  // which will end up being the UNC host. For example "file://foo/bar.txt"
+  // will get a server name of "foo" and a path of "/bar". Later, on Windows,
+  // this should be treated as the filename "\\foo\bar.txt" in proper UNC
+  // notation.
+  int host_len = next_slash - after_slashes;
+  if (host_len)
+    parsed->host = MakeRange(after_slashes, next_slash);
+  else
+    parsed->host.reset();
+  if (next_slash < spec_len) {
+    ParsePathInternal(spec, MakeRange(next_slash, spec_len),
+                      &parsed->path, &parsed->query, &parsed->ref);
+  } else {
+    parsed->path.reset();
+  }
+}
+
+// A subcomponent of DoParseFileURL, the input should be a local file, with the
+// beginning of the path indicated by the index in |path_begin|. This will
+// initialize the host, path, query, and ref, and leave the other output
+// components untouched (DoInitFileURL handles these for us).
+template<typename CHAR>
+void DoParseLocalFile(const CHAR* spec,
+                      int path_begin,
+                      int spec_len,
+                      Parsed* parsed) {
+  parsed->host.reset();
+  ParsePathInternal(spec, MakeRange(path_begin, spec_len),
+                    &parsed->path, &parsed->query, &parsed->ref);
+}
+
+// Backend for the external functions that operates on either char type.
+// Handles cases where there is a scheme, but also when handed the first
+// character following the "file:" at the beginning of the spec. If so,
+// this is usually a slash, but needn't be; we allow paths like "file:c:\foo".
+template<typename CHAR>
+void DoParseFileURL(const CHAR* spec, int spec_len, Parsed* parsed) {
+  DCHECK(spec_len >= 0, "");
+
+  // Get the parts we never use for file URLs out of the way.
+  parsed->username.reset();
+  parsed->password.reset();
+  parsed->port.reset();
+
+  // Many of the code paths don't set these, so it's convenient to just clear
+  // them. We'll write them in those cases we need them.
+  parsed->query.reset();
+  parsed->ref.reset();
+
+  // Strip leading & trailing spaces and control characters.
+  int begin = 0;
+  TrimURL(spec, &begin, &spec_len);
+
+  // Find the scheme, if any.
+  int num_slashes = CountConsecutiveSlashes(spec, begin, spec_len);
+  int after_scheme;
+  int after_slashes;
+#ifdef WIN32
+  // See how many slashes there are. We want to handle cases like UNC but also
+  // "/c:/foo". This is when there is no scheme, so we can allow pages to do
+  // links like "c:/foo/bar" or "//foo/bar". This is also called by the
+  // relative URL resolver when it determines there is an absolute URL, which
+  // may give us input like "/c:/foo".
+  after_slashes = begin + num_slashes;
+  if (DoesBeginWindowsDriveSpec(spec, after_slashes, spec_len)) {
+    // Windows path, don't try to extract the scheme (for example, "c:\foo").
+    parsed->scheme.reset();
+    after_scheme = after_slashes;
+  } else if (DoesBeginUNCPath(spec, begin, spec_len, false)) {
+    // Windows UNC path: don't try to extract the scheme, but keep the slashes.
+    parsed->scheme.reset();
+    after_scheme = begin;
+  } else
+#endif
+  {
+    // ExtractScheme doesn't understand the possibility of filenames with
+    // colons in them, in which case it returns the entire spec up to the
+    // colon as the scheme. So handle /foo.c:5 as a file but foo.c:5 as
+    // the foo.c: scheme.
+    if (!num_slashes &&
+        ExtractScheme(&spec[begin], spec_len - begin, &parsed->scheme)) {
+      // Offset the results since we gave ExtractScheme a substring.
+      parsed->scheme.begin += begin;
+      after_scheme = parsed->scheme.end() + 1;
+    } else {
+      // No scheme found, remember that.
+      parsed->scheme.reset();
+      after_scheme = begin;
+    }
+  }
+
+  // Handle empty specs ones that contain only whitespace or control chars,
+  // or that are just the scheme (for example "file:").
+  if (after_scheme == spec_len) {
+    parsed->host.reset();
+    parsed->path.reset();
+    return;
+  }
+
+  num_slashes = CountConsecutiveSlashes(spec, after_scheme, spec_len);
+  after_slashes = after_scheme + num_slashes;
+#ifdef WIN32
+  // Check whether the input is a drive again. We checked above for windows
+  // drive specs, but that's only at the very beginning to see if we have a
+  // scheme at all. This test will be duplicated in that case, but will
+  // additionally handle all cases with a real scheme such as "file:///C:/".
+  if (!DoesBeginWindowsDriveSpec(spec, after_slashes, spec_len) &&
+      num_slashes != 3) {
+    // Anything not beginning with a drive spec ("c:\") on Windows is treated
+    // as UNC, with the exception of three slashes which always means a file.
+    // Even IE7 treats file:///foo/bar as "/foo/bar", which then fails.
+    DoParseUNC(spec, after_slashes, spec_len, parsed);
+    return;
+  }
+#else
+  // file: URL with exactly 2 slashes is considered to have a host component.
+  if (num_slashes == 2) {
+    DoParseUNC(spec, after_slashes, spec_len, parsed);
+    return;
+  }
+#endif  // WIN32
+
+  // Easy and common case, the full path immediately follows the scheme
+  // (modulo slashes), as in "file://c:/foo". Just treat everything from
+  // there to the end as the path. Empty hosts have 0 length instead of -1.
+  // We include the last slash as part of the path if there is one.
+  DoParseLocalFile(spec,
+      num_slashes > 0 ? after_scheme + num_slashes - 1 : after_scheme,
+      spec_len, parsed);
+}
+
+}  // namespace
+
+void ParseFileURL(const char* url, int url_len, Parsed* parsed) {
+  DoParseFileURL(url, url_len, parsed);
+}
+
+void ParseFileURL(const base::char16* url, int url_len, Parsed* parsed) {
+  DoParseFileURL(url, url_len, parsed);
+}
+
+}  // namespace url
diff --git a/src/common/url/url_parse_internal.h b/src/common/url/url_parse_internal.h
new file mode 100644 (file)
index 0000000..8445870
--- /dev/null
@@ -0,0 +1,113 @@
+/*
+ * Copyright 2014 The Chromium Authors. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+
+ *    * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *    * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *    * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#pragma once
+
+// Contains common inline helper functions used by the URL parsing routines.
+
+#include "url/third_party/mozilla/url_parse.h"
+
+namespace url {
+
+// We treat slashes and backslashes the same for IE compatability.
+inline bool IsURLSlash(base::char16 ch) {
+  return ch == '/' || ch == '\\';
+}
+
+// Returns true if we should trim this character from the URL because it is a
+// space or a control character.
+inline bool ShouldTrimFromURL(base::char16 ch) {
+  return ch <= ' ';
+}
+
+// Given an already-initialized begin index and length, this shrinks the range
+// to eliminate "should-be-trimmed" characters. Note that the length does *not*
+// indicate the length of untrimmed data from |*begin|, but rather the position
+// in the input string (so the string starts at character |*begin| in the spec,
+// and goes until |*len|).
+template<typename CHAR>
+inline void TrimURL(const CHAR* spec, int* begin, int* len,
+                    bool trim_path_end = true) {
+  // Strip leading whitespace and control characters.
+  while (*begin < *len && ShouldTrimFromURL(spec[*begin]))
+    (*begin)++;
+
+  if (trim_path_end) {
+    // Strip trailing whitespace and control characters. We need the >i test
+    // for when the input string is all blanks; we don't want to back past the
+    // input.
+    while (*len > *begin && ShouldTrimFromURL(spec[*len - 1]))
+      (*len)--;
+  }
+}
+
+// Counts the number of consecutive slashes starting at the given offset
+// in the given string of the given length.
+template<typename CHAR>
+inline int CountConsecutiveSlashes(const CHAR *str,
+                                   int begin_offset, int str_len) {
+  int count = 0;
+  while (begin_offset + count < str_len &&
+         IsURLSlash(str[begin_offset + count]))
+    ++count;
+  return count;
+}
+
+// Internal functions in url_parse.cc that parse the path, that is, everything
+// following the authority section. The input is the range of everything
+// following the authority section, and the output is the identified ranges.
+//
+// This is designed for the file URL parser or other consumers who may do
+// special stuff at the beginning, but want regular path parsing, it just
+// maps to the internal parsing function for paths.
+void ParsePathInternal(const char* spec,
+                       const Component& path,
+                       Component* filepath,
+                       Component* query,
+                       Component* ref);
+void ParsePathInternal(const base::char16* spec,
+                       const Component& path,
+                       Component* filepath,
+                       Component* query,
+                       Component* ref);
+
+
+// Given a spec and a pointer to the character after the colon following the
+// scheme, this parses it and fills in the structure, Every item in the parsed
+// structure is filled EXCEPT for the scheme, which is untouched.
+void ParseAfterScheme(const char* spec,
+                      int spec_len,
+                      int after_scheme,
+                      Parsed* parsed);
+void ParseAfterScheme(const base::char16* spec,
+                      int spec_len,
+                      int after_scheme,
+                      Parsed* parsed);
+
+}  // namespace url
diff --git a/src/common/url/url_util.cc b/src/common/url/url_util.cc
new file mode 100644 (file)
index 0000000..510cd24
--- /dev/null
@@ -0,0 +1,187 @@
+/*
+ * Copyright 2014 The Chromium Authors. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+
+ *    * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *    * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *    * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include "url/url_util.h"
+
+#include <string.h>
+#include <vector>
+
+#include "base/logging.h"
+#include "url/url_util_internal.h"
+
+namespace url {
+
+namespace {
+
+// ASCII-specific tolower.  The standard library's tolower is locale sensitive,
+// so we don't want to use it here.
+template<class Char>
+inline Char ToLowerASCII(Char c) {
+  return (c >= 'A' && c <= 'Z') ? (c + ('a' - 'A')) : c;
+}
+
+// Backend for LowerCaseEqualsASCII.
+template<typename Iter>
+inline bool DoLowerCaseEqualsASCII(Iter a_begin, Iter a_end, const char* b) {
+  for (Iter it = a_begin; it != a_end; ++it, ++b) {
+    if (!*b || ToLowerASCII(*it) != *b)
+      return false;
+  }
+  return *b == 0;
+}
+
+const int kNumStandardURLSchemes = 9;
+const char* kStandardURLSchemes[kNumStandardURLSchemes] = {
+  kHttpScheme,
+  kHttpsScheme,
+  kFileScheme,  // Yes, file urls can have a hostname!
+  kFtpScheme,
+  kGopherScheme,
+  kWsScheme,    // WebSocket.
+  kWssScheme,   // WebSocket secure.
+  kFileSystemScheme,
+  "rtsp",
+};
+
+// List of the currently installed standard schemes. This list is lazily
+// initialized by InitStandardSchemes and is leaked on shutdown to prevent
+// any destructors from being called that will slow us down or cause problems.
+std::vector<const char*>* standard_schemes = NULL;
+
+// See the LockStandardSchemes declaration in the header.
+bool standard_schemes_locked = false;
+
+// Ensures that the standard_schemes list is initialized, does nothing if it
+// already has values.
+void InitStandardSchemes() {
+  if (standard_schemes)
+    return;
+  standard_schemes = new std::vector<const char*>;
+  for (int i = 0; i < kNumStandardURLSchemes; i++)
+    standard_schemes->push_back(kStandardURLSchemes[i]);
+}
+
+// Given a string and a range inside the string, compares it to the given
+// lower-case |compare_to| buffer.
+template<typename CHAR>
+inline bool DoCompareSchemeComponent(const CHAR* spec,
+                                     const Component& component,
+                                     const char* compare_to) {
+  if (!component.is_nonempty())
+    return compare_to[0] == 0;  // When component is empty, match empty scheme.
+  return LowerCaseEqualsASCII(&spec[component.begin],
+                              &spec[component.end()],
+                              compare_to);
+}
+
+// Returns true if the given scheme identified by |scheme| within |spec| is one
+// of the registered "standard" schemes.
+template<typename CHAR>
+bool DoIsStandard(const CHAR* spec, const Component& scheme) {
+  if (!scheme.is_nonempty())
+    return false;  // Empty or invalid schemes are non-standard.
+
+  InitStandardSchemes();
+  for (size_t i = 0; i < standard_schemes->size(); i++) {
+    if (LowerCaseEqualsASCII(&spec[scheme.begin], &spec[scheme.end()],
+                             standard_schemes->at(i)))
+      return true;
+  }
+  return false;
+}
+
+
+}  // namespace
+
+void Initialize() {
+  InitStandardSchemes();
+}
+
+void Shutdown() {
+  if (standard_schemes) {
+    delete standard_schemes;
+    standard_schemes = NULL;
+  }
+}
+
+void LockStandardSchemes() {
+  standard_schemes_locked = true;
+}
+
+
+
+// Front-ends for LowerCaseEqualsASCII.
+bool LowerCaseEqualsASCII(const char* a_begin,
+                          const char* a_end,
+                          const char* b) {
+  return DoLowerCaseEqualsASCII(a_begin, a_end, b);
+}
+
+bool LowerCaseEqualsASCII(const char* a_begin,
+                          const char* a_end,
+                          const char* b_begin,
+                          const char* b_end) {
+  while (a_begin != a_end && b_begin != b_end &&
+         ToLowerASCII(*a_begin) == *b_begin) {
+    a_begin++;
+    b_begin++;
+  }
+  return a_begin == a_end && b_begin == b_end;
+}
+
+bool LowerCaseEqualsASCII(const base::char16* a_begin,
+                          const base::char16* a_end,
+                          const char* b) {
+  return DoLowerCaseEqualsASCII(a_begin, a_end, b);
+}
+
+
+//=========================================
+
+bool IsStandard(const char* spec, const Component& scheme) {
+  return DoIsStandard(spec, scheme);
+}
+
+bool IsStandard(const base::char16* spec, const Component& scheme) {
+  return DoIsStandard(spec, scheme);
+}
+
+bool CompareSchemeComponent(const char* spec,
+                            const Component& component,
+                            const char* compare_to) {
+  return DoCompareSchemeComponent(spec, component, compare_to);
+}
+
+bool CompareSchemeComponent(const base::char16* spec,
+                            const Component& component,
+                            const char* compare_to) {
+  return DoCompareSchemeComponent(spec, component, compare_to);
+}
+
+}  // namespace url
diff --git a/src/common/url/url_util.h b/src/common/url/url_util.h
new file mode 100644 (file)
index 0000000..8d43d73
--- /dev/null
@@ -0,0 +1,72 @@
+/*
+ * Copyright 2014 The Chromium Authors. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+
+ *    * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *    * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *    * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#pragma once
+
+#include <string>
+
+#include "base/strings/string16.h"
+#include "url/url_constants.h"
+#include "url/url_export.h"
+#include "url/third_party/mozilla/url_parse.h"
+
+namespace url {
+
+// Returns true if the given string represents a standard URL. This means that
+// either the scheme is in the list of known standard schemes.
+URL_EXPORT bool IsStandard(const char* spec, const Component& scheme);
+URL_EXPORT bool IsStandard(const base::char16* spec, const Component& scheme);
+
+// TODO(brettw) remove this. This is a temporary compatibility hack to avoid
+// breaking the WebKit build when this version is synced via Chrome.
+inline bool IsStandard(const char* spec,
+                       int spec_len,
+                       const Component& scheme) {
+  return IsStandard(spec, scheme);
+}
+
+// Compare the lower-case form of the given string against the given ASCII
+// string.  This is useful for doing checking if an input string matches some
+// token, and it is optimized to avoid intermediate string copies.
+//
+// The versions of this function that don't take a b_end assume that the b
+// string is NULL terminated.
+URL_EXPORT bool LowerCaseEqualsASCII(const char* a_begin,
+                                     const char* a_end,
+                                     const char* b);
+URL_EXPORT bool LowerCaseEqualsASCII(const char* a_begin,
+                                     const char* a_end,
+                                     const char* b_begin,
+                                     const char* b_end);
+URL_EXPORT bool LowerCaseEqualsASCII(const base::char16* a_begin,
+                                     const base::char16* a_end,
+                                     const char* b);
+
+
+}  // namespace url
diff --git a/src/common/url/url_util_internal.h b/src/common/url/url_util_internal.h
new file mode 100644 (file)
index 0000000..fe12d3e
--- /dev/null
@@ -0,0 +1,48 @@
+/*
+ * Copyright 2014 The Chromium Authors. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+
+ *    * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *    * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *    * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#pragma once
+
+#include <string>
+
+#include "base/strings/string16.h"
+#include "url/third_party/mozilla/url_parse.h"
+
+namespace url {
+
+// Given a string and a range inside the string, compares it to the given
+// lower-case |compare_to| buffer.
+bool CompareSchemeComponent(const char* spec,
+                            const Component& component,
+                            const char* compare_to);
+bool CompareSchemeComponent(const base::char16* spec,
+                            const Component& component,
+                            const char* compare_to);
+
+}  // namespace url
diff --git a/src/curl/CMakeLists.txt b/src/curl/CMakeLists.txt
new file mode 100644 (file)
index 0000000..f26aa2a
--- /dev/null
@@ -0,0 +1,53 @@
+# Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
+#
+#    Licensed under the Apache License, Version 2.0 (the "License");
+#    you may not use this file except in compliance with the License.
+#    You may obtain a copy of the License at
+#
+#        http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS,
+#    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#    See the License for the specific language governing permissions and
+#    limitations under the License.
+#
+# @file     CMakeLists.txt
+# @author   Kyungwook Tak (k.tak@samsung.com)
+# @brief    TPKP curl lib makefile
+#
+PKG_CHECK_MODULES(TPKP_CURL_DEP
+       REQUIRED
+       openssl
+       libcurl
+       dlog
+       )
+
+INCLUDE_DIRECTORIES(
+       SYSTEM
+       include
+       ${PROJECT_SOURCE_DIR}/src/common/include # common library interface header
+       ${TPKP_CURL_DEP_INCLUDE_DIRS}
+       )
+
+SET(TPKP_CURL_SRCS
+       tpkp_curl.cpp
+       )
+
+ADD_LIBRARY(${TARGET_TPKP_CURL_LIB} SHARED ${TPKP_CURL_SRCS})
+
+SET_TARGET_PROPERTIES(${TARGET_TPKP_CURL_LIB}
+       PROPERTIES
+               COMPILE_FLAGS "-D_GNU_SOURCE -fPIC -fvisibility=hidden"
+               SOVERSION ${SO_VERSION}
+               VERSION ${VERSION}
+       )
+
+TARGET_LINK_LIBRARIES(${TARGET_TPKP_CURL_LIB}
+       ${TARGET_TPKP_COMMON_LIB}
+       ${TPKP_CURL_DEP_LIBRARIES}
+       )
+
+INSTALL(TARGETS ${TARGET_TPKP_CURL_LIB} DESTINATION ${LIB_INSTALL_DIR})
+
+INSTALL(FILES include/tpkp_curl.h DESTINATION ${INCLUDEDIR}/tpkp/curl)
diff --git a/src/curl/include/tpkp_curl.h b/src/curl/include/tpkp_curl.h
new file mode 100644 (file)
index 0000000..8b0126b
--- /dev/null
@@ -0,0 +1,141 @@
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ *    Licensed under the Apache License, Version 2.0 (the "License");
+ *    you may not use this file except in compliance with the License.
+ *    You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *    Unless required by applicable law or agreed to in writing, software
+ *    distributed under the License is distributed on an "AS IS" BASIS,
+ *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *    See the License for the specific language governing permissions and
+ *    limitations under the License.
+ */
+/*
+ * @file        tpkp_curl.h
+ * @author      Kyungwook Tak (k.tak@samsung.com)
+ * @version     1.0
+ * @brief       Tizen Https Public Key Pinning interface for libcurl.
+ */
+#ifndef TPKP_CURL_H_
+#define TPKP_CURL_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <openssl/ssl.h>
+#include <curl/curl.h>
+#include <tpkp_error.h>
+
+/*
+ *  @brief   verify_callback of OpenSSL SSL_CTX_set_verify.
+ *
+ *  @remarks verify_callback which verifies HPKP with url set by
+ *           tpkp_curl_set_url_data() in ssl_ctx_callback set by
+ *           CURLOPT_SSL_CTX_FUNCTION curl option.
+ *  @remarks tpkp_curl_set_url_data() should be used to set url data
+ *           on ssl_ctx_callback.
+ *
+ *
+ *  @param[in] preverify_ok Whether the verification of the certificate in
+ *                          question was passed(1) or not(0)
+ *  @param[in] x509_ctx     pointer to the complete context used for
+ *                          certificate chain verification
+ *
+ *  @return return 1 on success, otherwise return 0.
+ *
+ *  @see tpkp_curl_set_url_data()
+ */
+int tpkp_curl_verify_callback(int preverify_ok, X509_STORE_CTX *x509_ctx);
+
+/*
+ *  @brief   Sets current url to check pinned info later (in tpkp_curl_verify_callback())
+ *
+ *  @remarks Url data is saved thread-specifically.
+ *  @remarks tpkp_curl_cleanup() should be called before current thread ended
+ *           or tpkp_curl_cleanup_all() should be called on thread globally
+ *           before the process ended to use libcurl.
+ *
+ *  @param[in]     curl     cURL handle
+ *
+ *  @return #TPKP_E_NONE on success.
+ *
+ *  @see tpkp_curl_cleanup()
+ *  @see tpkp_curl_cleanup_all()
+ */
+tpkp_e tpkp_curl_set_url_data(CURL *curl);
+
+/*
+ *  @brief   Sets verify_callback with SSL_CTX_set_verify.
+ *
+ *  @remarks For clients who doesn't use SSL_CTX_set_verify in ssl_ctx_callback.
+ *  @remarks url data is set internall, so client doesn't needed to call
+ *           tpkp_curl_set_url_data().
+ *  @remarks tpkp_curl_cleanup() should be called before current thread ended
+ *           or tpkp_curl_cleanup_all() should be called on thread globally
+ *           before the process ended to use libcurl.
+ *
+ *  @param[in]     curl     cURL handle
+ *  @param[in/out] ssl_ctx  OpenSSL SSL_CTX
+ *
+ *  @return #TPKP_E_NONE on success.
+ *
+ *  @see tpkp_curl_cleanup()
+ *  @see tpkp_curl_cleanup_all()
+ */
+tpkp_e tpkp_curl_set_verify(CURL *curl, SSL_CTX *ssl_ctx);
+
+/*
+ *  @brief SSL context callback for OpenSSL. callback type is defined by libcurl.
+ *
+ *  @remarks Refer CURLOPT_SSL_CTX_FUNCTION and ssl_ctx_callback defined in libcurl.
+ *  @remarks tpkp_curl_cleanup() should be called before current thread ended
+ *           or tpkp_curl_cleanup_all() should be called on thread globally
+ *           before the process ended to use libcurl.
+ *
+ *  @param[in]     curl     cURL handle
+ *  @param[in/out] ssl_ctx  OpenSSL SSL_CTX
+ *  @param[in]     userptr  Not used
+ *
+ *  @return TPKP_E_NONE on success.
+ *
+ *  @retval #TPKP_E_NONE
+ *
+ *  @see tpkp_curl_cleanup()
+ *  @see tpkp_curl_cleanup_all()
+ */
+CURLcode tpkp_curl_ssl_ctx_callback(CURL *curl, void *ssl_ctx, void *userptr);
+
+/*
+ *  @brief   Cleans up memory of current thread.
+ *
+ *  @remarks Only cleans up current thread's specific memory. It should be called
+ *           inside of thread before end.
+ *  @remarks Call beside of curl_[easy|multi]_cleanup().
+ *
+ *  @see tpkp_curl_ssl_ctx_callback()
+ *  @see tpkp_curl_set_verify()
+ *  @see tpkp_curl_set_url_data()
+ */
+void tpkp_curl_cleanup(void);
+
+/*
+ *  @brief   Cleans up all memory used by tpkp_curl API.
+ *
+ *  @remarks Should be called thread-globally, after all jobs done by worker threads.
+ *  @remarks Call beside of curl_global_cleanup().
+ *
+ *  @see tpkp_curl_ssl_ctx_callback()
+ *  @see tpkp_curl_set_verify()
+ *  @see tpkp_curl_set_url_data()
+ */
+void tpkp_curl_cleanup_all(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* TPKP_CURL_H_ */
diff --git a/src/curl/tpkp_curl.cpp b/src/curl/tpkp_curl.cpp
new file mode 100644 (file)
index 0000000..2ba5cfe
--- /dev/null
@@ -0,0 +1,188 @@
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ *    Licensed under the Apache License, Version 2.0 (the "License");
+ *    you may not use this file except in compliance with the License.
+ *    You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *    Unless required by applicable law or agreed to in writing, software
+ *    distributed under the License is distributed on an "AS IS" BASIS,
+ *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *    See the License for the specific language governing permissions and
+ *    limitations under the License.
+ */
+/*
+ * @file        tpkp_curl.cpp
+ * @author      Kyungwook Tak (k.tak@samsung.com)
+ * @version     1.0
+ * @brief       Tizen Https Public Key Pinning implementation for libcurl.
+ */
+#include <string>
+#include <memory>
+#include <map>
+#include <mutex>
+
+#include <curl/curl.h>
+
+#include "tpkp_common.h"
+#include "tpkp_curl.h"
+
+namespace {
+
+std::map<pid_t, std::string> s_urlmap;
+std::mutex s_mutex;
+
+inline CURLcode err_tpkp_to_curle(tpkp_e err) noexcept
+{
+       switch (err) {
+       case TPKP_E_NONE:                    return CURLE_OK;
+       case TPKP_E_MEMORY:                  return CURLE_OUT_OF_MEMORY;
+       case TPKP_E_INVALID_URL:             return CURLE_URL_MALFORMAT;
+       case TPKP_E_NO_URL_DATA:             return CURLE_SSL_CERTPROBLEM;
+       case TPKP_E_PUBKEY_MISMATCH:         return CURLE_SSL_PINNEDPUBKEYNOTMATCH;
+       case TPKP_E_INVALID_CERT:
+       case TPKP_E_INVALID_PEER_CERT_CHAIN:
+       case TPKP_E_FAILED_GET_PUBKEY_HASH:  return CURLE_PEER_FAILED_VERIFICATION;
+       case TPKP_E_STD_EXCEPTION:
+       case TPKP_E_INTERNAL:
+       default:                             return CURLE_UNKNOWN_OPTION;
+       }
+}
+
+TPKP::RawBuffer getPubkeyHash(X509 *cert, TPKP::HashAlgo algo)
+{
+       std::unique_ptr<EVP_PKEY, void(*)(EVP_PKEY *)>
+               pubkeyPtr(X509_get_pubkey(cert), EVP_PKEY_free);
+
+       TPKP_CHECK_THROW_EXCEPTION(pubkeyPtr,
+               TPKP_E_INVALID_CERT, "Failed to get pubkey from cert.");
+
+       unsigned char *der = nullptr;
+       auto len = i2d_PUBKEY(pubkeyPtr.get(), &der);
+       TPKP_CHECK_THROW_EXCEPTION(len > 0,
+               TPKP_E_INVALID_CERT, "Failed to convert pem pubkey to der.");
+
+       TPKP::RawBuffer pubkeyder(der, der + len);
+       free(der);
+       unsigned char *hashResult = nullptr;
+       TPKP::RawBuffer out;
+       switch (algo) {
+       case TPKP::HashAlgo::SHA1:
+               out.resize(SHA_DIGEST_LENGTH);
+               hashResult = SHA1(pubkeyder.data(), pubkeyder.size(), out.data());
+
+               break;
+
+       default:
+               TPKP_CHECK_THROW_EXCEPTION(false,
+                       TPKP_E_INTERNAL, "Invalid hash algo type in get_pubkey_hash");
+       }
+
+       TPKP_CHECK_THROW_EXCEPTION(hashResult,
+               TPKP_E_FAILED_GET_PUBKEY_HASH, "Failed to get pubkey haso by openssl SHA1.");
+
+       return out;
+}
+
+} // anonymous namespace
+
+
+EXPORT_API
+int tpkp_curl_verify_callback(int preverify_ok, X509_STORE_CTX *x509_ctx)
+{
+       tpkp_e res = TPKP::ExceptionSafe([&]{
+               TPKP_CHECK_THROW_EXCEPTION(preverify_ok != 0,
+                       TPKP_E_INTERNAL, "verify callback already failed before enter tpkp_curl callback");
+
+               auto tid = TPKP::getThreadId();
+               std::string url;
+
+               {
+                       std::lock_guard<std::mutex> lock(s_mutex);
+                       url = s_urlmap[tid];
+               }
+
+               TPKP_CHECK_THROW_EXCEPTION(!url.empty(),
+                       TPKP_E_NO_URL_DATA, "No url for thread id[" << tid << "] in map");
+
+               SLOGD("get url[%s] of thread id[%u]", url.c_str(), tid);
+
+               TPKP::Context ctx(url);
+               if (!ctx.hasPins()) {
+                       SLOGI("Skip. No static pin data for url: %s", url.c_str());
+                       return;
+               }
+
+               auto chain = X509_STORE_CTX_get1_chain(x509_ctx);
+               int num = sk_X509_num(chain);
+               TPKP_CHECK_THROW_EXCEPTION(num != -1,
+                       TPKP_E_INVALID_PEER_CERT_CHAIN,
+                       "Invalid cert chain from x509_ctx in verify callback.");
+
+               for (int i = 0; i < num; i++)
+                       ctx.addPubkeyHash(
+                               TPKP::HashAlgo::SHA1,
+                               getPubkeyHash(sk_X509_value(chain, i), TPKP::HashAlgo::SHA1));
+
+               TPKP_CHECK_THROW_EXCEPTION(ctx.checkPubkeyPins(),
+                       TPKP_E_PUBKEY_MISMATCH, "The pubkey mismatched with pinned data!");
+       });
+
+       return (res == TPKP_E_NONE) ? 1 : 0;
+}
+
+EXPORT_API
+tpkp_e tpkp_curl_set_url_data(CURL *curl)
+{
+       return TPKP::ExceptionSafe([&]{
+               char *url = nullptr;
+               curl_easy_getinfo(curl, CURLINFO_EFFECTIVE_URL, &url);
+
+               auto tid = TPKP::getThreadId();
+
+               {
+                       std::lock_guard<std::mutex> lock(s_mutex);
+                       s_urlmap[tid] = url;
+               }
+
+               SLOGD("set url[%s] of thread id[%u]", url, tid);
+       });
+}
+
+EXPORT_API
+tpkp_e tpkp_curl_set_verify(CURL *curl, SSL_CTX *ssl_ctx)
+{
+       SSL_CTX_set_verify(ssl_ctx, SSL_VERIFY_PEER, tpkp_curl_verify_callback);
+       return tpkp_curl_set_url_data(curl);
+}
+
+EXPORT_API
+CURLcode tpkp_curl_ssl_ctx_callback(CURL *curl, void *ssl_ctx, void *)
+{
+       return err_tpkp_to_curle(tpkp_curl_set_verify(curl, (SSL_CTX *)ssl_ctx));
+}
+
+EXPORT_API
+void tpkp_curl_cleanup(void)
+{
+       tpkp_e res = TPKP::ExceptionSafe([&]{
+               auto tid = TPKP::getThreadId();
+
+               {
+                       std::lock_guard<std::mutex> lock(s_mutex);
+                       s_urlmap.erase(tid);
+               }
+
+               SLOGD("cleanup url data for thread id[%u]", tid);
+       });
+
+       (void) res;
+}
+
+EXPORT_API
+void tpkp_curl_cleanup_all(void)
+{
+       s_urlmap.clear();
+}
diff --git a/src/gnutls/CMakeLists.txt b/src/gnutls/CMakeLists.txt
new file mode 100644 (file)
index 0000000..adf0e92
--- /dev/null
@@ -0,0 +1,52 @@
+# Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
+#
+#    Licensed under the Apache License, Version 2.0 (the "License");
+#    you may not use this file except in compliance with the License.
+#    You may obtain a copy of the License at
+#
+#        http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS,
+#    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#    See the License for the specific language governing permissions and
+#    limitations under the License.
+#
+# @file     CMakeLists.txt
+# @author   Kyungwook Tak (k.tak@samsung.com)
+# @brief    TPKP gnutls lib makefile
+#
+PKG_CHECK_MODULES(TPKP_GNUTLS_DEP
+       REQUIRED
+       gnutls
+       dlog
+       )
+
+INCLUDE_DIRECTORIES(
+       SYSTEM
+       include
+       ${PROJECT_SOURCE_DIR}/src/common/include # common library interface header
+       ${TPKP_GNUTLS_DEP_INCLUDE_DIRS}
+       )
+
+SET(TPKP_GNUTLS_SRCS
+       tpkp_gnutls.cpp
+       )
+
+ADD_LIBRARY(${TARGET_TPKP_GNUTLS_LIB} SHARED ${TPKP_GNUTLS_SRCS})
+
+SET_TARGET_PROPERTIES(${TARGET_TPKP_GNUTLS_LIB}
+       PROPERTIES
+               COMPILE_FLAGS "-D_GNU_SOURCE -fPIC -fvisibility=hidden"
+               SOVERSION ${SO_VERSION}
+               VERSION ${VERSION}
+       )
+
+TARGET_LINK_LIBRARIES(${TARGET_TPKP_GNUTLS_LIB}
+       ${TARGET_TPKP_COMMON_LIB}
+       ${TPKP_GNUTLS_DEP_LIBRARIES}
+       )
+
+INSTALL(TARGETS ${TARGET_TPKP_GNUTLS_LIB} DESTINATION ${LIB_INSTALL_DIR})
+
+INSTALL(FILES include/tpkp_gnutls.h DESTINATION ${INCLUDEDIR}/tpkp/gnutls)
diff --git a/src/gnutls/include/tpkp_gnutls.h b/src/gnutls/include/tpkp_gnutls.h
new file mode 100644 (file)
index 0000000..fd412d2
--- /dev/null
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ *    Licensed under the Apache License, Version 2.0 (the "License");
+ *    you may not use this file except in compliance with the License.
+ *    You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *    Unless required by applicable law or agreed to in writing, software
+ *    distributed under the License is distributed on an "AS IS" BASIS,
+ *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *    See the License for the specific language governing permissions and
+ *    limitations under the License.
+ */
+/*
+ * @file        tpkp_gnutls.h
+ * @author      Kyungwook Tak (k.tak@samsung.com)
+ * @version     1.0
+ * @brief       Tizen Https Public Key Pinning interface for gnutls.
+ */
+#ifndef TPKP_GNUTLS_H_
+#define TPKP_GNUTLS_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <gnutls/gnutls.h>
+#include <tpkp_error.h>
+
+/*
+ *  @brief   gnutls_certificate_verify_function of verifying pubkey pinning
+ *
+ *  @remarks set by gnutls_certificate_verify_function().
+ *
+ *
+ */
+int tpkp_gnutls_verify_callback(gnutls_session_t session);
+
+tpkp_e tpkp_gnutls_set_url_data(const char *url);
+
+void tpkp_gnutls_cleanup(void);
+
+void tpkp_gnutls_cleanup_all(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* TPKP_GNUTLS_H_ */
diff --git a/src/gnutls/tpkp_gnutls.cpp b/src/gnutls/tpkp_gnutls.cpp
new file mode 100644 (file)
index 0000000..b4ef9f4
--- /dev/null
@@ -0,0 +1,229 @@
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ *    Licensed under the Apache License, Version 2.0 (the "License");
+ *    you may not use this file except in compliance with the License.
+ *    You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *    Unless required by applicable law or agreed to in writing, software
+ *    distributed under the License is distributed on an "AS IS" BASIS,
+ *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *    See the License for the specific language governing permissions and
+ *    limitations under the License.
+ */
+/*
+ * @file        tpkp_gnutls.cpp
+ * @author      Kyungwook Tak (k.tak@samsung.com)
+ * @version     1.0
+ * @brief       Tizen Https Public Key Pinning implementation for gnutls.
+ */
+#include <string>
+#include <memory>
+#include <map>
+#include <mutex>
+
+#include <gnutls/gnutls.h>
+#include <gnutls/abstract.h>
+#include <gnutls/x509.h>
+
+#include "tpkp_common.h"
+#include "tpkp_gnutls.h"
+
+namespace {
+
+std::map<pid_t, std::string> s_urlmap;
+std::mutex s_mutex;
+
+inline int err_tpkp_to_gnutlse(tpkp_e err) noexcept
+{
+       switch (err) {
+       case TPKP_E_NONE:                    return GNUTLS_E_SUCCESS;
+       case TPKP_E_MEMORY:                  return GNUTLS_E_MEMORY_ERROR;
+       case TPKP_E_INVALID_URL:             return GNUTLS_E_INVALID_SESSION;
+       case TPKP_E_NO_URL_DATA:             return GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE;
+       case TPKP_E_PUBKEY_MISMATCH:         return GNUTLS_E_CERTIFICATE_KEY_MISMATCH;
+       case TPKP_E_INVALID_CERT:
+       case TPKP_E_INVALID_PEER_CERT_CHAIN:
+       case TPKP_E_FAILED_GET_PUBKEY_HASH:  return GNUTLS_E_PK_SIG_VERIFY_FAILED;
+       case TPKP_E_STD_EXCEPTION:
+       case TPKP_E_INTERNAL:
+       default:                             return GNUTLS_E_INTERNAL_ERROR;
+       }
+}
+
+TPKP::RawBuffer getPubkeyHash(gnutls_x509_crt_t cert, TPKP::HashAlgo algo)
+{
+       std::unique_ptr<gnutls_pubkey_t, void(*)(gnutls_pubkey_t *)>
+               pubkeyPtr(new gnutls_pubkey_t, [](gnutls_pubkey_t *ptr)->void
+                       {
+                               if (ptr != nullptr)
+                                       gnutls_pubkey_deinit(*ptr);
+                       });
+
+       int ret = gnutls_pubkey_init(pubkeyPtr.get());
+       TPKP_CHECK_THROW_EXCEPTION(ret == GNUTLS_E_SUCCESS,
+               TPKP_E_INTERNAL,
+               "Failed to gnutls_pubkey_init. gnutls ret: " << ret);
+
+       ret = gnutls_pubkey_import_x509(*pubkeyPtr, cert, 0);
+       TPKP_CHECK_THROW_EXCEPTION(ret == GNUTLS_E_SUCCESS,
+               TPKP_E_INVALID_CERT,
+               "Failed to gnutls_pubkey_import_x509. gnutls ret: " << ret);
+
+       size_t len = 0;
+       ret = gnutls_pubkey_export(*pubkeyPtr, GNUTLS_X509_FMT_DER, nullptr, &len);
+       TPKP_CHECK_THROW_EXCEPTION(
+               (ret == GNUTLS_E_SHORT_MEMORY_BUFFER || ret == GNUTLS_E_SUCCESS) && len != 0,
+               TPKP_E_INVALID_CERT,
+               "Failed to gnutls_pubkey_export for getting size. gnutls ret: "
+                       << ret << " desc: " << gnutls_strerror(ret) << " size: " << len);
+
+       TPKP::RawBuffer derbuf(len, 0x00);
+       ret = gnutls_pubkey_export(*pubkeyPtr, GNUTLS_X509_FMT_DER, derbuf.data(), &len);
+       TPKP_CHECK_THROW_EXCEPTION(ret == GNUTLS_E_SUCCESS && len == derbuf.size(),
+               TPKP_E_INVALID_CERT,
+               "Failed to gnutls_pubkey_export. gnutls ret: "
+                       << ret << " desc: " << gnutls_strerror(ret));
+
+       gnutls_datum_t pubkeyder = {
+               derbuf.data(),
+               static_cast<unsigned int>(derbuf.size())
+       };
+
+       auto gnutlsHashAlgo = GNUTLS_DIG_SHA1; /* default hash alog */
+       TPKP::RawBuffer out;
+       switch (algo) {
+       case TPKP::HashAlgo::SHA1:
+               out.resize(TPKP::typeCast(TPKP::HashSize::SHA1), 0x00);
+               len = out.size();
+               gnutlsHashAlgo = GNUTLS_DIG_SHA1;
+               break;
+
+       default:
+               TPKP_CHECK_THROW_EXCEPTION(
+                       false,
+                       TPKP_E_INTERNAL,
+                       "Invalid hash algo type in getPubkeyHash.");
+       }
+
+       ret = gnutls_fingerprint(gnutlsHashAlgo, &pubkeyder, out.data(), &len);
+       TPKP_CHECK_THROW_EXCEPTION(ret == GNUTLS_E_SUCCESS && len == out.size(),
+               TPKP_E_FAILED_GET_PUBKEY_HASH,
+               "Failed to gnutls_fingerprint. gnutls ret: "
+                       << ret << " desc: " << gnutls_strerror(ret));
+
+       return out;
+}
+
+}
+
+EXPORT_API
+int tpkp_gnutls_verify_callback(gnutls_session_t session)
+{
+       tpkp_e res = TPKP::ExceptionSafe([&]{
+               gnutls_certificate_type_t type = gnutls_certificate_type_get(session);
+               if (type != GNUTLS_CRT_X509) {
+                       //
+                       // TODO: what should we do if it's not x509 type cert?
+                       // for now, just return 0 which means verification success
+                       //
+                       SLOGW("Certificate type of session isn't X509. skipt for now...");
+                       return;
+               }
+
+               unsigned int listSize = 0;
+               const gnutls_datum_t *certChain = gnutls_certificate_get_peers(session, &listSize);
+               TPKP_CHECK_THROW_EXCEPTION(certChain != nullptr && listSize != 0,
+                       TPKP_E_INVALID_PEER_CERT_CHAIN,
+                       "no certificate from peer!");
+
+               auto tid = TPKP::getThreadId();
+               std::string url;
+
+               {
+                       std::lock_guard<std::mutex> lock(s_mutex);
+                       url = s_urlmap[tid];
+               }
+
+               TPKP_CHECK_THROW_EXCEPTION(
+                       !url.empty(),
+                       TPKP_E_NO_URL_DATA,
+                       "No url of thread id[" << tid << "]");
+
+               SLOGD("get url[%s] of thread id[%u]", url.c_str(), tid);
+
+               TPKP::Context ctx(url);
+               if (!ctx.hasPins()) {
+                       SLOGI("Skip. No static pin data for url: %s", url.c_str());
+                       return;
+               }
+
+               for (unsigned int i = 0; i < listSize; i++) {
+                       std::unique_ptr<gnutls_x509_crt_t, void(*)(gnutls_x509_crt_t *)>
+                               crtPtr(new gnutls_x509_crt_t, [](gnutls_x509_crt_t *ptr)->void
+                                       {
+                                               if (ptr != nullptr)
+                                                       gnutls_x509_crt_deinit(*ptr);
+                                       });
+
+                       TPKP_CHECK_THROW_EXCEPTION(
+                               gnutls_x509_crt_init(crtPtr.get()) == GNUTLS_E_SUCCESS,
+                               TPKP_E_INTERNAL,
+                               "Failed to gnutls_x509_crt_init.");
+
+                       TPKP_CHECK_THROW_EXCEPTION(
+                               gnutls_x509_crt_import(*crtPtr, certChain++, GNUTLS_X509_FMT_DER) >= 0,
+                               TPKP_E_INVALID_CERT,
+                               "Failed to import DER cert to gnutls crt");
+
+                       ctx.addPubkeyHash(
+                               TPKP::HashAlgo::SHA1,
+                               getPubkeyHash(*crtPtr, TPKP::HashAlgo::SHA1));
+               }
+
+               TPKP_CHECK_THROW_EXCEPTION(ctx.checkPubkeyPins(),
+                       TPKP_E_PUBKEY_MISMATCH, "THe pubkey mismatched with pinned data!");
+       });
+
+       return err_tpkp_to_gnutlse(res);
+}
+
+EXPORT_API
+tpkp_e tpkp_gnutls_set_url_data(const char *url)
+{
+       return TPKP::ExceptionSafe([&]{
+               pid_t tid = TPKP::getThreadId();
+
+               {
+                       std::lock_guard<std::mutex> lock(s_mutex);
+                       s_urlmap[tid] = url;
+               }
+
+               SLOGD("set url[%s] of thread id[%u]", url, tid);
+       });
+}
+
+EXPORT_API
+void tpkp_gnutls_cleanup(void)
+{
+       tpkp_e res = TPKP::ExceptionSafe([&]{
+               auto tid = TPKP::getThreadId();
+
+               {
+                       std::lock_guard<std::mutex> lock(s_mutex);
+                       s_urlmap.erase(tid);
+               }
+
+               SLOGD("cleanup url data from thread id[%u]", tid);
+       });
+
+       (void) res;
+}
+
+EXPORT_API
+void tpkp_gnutls_cleanup_all(void)
+{
+       s_urlmap.clear();
+}
diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt
new file mode 100644 (file)
index 0000000..a9c32d3
--- /dev/null
@@ -0,0 +1,53 @@
+# Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
+#
+#    Licensed under the Apache License, Version 2.0 (the "License");
+#    you may not use this file except in compliance with the License.
+#    You may obtain a copy of the License at
+#
+#        http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS,
+#    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#    See the License for the specific language governing permissions and
+#    limitations under the License.
+#
+# @file     CMakeLists.txt
+# @author   Kyungwook Tak (k.tak@samsung.com)
+# @brief    TPKP test makefile
+#
+ADD_DEFINITIONS("-DBOOST_TEST_DYN_LINK")
+
+PKG_CHECK_MODULES(TEST_TPKP_DEP
+       REQUIRED
+       openssl
+       libcurl
+       gnutls
+       )
+
+INCLUDE_DIRECTORIES(
+       SYSTEM
+       ${TEST_TPKP_DEP_INCLUDE_DIRS}
+       ${PROJECT_SOURCE_DIR}/src/curl/include   # tpkp API header
+       ${PROJECT_SOURCE_DIR}/src/gnutls/include # tpkp API header
+       ${PROJECT_SOURCE_DIR}/src/common/include # tpkp error header in common
+       )
+
+SET(TEST_SRCS
+       colour_log_formatter.cpp
+       colors.cpp
+       main.cpp
+       gnutls_test.cpp
+       curl_test.cpp
+       )
+
+ADD_EXECUTABLE(${TARGET_TPKP_TEST} ${TEST_SRCS})
+
+TARGET_LINK_LIBRARIES(${TARGET_TPKP_TEST}
+       ${TEST_TPKP_DEP_LIBRARIES}
+       ${TARGET_TPKP_GNUTLS_LIB}
+       ${TARGET_TPKP_CURL_LIB}
+       boost_unit_test_framework
+       )
+
+INSTALL(TARGETS ${TARGET_TPKP_TEST} DESTINATION bin)
diff --git a/test/colors.cpp b/test/colors.cpp
new file mode 100644 (file)
index 0000000..9e06956
--- /dev/null
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ *    Licensed under the Apache License, Version 2.0 (the "License");
+ *    you may not use this file except in compliance with the License.
+ *    You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *    Unless required by applicable law or agreed to in writing, software
+ *    distributed under the License is distributed on an "AS IS" BASIS,
+ *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *    See the License for the specific language governing permissions and
+ *    limitations under the License.
+ */
+/*
+ * @file        colors.cpp
+ * @author      Lukasz Wrzosek (l.wrzosek@samsung.com)
+ * @version     1.0
+ * @brief       Some constants with definition of colors for Console
+ *              and html output
+ */
+#include <stddef.h>
+#include "colors.h"
+
+namespace TPKP {
+namespace Colors {
+namespace Text {
+const char* BOLD_GREEN_BEGIN = "\033[1;32m";
+const char* BOLD_GREEN_END = "\033[m";
+const char* RED_BEGIN = "\033[0;31m";
+const char* RED_END = "\033[m";
+const char* PURPLE_BEGIN = "\033[0;35m";
+const char* PURPLE_END = "\033[m";
+const char* GREEN_BEGIN = "\033[0;32m";
+const char* GREEN_END = "\033[m";
+const char* CYAN_BEGIN = "\033[0;36m";
+const char* CYAN_END = "\033[m";
+const char* BOLD_RED_BEGIN = "\033[1;31m";
+const char* BOLD_RED_END = "\033[m";
+const char* BOLD_YELLOW_BEGIN = "\033[1;33m";
+const char* BOLD_YELLOW_END = "\033[m";
+const char* BOLD_GOLD_BEGIN = "\033[0;33m";
+const char* BOLD_GOLD_END = "\033[m";
+const char* BOLD_WHITE_BEGIN = "\033[1;37m";
+const char* BOLD_WHITE_END = "\033[m";
+const char* COLOR_END = "\033[m";
+} //namespace Text
+} //namespace Colors
+} //namespace TPKP
diff --git a/test/colors.h b/test/colors.h
new file mode 100644 (file)
index 0000000..437e4a6
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ *    Licensed under the Apache License, Version 2.0 (the "License");
+ *    you may not use this file except in compliance with the License.
+ *    You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *    Unless required by applicable law or agreed to in writing, software
+ *    distributed under the License is distributed on an "AS IS" BASIS,
+ *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *    See the License for the specific language governing permissions and
+ *    limitations under the License.
+ */
+/*
+ * @file        colors.h
+ * @author      Lukasz Wrzosek (l.wrzosek@samsung.com)
+ * @version     1.0
+ * @brief       Some constants with definition of colors for Console
+ *              and html output
+ */
+#pragma once
+
+namespace TPKP {
+namespace Colors {
+namespace Text {
+extern const char* BOLD_GREEN_BEGIN;
+extern const char* BOLD_GREEN_END;
+extern const char* PURPLE_BEGIN;
+extern const char* PURPLE_END;
+extern const char* RED_BEGIN;
+extern const char* RED_END;
+extern const char* GREEN_BEGIN;
+extern const char* GREEN_END;
+extern const char* CYAN_BEGIN;
+extern const char* CYAN_END;
+extern const char* BOLD_RED_BEGIN;
+extern const char* BOLD_RED_END;
+extern const char* BOLD_YELLOW_BEGIN;
+extern const char* BOLD_YELLOW_END;
+extern const char* BOLD_GOLD_BEGIN;
+extern const char* BOLD_GOLD_END;
+extern const char* BOLD_WHITE_BEGIN;
+extern const char* BOLD_WHITE_END;
+extern const char* COLOR_END;
+} //namespace Text
+} //namespace Colors
+} //namespace TPKP
diff --git a/test/colour_log_formatter.cpp b/test/colour_log_formatter.cpp
new file mode 100644 (file)
index 0000000..08ef10d
--- /dev/null
@@ -0,0 +1,244 @@
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ *    Licensed under the Apache License, Version 2.0 (the "License");
+ *    you may not use this file except in compliance with the License.
+ *    You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *    Unless required by applicable law or agreed to in writing, software
+ *    distributed under the License is distributed on an "AS IS" BASIS,
+ *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *    See the License for the specific language governing permissions and
+ *    limitations under the License.
+ */
+/*
+ * @file        colour_log_formatter.cpp
+ * @author      Zofia Abramowska (z.abramowska@samsung.com)
+ * @version     1.0
+ * @brief       color formatter for test output.
+ */
+#include <boost/test/unit_test_suite_impl.hpp>
+#include <boost/test/framework.hpp>
+#include <boost/test/utils/basic_cstring/io.hpp>
+#include <boost/test/utils/lazy_ostream.hpp>
+#include <boost/version.hpp>
+
+#include <iostream>
+#include <string>
+
+#include "colors.h"
+#include "colour_log_formatter.h"
+
+using namespace boost::unit_test;
+namespace TPKP {
+
+namespace {
+
+const_string
+test_phase_identifier()
+{
+    return framework::is_initialized()
+            ? const_string( framework::current_test_case().p_name.get() )
+            : BOOST_TEST_L( "Test setup" );
+}
+
+const_string
+get_basename(const const_string &file_name) {
+    return basename(file_name.begin());
+}
+
+std::string
+get_basename(const std::string &file_name) {
+    return basename(file_name.c_str());
+}
+
+} // local namespace
+
+//____________________________________________________________________________//
+
+void
+colour_log_formatter::log_start(
+        std::ostream& output,
+        counter_t test_cases_amount )
+{
+    if( test_cases_amount > 0 )
+        output  << "Running " << test_cases_amount << " test "
+                << (test_cases_amount > 1 ? "cases" : "case") << "...\n";
+}
+
+//____________________________________________________________________________//
+
+void
+colour_log_formatter::log_finish( std::ostream& ostr )
+{
+    ostr.flush();
+}
+
+//____________________________________________________________________________//
+
+void
+colour_log_formatter::log_build_info( std::ostream& output )
+{
+    output  << "Platform: " << BOOST_PLATFORM            << '\n'
+            << "Compiler: " << BOOST_COMPILER            << '\n'
+            << "STL     : " << BOOST_STDLIB              << '\n'
+            << "Boost   : " << BOOST_VERSION/100000      << "."
+                            << BOOST_VERSION/100 % 1000  << "."
+                            << BOOST_VERSION % 100       << std::endl;
+}
+
+//____________________________________________________________________________//
+
+void
+colour_log_formatter::test_unit_start(
+        std::ostream& output,
+        test_unit const& tu )
+{
+    if (tu.p_type_name->find(const_string("suite")) == 0) {
+        output << "Starting test " << tu.p_type_name << " \"" << tu.p_name << "\"" << std::endl;
+    } else {
+        output << "Running test " << tu.p_type_name << " \"" << tu.p_name << "\"" << std::endl;
+    }
+}
+
+//____________________________________________________________________________//
+
+void
+colour_log_formatter::test_unit_finish(
+        std::ostream& output,
+        test_unit const& tu,
+        unsigned long elapsed )
+{
+    if (tu.p_type_name->find(const_string("suite")) == 0) {
+        output << "Finished test " << tu.p_type_name << " \"" << tu.p_name << "\""<< std::endl;
+        return;
+    }
+    std::string color = TPKP::Colors::Text::GREEN_BEGIN;
+    std::string status = "OK";
+    if (m_isTestCaseFailed) {
+        color = TPKP::Colors::Text::RED_BEGIN;
+        status = "FAIL";
+    }
+    output << "\t" << "[   " << color << status << TPKP::Colors::Text::COLOR_END << "   ]";
+
+
+    output << ", " << TPKP::Colors::Text::CYAN_BEGIN << "time: ";
+    if( elapsed > 0 ) {
+        if( elapsed % 1000 == 0 )
+            output << elapsed/1000 << "ms";
+        else
+            output << elapsed << "mks";
+    } else {
+        output << "N/A";
+    }
+
+    output << TPKP::Colors::Text::COLOR_END << std::endl;
+    m_isTestCaseFailed = false;
+}
+
+//____________________________________________________________________________//
+
+void
+colour_log_formatter::test_unit_skipped(
+        std::ostream& output,
+        test_unit const& tu )
+{
+    output  << "Test " << tu.p_type_name << " \"" << tu.p_name << "\"" << "is skipped" << std::endl;
+}
+
+//____________________________________________________________________________//
+
+void
+colour_log_formatter::log_exception(
+        std::ostream& output,
+        log_checkpoint_data const& checkpoint_data,
+        boost::execution_exception const& ex )
+{
+    boost::execution_exception::location const& loc = ex.where();
+    output << '\t' << TPKP::Colors::Text::BOLD_YELLOW_BEGIN << get_basename(loc.m_file_name)
+            << '(' << loc.m_line_num << "), ";
+
+    output << "fatal error in \""
+            << (loc.m_function.is_empty() ? test_phase_identifier() : loc.m_function ) << "\": ";
+
+    output << TPKP::Colors::Text::COLOR_END << ex.what();
+
+    if( !checkpoint_data.m_file_name.is_empty() ) {
+        output << '\n';
+        output << "\tlast checkpoint : " << get_basename(checkpoint_data.m_file_name)
+                << '(' << checkpoint_data.m_line_num << ")";
+        if( !checkpoint_data.m_message.empty() )
+            output << ": " << checkpoint_data.m_message;
+    }
+
+    output << std::endl;
+    m_isTestCaseFailed = true;
+}
+
+//____________________________________________________________________________//
+
+void
+colour_log_formatter::log_entry_start(
+        std::ostream& output,
+        log_entry_data const& entry_data,
+        log_entry_types let )
+{
+    switch( let ) {
+        case BOOST_UTL_ET_INFO:
+            output << '\t' << entry_data.m_file_name << '(' << entry_data.m_line_num << "), ";
+            output << "info: ";
+            break;
+        case BOOST_UTL_ET_MESSAGE:
+            break;
+        case BOOST_UTL_ET_WARNING:
+            output << '\t' << get_basename(entry_data.m_file_name) << '(' << entry_data.m_line_num << "), ";
+            output << "warning in \"" << test_phase_identifier() << "\": ";
+            break;
+        case BOOST_UTL_ET_ERROR:
+            output << '\t' << TPKP::Colors::Text::BOLD_YELLOW_BEGIN <<  get_basename(entry_data.m_file_name)
+                << '(' << entry_data.m_line_num << "), ";
+            output << "error in \"" << test_phase_identifier() << "\": ";
+            m_isTestCaseFailed = true;
+            break;
+        case BOOST_UTL_ET_FATAL_ERROR:
+            output << '\t' << TPKP::Colors::Text::BOLD_YELLOW_BEGIN <<  get_basename(entry_data.m_file_name)
+                << '(' << entry_data.m_line_num << "),  ";
+            output <<  " fatal error in \"" << test_phase_identifier() << "\": ";
+            m_isTestCaseFailed = true;
+            break;
+    }
+    output << TPKP::Colors::Text::COLOR_END;
+}
+
+//____________________________________________________________________________//
+
+void
+colour_log_formatter::log_entry_value(
+        std::ostream& output,
+        const_string value )
+{
+    output << value;
+}
+
+//____________________________________________________________________________//
+
+void
+colour_log_formatter::log_entry_value(
+        std::ostream& output,
+        lazy_ostream const& value )
+{
+    output << value;
+}
+
+//____________________________________________________________________________//
+
+void
+colour_log_formatter::log_entry_finish(
+        std::ostream& output )
+{
+    output << std::endl;
+}
+
+} // namespace TPKP
diff --git a/test/colour_log_formatter.h b/test/colour_log_formatter.h
new file mode 100644 (file)
index 0000000..b36838a
--- /dev/null
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ *    Licensed under the Apache License, Version 2.0 (the "License");
+ *    you may not use this file except in compliance with the License.
+ *    You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *    Unless required by applicable law or agreed to in writing, software
+ *    distributed under the License is distributed on an "AS IS" BASIS,
+ *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *    See the License for the specific language governing permissions and
+ *    limitations under the License.
+ */
+/*
+ * @file        colour_log_formatter.h
+ * @author      Zofia Abramowska (z.abramowska@samsung.com)
+ * @version     1.0
+ * @brief       color formatter for test output.
+ */
+#pragma once
+
+#include <boost/test/unit_test_log_formatter.hpp>
+
+namespace TPKP {
+class colour_log_formatter : public boost::unit_test::unit_test_log_formatter {
+public:
+    // Formatter interface
+    colour_log_formatter() : m_isTestCaseFailed(false) {}
+    void    log_start(
+                std::ostream&,
+                boost::unit_test::counter_t test_cases_amount );
+    void    log_finish( std::ostream& );
+    void    log_build_info( std::ostream& );
+
+    void    test_unit_start(
+                std::ostream&,
+                boost::unit_test::test_unit const& tu );
+    void    test_unit_finish(
+                std::ostream&,
+                boost::unit_test::test_unit const& tu,
+                unsigned long elapsed );
+    void    test_unit_skipped(
+                std::ostream&,
+                boost::unit_test::test_unit const& tu );
+
+    void    log_exception(
+                std::ostream&,
+                boost::unit_test::log_checkpoint_data const&,
+                boost::execution_exception const& ex );
+
+    void    log_entry_start(
+                std::ostream&,
+                boost::unit_test::log_entry_data const&,
+                log_entry_types let );
+    void    log_entry_value(
+                std::ostream&,
+                boost::unit_test::const_string value );
+    void    log_entry_value(
+                std::ostream&,
+                boost::unit_test::lazy_ostream const& value );
+    void    log_entry_finish( std::ostream& );
+private:
+    bool m_isTestCaseFailed;
+};
+
+}
diff --git a/test/curl_test.cpp b/test/curl_test.cpp
new file mode 100644 (file)
index 0000000..2c52c49
--- /dev/null
@@ -0,0 +1,435 @@
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ *    Licensed under the Apache License, Version 2.0 (the "License");
+ *    you may not use this file except in compliance with the License.
+ *    You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *    Unless required by applicable law or agreed to in writing, software
+ *    distributed under the License is distributed on an "AS IS" BASIS,
+ *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *    See the License for the specific language governing permissions and
+ *    limitations under the License.
+ */
+/*
+ * @file        libcurl_sample.cpp
+ * @author      Kyungwook Tak (k.tak@samsung.com)
+ * @version     1.0
+ * @brief       tpkp_curl unit test.
+ */
+#include <iostream>
+#include <string>
+#include <openssl/ssl.h>
+#include <openssl/sha.h>
+#include <openssl/x509.h>
+#include <curl/curl.h>
+#include <thread>
+#include <vector>
+
+#include <tpkp_curl.h>
+
+#include <boost/test/unit_test.hpp>
+
+static std::vector<std::string> UrlList = {
+       "https://www.google.com",
+       "https://www.facebook.com",
+       "https://www.twitter.com",
+       "https://www.dropbox.com",
+       "https://www.spideroak.com",
+       "https://www.youtube.com",
+       "https://thehackernews.com" /* no static pinned data */
+};
+
+const std::string targetUrl        = "https://WwW.GooGle.cO.Kr";
+const std::string targetInvalidUrl = "https://WwW.GooGle.cO.Kr11143343jiuj::";
+
+int verify_callback(int preverify_ok, X509_STORE_CTX *x509_ctx)
+{
+       if (preverify_ok == 0)
+               return 0;
+
+       /*
+        *  Do something which isn't related with HPKP here
+        *  And update value to preverify_ok of validation result
+        */
+
+       /* call tpkp_verify_callback as additional step */
+       return tpkp_curl_verify_callback(preverify_ok, x509_ctx);
+}
+
+static CURLcode ssl_ctx_callback_set_verify(CURL *curl, void *ssl_ctx, void *userptr)
+{
+       (void)userptr;
+
+       SSL_CTX_set_verify((SSL_CTX *)ssl_ctx, SSL_VERIFY_PEER, verify_callback);
+       tpkp_e res = tpkp_curl_set_url_data(curl);
+       if (res != TPKP_E_NONE)
+               return CURLE_FAILED_INIT;
+
+       return CURLE_OK;
+}
+
+static CURLcode ssl_ctx_callback_not_set_verify(CURL *curl, void *ssl_ctx, void *userptr)
+{
+       (void)userptr;
+
+       tpkp_e res = tpkp_curl_set_verify(curl, (SSL_CTX *)ssl_ctx);
+       if (res != TPKP_E_NONE)
+               return CURLE_FAILED_INIT;
+
+       return CURLE_OK;
+}
+
+static CURL *makeLocalDefaultHandle(std::string url)
+{
+       CURL *handle = curl_easy_init();
+
+       BOOST_REQUIRE_MESSAGE(
+               curl_easy_setopt(handle, CURLOPT_URL, url.c_str()) == CURLE_OK,
+               "Failed to set opt url : " << targetUrl);
+
+       BOOST_REQUIRE_MESSAGE(
+               curl_easy_setopt(handle, CURLOPT_VERBOSE, 0L) == CURLE_OK,
+               "Failed to set opt verbose");
+
+       BOOST_REQUIRE_MESSAGE(
+               curl_easy_setopt(handle, CURLOPT_SSL_VERIFYPEER, 1L) == CURLE_OK,
+               "Failed to set opt verify peer");
+
+       BOOST_REQUIRE_MESSAGE(
+               curl_easy_setopt(handle, CURLOPT_SSL_VERIFYHOST, 2L) == CURLE_OK,
+               "Failed to set opt verify host");
+
+       BOOST_REQUIRE_MESSAGE(
+               curl_easy_setopt(handle, CURLOPT_FOLLOWLOCATION, 1L) == CURLE_OK,
+               "Failed to set opt follow location");
+
+       BOOST_REQUIRE_MESSAGE(
+               curl_easy_setopt(handle, CURLOPT_NOBODY, 1L) == CURLE_OK,
+               "Failed to set opt no body");
+
+       return handle;
+}
+
+static CURL *makeDefaultHandle(std::string url)
+{
+       curl_global_init(CURL_GLOBAL_DEFAULT);
+
+       return makeLocalDefaultHandle(url);
+}
+
+static void performWithUrl(std::string url)
+{
+       CURL *curl = makeLocalDefaultHandle(url);
+       CURLcode res;
+
+       res = curl_easy_setopt(curl, CURLOPT_SSL_CTX_FUNCTION, tpkp_curl_ssl_ctx_callback);
+       BOOST_REQUIRE_MESSAGE(
+               res == CURLE_OK,
+               "Failed to set opt ssl ctx function. code: " << curl_easy_strerror(res));
+
+       res = curl_easy_perform(curl);
+       BOOST_REQUIRE_MESSAGE(
+               res == CURLE_OK,
+               "Failed to perform curl: " << curl_easy_strerror(res));
+
+       tpkp_curl_cleanup();
+       curl_easy_cleanup(curl);
+}
+
+BOOST_AUTO_TEST_SUITE(TPKP_CURL_TEST)
+
+BOOST_AUTO_TEST_CASE(T00101_posivite_notusing_ssl_ctx_func_opt)
+{
+       CURL *curl = makeDefaultHandle(targetUrl);
+       CURLcode res;
+
+       res = curl_easy_setopt(curl, CURLOPT_SSL_CTX_FUNCTION, tpkp_curl_ssl_ctx_callback);
+       BOOST_REQUIRE_MESSAGE(
+               res == CURLE_OK,
+               "Failed to set opt ssl ctx function. code: " << curl_easy_strerror(res));
+
+       res = curl_easy_perform(curl);
+       BOOST_REQUIRE_MESSAGE(
+               res == CURLE_OK,
+               "Failed to perform curl: " << curl_easy_strerror(res));
+
+       tpkp_curl_cleanup();
+       curl_easy_cleanup(curl);
+       curl_global_cleanup();
+}
+
+BOOST_AUTO_TEST_CASE(T00102_posivite_using_ssl_ctx_func_opt_notusing_ssl_ctx_set_verify)
+{
+       CURL *curl = makeDefaultHandle(targetUrl);
+       CURLcode res;
+
+       res = curl_easy_setopt(curl, CURLOPT_SSL_CTX_FUNCTION, ssl_ctx_callback_not_set_verify);
+       BOOST_REQUIRE_MESSAGE(
+               res == CURLE_OK,
+               "Failed to set opt ssl ctx function. code: " << curl_easy_strerror(res));
+
+       res = curl_easy_perform(curl);
+       BOOST_REQUIRE_MESSAGE(
+               res == CURLE_OK,
+               "Failed to perform curl: " << curl_easy_strerror(res));
+
+       tpkp_curl_cleanup();
+       curl_easy_cleanup(curl);
+       curl_global_cleanup();
+}
+
+BOOST_AUTO_TEST_CASE(T00103_posivite_using_ssl_ctx_func_opt_using_ssl_ctx_set_verify)
+{
+       CURL *curl = makeDefaultHandle(targetUrl);
+       CURLcode res;
+
+       res = curl_easy_setopt(curl, CURLOPT_SSL_CTX_FUNCTION, ssl_ctx_callback_set_verify);
+       BOOST_REQUIRE_MESSAGE(
+               res == CURLE_OK,
+               "Failed to set opt ssl ctx function. code: " << curl_easy_strerror(res));
+
+       res = curl_easy_perform(curl);
+       BOOST_REQUIRE_MESSAGE(
+               res == CURLE_OK,
+               "Failed to perform curl: " << curl_easy_strerror(res));
+
+       tpkp_curl_cleanup();
+       curl_easy_cleanup(curl);
+       curl_global_cleanup();
+}
+
+BOOST_AUTO_TEST_CASE(T00104_negative_invalid_url)
+{
+       CURL *curl = makeDefaultHandle(targetInvalidUrl);
+       CURLcode res;
+
+       res = curl_easy_setopt(curl, CURLOPT_SSL_CTX_FUNCTION, ssl_ctx_callback_set_verify);
+       BOOST_REQUIRE_MESSAGE(
+               res == CURLE_OK,
+               "Failed to set opt ssl ctx function. code: " << curl_easy_strerror(res));
+
+       res = curl_easy_perform(curl);
+       BOOST_REQUIRE_MESSAGE(
+               res != CURLE_OK,
+               "Shouldnot success perform curl: " << curl_easy_strerror(res));
+       std::cout << "code: " << res << " description: " << curl_easy_strerror(res) << std::endl;
+
+       tpkp_curl_cleanup();
+       curl_easy_cleanup(curl);
+       curl_global_cleanup();
+}
+
+BOOST_AUTO_TEST_CASE(T00105_positive_facebook_with_https)
+{
+       CURL *curl = makeDefaultHandle("https://www.facebook.com");
+       CURLcode res;
+
+       res = curl_easy_setopt(curl, CURLOPT_SSL_CTX_FUNCTION, tpkp_curl_ssl_ctx_callback);
+       BOOST_REQUIRE_MESSAGE(
+               res == CURLE_OK,
+               "Failed to set opt ssl ctx function. code: " << curl_easy_strerror(res));
+
+       res = curl_easy_perform(curl);
+       BOOST_REQUIRE_MESSAGE(
+               res == CURLE_OK,
+               "Failed to perform curl: " << curl_easy_strerror(res));
+
+       tpkp_curl_cleanup();
+       curl_easy_cleanup(curl);
+       curl_global_cleanup();
+}
+
+BOOST_AUTO_TEST_CASE(T00106_positive_facebook_with_http)
+{
+       CURL *curl = makeDefaultHandle("http://www.facebook.com");
+       CURLcode res;
+
+       res = curl_easy_setopt(curl, CURLOPT_SSL_CTX_FUNCTION, tpkp_curl_ssl_ctx_callback);
+       BOOST_REQUIRE_MESSAGE(
+               res == CURLE_OK,
+               "Failed to set opt ssl ctx function. code: " << curl_easy_strerror(res));
+
+       res = curl_easy_perform(curl);
+       BOOST_REQUIRE_MESSAGE(
+               res == CURLE_OK,
+               "Failed to perform curl: " << curl_easy_strerror(res));
+
+       tpkp_curl_cleanup();
+       curl_easy_cleanup(curl);
+       curl_global_cleanup();
+}
+
+BOOST_AUTO_TEST_CASE(T00107_positive_facebook_with_hostname)
+{
+       CURL *curl = makeDefaultHandle("www.facebook.com");
+       CURLcode res;
+
+       res = curl_easy_setopt(curl, CURLOPT_SSL_CTX_FUNCTION, tpkp_curl_ssl_ctx_callback);
+       BOOST_REQUIRE_MESSAGE(
+               res == CURLE_OK,
+               "Failed to set opt ssl ctx function. code: " << curl_easy_strerror(res));
+
+       res = curl_easy_perform(curl);
+       BOOST_REQUIRE_MESSAGE(
+               res == CURLE_OK,
+               "Failed to perform curl: " << curl_easy_strerror(res));
+
+       tpkp_curl_cleanup();
+       curl_easy_cleanup(curl);
+       curl_global_cleanup();
+}
+
+BOOST_AUTO_TEST_CASE(T00108_positive_twitter_with_https)
+{
+       CURL *curl = makeDefaultHandle("https://www.twitter.com");
+       CURLcode res;
+
+       res = curl_easy_setopt(curl, CURLOPT_SSL_CTX_FUNCTION, tpkp_curl_ssl_ctx_callback);
+       BOOST_REQUIRE_MESSAGE(
+               res == CURLE_OK,
+               "Failed to set opt ssl ctx function. code: " << curl_easy_strerror(res));
+
+       res = curl_easy_perform(curl);
+       BOOST_REQUIRE_MESSAGE(
+               res == CURLE_OK,
+               "Failed to perform curl: " << curl_easy_strerror(res));
+
+       tpkp_curl_cleanup();
+       curl_easy_cleanup(curl);
+       curl_global_cleanup();
+}
+
+BOOST_AUTO_TEST_CASE(T00109_positive_dropbox_with_https)
+{
+       CURL *curl = makeDefaultHandle("https://www.dropbox.com");
+       CURLcode res;
+
+       res = curl_easy_setopt(curl, CURLOPT_SSL_CTX_FUNCTION, tpkp_curl_ssl_ctx_callback);
+       BOOST_REQUIRE_MESSAGE(
+               res == CURLE_OK,
+               "Failed to set opt ssl ctx function. code: " << curl_easy_strerror(res));
+
+       res = curl_easy_perform(curl);
+       BOOST_REQUIRE_MESSAGE(
+               res == CURLE_OK,
+               "Failed to perform curl: " << curl_easy_strerror(res));
+
+       tpkp_curl_cleanup();
+       curl_easy_cleanup(curl);
+       curl_global_cleanup();
+}
+
+BOOST_AUTO_TEST_CASE(T00110_positive_spideroak_with_https)
+{
+       CURL *curl = makeDefaultHandle("https://www.spideroak.com");
+       CURLcode res;
+
+       res = curl_easy_setopt(curl, CURLOPT_SSL_CTX_FUNCTION, tpkp_curl_ssl_ctx_callback);
+       BOOST_REQUIRE_MESSAGE(
+               res == CURLE_OK,
+               "Failed to set opt ssl ctx function. code: " << curl_easy_strerror(res));
+
+       res = curl_easy_perform(curl);
+       BOOST_REQUIRE_MESSAGE(
+               res == CURLE_OK,
+               "Failed to perform curl: " << curl_easy_strerror(res));
+
+       tpkp_curl_cleanup();
+       curl_easy_cleanup(curl);
+       curl_global_cleanup();
+}
+
+BOOST_AUTO_TEST_CASE(T00111_positive_https_but_no_pinned_data_youtube)
+{
+       CURL *curl = makeDefaultHandle("https://www.youtube.com");
+       CURLcode res;
+
+       res = curl_easy_setopt(curl, CURLOPT_SSL_CTX_FUNCTION, tpkp_curl_ssl_ctx_callback);
+       BOOST_REQUIRE_MESSAGE(
+               res == CURLE_OK,
+               "Failed to set opt ssl ctx function. code: " << curl_easy_strerror(res));
+
+       res = curl_easy_perform(curl);
+       BOOST_REQUIRE_MESSAGE(
+               res == CURLE_OK,
+               "Failed to perform curl: " << curl_easy_strerror(res));
+
+       tpkp_curl_cleanup();
+       curl_easy_cleanup(curl);
+       curl_global_cleanup();
+}
+
+BOOST_AUTO_TEST_CASE(T00112_positive_https_but_no_pinned_data_hackernews)
+{
+       CURL *curl = makeDefaultHandle("https://thehackernews.com");
+       CURLcode res;
+
+       res = curl_easy_setopt(curl, CURLOPT_SSL_CTX_FUNCTION, tpkp_curl_ssl_ctx_callback);
+       BOOST_REQUIRE_MESSAGE(
+               res == CURLE_OK,
+               "Failed to set opt ssl ctx function. code: " << curl_easy_strerror(res));
+
+       res = curl_easy_perform(curl);
+       BOOST_REQUIRE_MESSAGE(
+               res == CURLE_OK,
+               "Failed to perform curl: " << curl_easy_strerror(res));
+
+       tpkp_curl_cleanup();
+       curl_easy_cleanup(curl);
+       curl_global_cleanup();
+
+}
+
+BOOST_AUTO_TEST_CASE(T00113_positive_threads)
+{
+       curl_global_init(CURL_GLOBAL_DEFAULT);
+
+       std::vector<std::thread> threads;
+
+       for (const auto &url : UrlList)
+               threads.emplace_back(performWithUrl, url);
+
+       for (auto &t : threads)
+               t.join();
+
+       curl_global_cleanup();
+}
+
+BOOST_AUTO_TEST_CASE(T00114_positive_threads_2times)
+{
+       curl_global_init(CURL_GLOBAL_DEFAULT);
+
+       std::vector<std::thread> threads;
+
+       for (int i = 0; i < 2; i++) {
+               for (const auto &url : UrlList)
+                       threads.emplace_back(performWithUrl, url);
+       }
+
+       for (auto &t : threads)
+               t.join();
+
+       curl_global_cleanup();
+}
+
+BOOST_AUTO_TEST_CASE(T00113_positive_threads_3times)
+{
+       curl_global_init(CURL_GLOBAL_DEFAULT);
+
+       std::vector<std::thread> threads;
+
+       for (int i = 0; i < 3; i++) {
+               for (const auto &url : UrlList)
+                       threads.emplace_back(performWithUrl, url);
+       }
+
+       for (auto &t : threads)
+               t.join();
+
+       curl_global_cleanup();
+}
+
+BOOST_AUTO_TEST_SUITE_END()
diff --git a/test/gnutls_test.cpp b/test/gnutls_test.cpp
new file mode 100644 (file)
index 0000000..3c3399f
--- /dev/null
@@ -0,0 +1,188 @@
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ *    Licensed under the Apache License, Version 2.0 (the "License");
+ *    you may not use this file except in compliance with the License.
+ *    You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *    Unless required by applicable law or agreed to in writing, software
+ *    distributed under the License is distributed on an "AS IS" BASIS,
+ *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *    See the License for the specific language governing permissions and
+ *    limitations under the License.
+ */
+/*
+ * @file        gnutls_sample.cpp
+ * @author      Kyungwook Tak (k.tak@samsung.com)
+ * @version     1.0
+ * @brief       tpkp_gnutls unit test.
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+#include <iostream>
+
+#include <gnutls/gnutls.h>
+
+#include <tpkp_gnutls.h>
+
+#include <boost/test/unit_test.hpp>
+
+#define SHA1_LENGTH 20
+
+namespace {
+const std::string targetUrl = "https://WwW.GooGle.cO.Kr";
+
+const char certStr[] =
+       "-----BEGIN CERTIFICATE-----\n"
+       "MIIDfTCCAuagAwIBAgIDErvmMA0GCSqGSIb3DQEBBQUAME4xCzAJBgNVBAYTAlVT\n"
+       "MRAwDgYDVQQKEwdFcXVpZmF4MS0wKwYDVQQLEyRFcXVpZmF4IFNlY3VyZSBDZXJ0\n"
+       "aWZpY2F0ZSBBdXRob3JpdHkwHhcNMDIwNTIxMDQwMDAwWhcNMTgwODIxMDQwMDAw\n"
+       "WjBCMQswCQYDVQQGEwJVUzEWMBQGA1UEChMNR2VvVHJ1c3QgSW5jLjEbMBkGA1UE\n"
+       "AxMSR2VvVHJ1c3QgR2xvYmFsIENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB\n"
+       "CgKCAQEA2swYYzD99BcjGlZ+W988bDjkcbd4kdS8odhM+KhDtgPpTSEHCIjaWC9m\n"
+       "OSm9BXiLnTjoBbdqfnGk5sRgprDvgOSJKA+eJdbtg/OtppHHmMlCGDUUna2YRpIu\n"
+       "T8rxh0PBFpVXLVDviS2Aelet8u5fa9IAjbkU+BQVNdnARqN7csiRv8lVK83Qlz6c\n"
+       "JmTM386DGXHKTubU1XupGc1V3sjs0l44U+VcT4wt/lAjNvxm5suOpDkZALeVAjmR\n"
+       "Cw7+OC7RHQWa9k0+bw8HHa8sHo9gOeL6NlMTOdReJivbPagUvTLrGAMoUgRx5asz\n"
+       "PeE4uwc2hGKceeoWMPRfwCvocWvk+QIDAQABo4HwMIHtMB8GA1UdIwQYMBaAFEjm\n"
+       "aPkr0rKV10fYIyAQTzOYkJ/UMB0GA1UdDgQWBBTAephojYn7qwVkDBF9qn1luMrM\n"
+       "TjAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjA6BgNVHR8EMzAxMC+g\n"
+       "LaArhilodHRwOi8vY3JsLmdlb3RydXN0LmNvbS9jcmxzL3NlY3VyZWNhLmNybDBO\n"
+       "BgNVHSAERzBFMEMGBFUdIAAwOzA5BggrBgEFBQcCARYtaHR0cHM6Ly93d3cuZ2Vv\n"
+       "dHJ1c3QuY29tL3Jlc291cmNlcy9yZXBvc2l0b3J5MA0GCSqGSIb3DQEBBQUAA4GB\n"
+       "AHbhEm5OSxYShjAGsoEIz/AIx8dxfmbuwu3UOx//8PDITtZDOLC5MH0Y0FWDomrL\n"
+       "NhGc6Ehmo21/uBPUR/6LWlxz/K7ZGzIZOKuXNBSqltLroxwUCEm2u+WR74M26x1W\n"
+       "b8ravHNjkOR/ez4iyz0H7V84dJzjA1BOoa+Y7mHyhD8S\n"
+       "-----END CERTIFICATE-----\n";
+
+const char sha1hash[] = // kSPKIHash_GeoTrustGlobal
+           "\xc0\x7a\x98\x68\x8d\x89\xfb\xab\x05\x64"
+           "\x0c\x11\x7d\xaa\x7d\x65\xb8\xca\xcc\x4e";
+
+int tcp_connect(const char *ip, int port)
+{
+       int sock;
+       struct sockaddr_in server_addr;
+
+       BOOST_REQUIRE_MESSAGE(
+               (sock = socket(PF_INET, SOCK_STREAM, 0)) >= 0,
+               "Cannot create socket!");
+
+       memset(&server_addr, 0x00, sizeof(server_addr));
+       server_addr.sin_family = AF_INET;
+       server_addr.sin_addr.s_addr = inet_addr(ip);
+       server_addr.sin_port = htons(port);
+
+       BOOST_REQUIRE_MESSAGE(
+               (connect(sock, (struct sockaddr *)&server_addr, sizeof(server_addr))) >= 0,
+               "Cannot connect to sock:" << sock);
+
+       return sock;
+}
+
+void tcp_close(int sd)
+{
+       close(sd);
+}
+
+typedef struct _GIOGnuTLSChannel GIOGnuTLSChannel;
+
+struct _GIOGnuTLSChannel {
+    int fd;
+};
+
+gnutls_session_t makeDefaultSession(void)
+{
+       int ret = gnutls_global_init();
+       BOOST_REQUIRE_MESSAGE(
+               ret == GNUTLS_E_SUCCESS,
+               "Failed to gnutls global init: " << gnutls_strerror(ret));
+
+       gnutls_session_t session;
+       ret = gnutls_init(&session, GNUTLS_CLIENT);
+       BOOST_REQUIRE_MESSAGE(
+               ret == GNUTLS_E_SUCCESS,
+               "Failed to gnutls init session: " << gnutls_strerror(ret));
+
+       ret = gnutls_set_default_priority(session);
+       BOOST_REQUIRE_MESSAGE(
+               ret == GNUTLS_E_SUCCESS,
+               "Failed to set default priority on session: " << gnutls_strerror(ret));
+
+       return session;
+}
+
+inline gnutls_certificate_credentials_t makeDefaultCred(gnutls_certificate_verify_function *verify_callback)
+{
+       gnutls_certificate_credentials_t cred;
+
+       int ret = gnutls_certificate_allocate_credentials(&cred);
+       BOOST_REQUIRE_MESSAGE(
+               ret == GNUTLS_E_SUCCESS,
+               "Failed to gnutls_certificate_allocate_credentials: " << gnutls_strerror(ret));
+
+       ret = gnutls_certificate_set_x509_trust_file(cred, "/etc/ssl/ca-bundle.pem", GNUTLS_X509_FMT_PEM);
+       BOOST_REQUIRE_MESSAGE(
+               ret > 0,
+               "Failed to gnutls_certificate_set_x509_trust_file ret: " << ret);
+       std::cout << "x509 trust file loaded. cert num: " << ret << std::endl;
+
+       gnutls_certificate_set_verify_function(cred, verify_callback);
+
+       return cred;
+}
+
+}
+
+BOOST_AUTO_TEST_SUITE(TPKP_GNUTLS_TEST)
+
+#define MAX_BUF 1024
+#define MSG "GET / HTTP/1.0\r\n\r\n"
+BOOST_AUTO_TEST_CASE(T00101_positive)
+{
+       gnutls_certificate_credentials_t cred = makeDefaultCred(&tpkp_gnutls_verify_callback);
+       gnutls_session_t session = makeDefaultSession();
+
+       int ret = gnutls_credentials_set(session, GNUTLS_CRD_CERTIFICATE, cred);
+       BOOST_REQUIRE_MESSAGE(
+               ret == GNUTLS_E_SUCCESS,
+               "Failed to gnutls_credentials_set: " << gnutls_strerror(ret));
+
+       int sd = tcp_connect("216.58.221.36", 443);
+
+       BOOST_REQUIRE_MESSAGE(
+               tpkp_gnutls_set_url_data(targetUrl.c_str()) == TPKP_E_NONE,
+               "Failed to tpkp_gnutls_set_url_data.");
+
+       gnutls_transport_set_int(session, sd);
+       gnutls_handshake_set_timeout(session, GNUTLS_DEFAULT_HANDSHAKE_TIMEOUT);
+
+       do {
+               ret = gnutls_handshake(session);
+       } while (ret != GNUTLS_E_SUCCESS && gnutls_error_is_fatal(ret) == 0);
+
+       BOOST_REQUIRE_MESSAGE(
+               ret == GNUTLS_E_SUCCESS,
+               "Handshake failed: " << gnutls_strerror(ret));
+
+       gnutls_bye(session, GNUTLS_SHUT_RDWR);
+
+    tcp_close(sd);
+
+    gnutls_certificate_free_credentials(cred);
+
+    gnutls_deinit(session);
+    gnutls_global_deinit();
+}
+
+BOOST_AUTO_TEST_SUITE_END()
diff --git a/test/main.cpp b/test/main.cpp
new file mode 100644 (file)
index 0000000..cb9670f
--- /dev/null
@@ -0,0 +1,38 @@
+/*
+ *  Copyright (c) 2000 - 2015 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License
+ */
+/*
+ * @file       main.cpp
+ * @author     Kyungwook Tak (k.tak@samsung.com)
+ * @version    1.0
+ * @brief      pubkey-pinning internal unit test main of boost test framework.
+ */
+#define BOOST_TEST_MODULE TPKP_INTERNAL_TEST
+#include <boost/test/unit_test.hpp>
+#include <boost/test/unit_test_log.hpp>
+#include <boost/test/results_reporter.hpp>
+
+#include "colour_log_formatter.h"
+
+struct TestConfig {
+       TestConfig()
+       {
+               boost::unit_test::unit_test_log.set_threshold_level( boost::unit_test::log_test_units);
+               boost::unit_test::results_reporter::set_level(boost::unit_test::SHORT_REPORT);
+               boost::unit_test::unit_test_log.set_formatter(new TPKP::colour_log_formatter);
+       }
+};
+
+BOOST_GLOBAL_FIXTURE(TestConfig)
diff --git a/tpkp-curl.pc.in b/tpkp-curl.pc.in
new file mode 100644 (file)
index 0000000..abe4669
--- /dev/null
@@ -0,0 +1,9 @@
+libdir=@LIB_INSTALL_DIR@
+includedir=@INCLUDEDIR@
+
+Name: tpkp-curl
+Description: Tizen HPKP for curl
+Version: @VERSION@
+Requires: openssl curl
+Libs: -L${libdir} -ltpkp-curl -ltpkp-common
+Cflags: -I${includedir}/tpkp/curl -I${includedir}/tpkp/common
diff --git a/tpkp-gnutls.pc.in b/tpkp-gnutls.pc.in
new file mode 100644 (file)
index 0000000..86cb9d9
--- /dev/null
@@ -0,0 +1,9 @@
+libdir=@LIB_INSTALL_DIR@
+includedir=@INCLUDEDIR@
+
+Name: tpkp-gnutls
+Description: Tizen HPKP for gnutls
+Version: @VERSION@
+Requires: gnutls
+Libs: -L${libdir} -ltpkp-gnutls -ltpkp-common
+Cflags: -I${includedir}/tpkp/gnutls -I${includedir}/tpkp/common