From 8bc226c258872a551fcf7495b3aecb749bcd2a8c Mon Sep 17 00:00:00 2001 From: Moonchild Date: Fri, 13 Nov 2020 10:09:36 +0000 Subject: [PATCH 1/7] Issue #1391 - Disable DOM Filesystem/dirpicker APIs by default. There don't seem to be any drawbacks to this; tested for the past month disabled and there have been no issues with any sites visited. Adoption seems very low. --- modules/libpref/init/all.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/libpref/init/all.js b/modules/libpref/init/all.js index c672bd894c..9ccd9ad5dd 100644 --- a/modules/libpref/init/all.js +++ b/modules/libpref/init/all.js @@ -5421,8 +5421,8 @@ pref("osfile.reset_worker_delay", 30000); #endif #if !defined(MOZ_WIDGET_ANDROID) -pref("dom.webkitBlink.dirPicker.enabled", true); -pref("dom.webkitBlink.filesystem.enabled", true); +pref("dom.webkitBlink.dirPicker.enabled", false); +pref("dom.webkitBlink.filesystem.enabled", false); #endif #ifdef NIGHTLY_BUILD From 6d5eda301066911d4e9914924cf5707ac574cdf7 Mon Sep 17 00:00:00 2001 From: Moonchild Date: Fri, 13 Nov 2020 13:33:08 +0000 Subject: [PATCH 2/7] Issue #1682 - Remove vibrator DOM interface and support code. Resolves #1682 --- config/system-headers | 1 - dom/base/Navigator.cpp | 193 +----------------- dom/base/Navigator.h | 3 - dom/tests/mochitest/general/mochitest.ini | 1 - .../mochitest/general/test_vibrator.html | 93 --------- dom/webidl/Navigator.webidl | 25 +-- hal/Hal.cpp | 79 ------- hal/Hal.h | 35 ---- hal/fallback/FallbackVibration.cpp | 22 -- hal/moz.build | 5 - hal/sandbox/PHal.ipdl | 3 - hal/sandbox/SandboxHal.cpp | 52 ----- modules/libpref/init/all.js | 4 - testing/web-platform/tests/vibration/OWNERS | 3 - .../tests/vibration/api-is-present.html | 27 --- .../vibration/cancel-when-hidden-manual.html | 38 ---- .../tests/vibration/cancel-with-0-manual.html | 31 --- .../vibration/cancel-with-array-0-manual.html | 33 --- .../cancel-with-empty-array-manual.html | 31 --- .../vibration/cancel-with-new-manual.html | 32 --- testing/web-platform/tests/vibration/idl.html | 23 --- .../tests/vibration/invalid-values.html | 79 ------- .../vibration/pattern-array-extra-manual.html | 27 --- .../tests/vibration/pattern-array-manual.html | 26 --- .../pattern-array-with-0-manual.html | 26 --- .../tests/vibration/silent-ignore.html | 31 --- .../tests/vibration/simple-array-manual.html | 23 --- .../tests/vibration/simple-scalar-manual.html | 25 --- 28 files changed, 4 insertions(+), 967 deletions(-) delete mode 100644 dom/tests/mochitest/general/test_vibrator.html delete mode 100644 hal/fallback/FallbackVibration.cpp delete mode 100644 testing/web-platform/tests/vibration/OWNERS delete mode 100644 testing/web-platform/tests/vibration/api-is-present.html delete mode 100644 testing/web-platform/tests/vibration/cancel-when-hidden-manual.html delete mode 100644 testing/web-platform/tests/vibration/cancel-with-0-manual.html delete mode 100644 testing/web-platform/tests/vibration/cancel-with-array-0-manual.html delete mode 100644 testing/web-platform/tests/vibration/cancel-with-empty-array-manual.html delete mode 100644 testing/web-platform/tests/vibration/cancel-with-new-manual.html delete mode 100644 testing/web-platform/tests/vibration/idl.html delete mode 100644 testing/web-platform/tests/vibration/invalid-values.html delete mode 100644 testing/web-platform/tests/vibration/pattern-array-extra-manual.html delete mode 100644 testing/web-platform/tests/vibration/pattern-array-manual.html delete mode 100644 testing/web-platform/tests/vibration/pattern-array-with-0-manual.html delete mode 100644 testing/web-platform/tests/vibration/silent-ignore.html delete mode 100644 testing/web-platform/tests/vibration/simple-array-manual.html delete mode 100644 testing/web-platform/tests/vibration/simple-scalar-manual.html diff --git a/config/system-headers b/config/system-headers index 3685d6d1c3..0156444284 100644 --- a/config/system-headers +++ b/config/system-headers @@ -526,7 +526,6 @@ hardware/lights.h hardware/power.h hardware_legacy/power.h hardware_legacy/uevent.h -hardware_legacy/vibrator.h #endif HIToolbox/HIToolbox.h hlink.h diff --git a/dom/base/Navigator.cpp b/dom/base/Navigator.cpp index 26fb16e4cd..c0580c3590 100644 --- a/dom/base/Navigator.cpp +++ b/dom/base/Navigator.cpp @@ -97,11 +97,6 @@ namespace mozilla { namespace dom { -static bool sVibratorEnabled = false; -static uint32_t sMaxVibrateMS = 0; -static uint32_t sMaxVibrateListLen = 0; -static const char* kVibrationPermissionType = "vibration"; - static void AddPermission(nsIPrincipal* aPrincipal, const char* aType, uint32_t aPermission, uint32_t aExpireType, int64_t aExpireTime) @@ -152,12 +147,7 @@ GetPermission(nsIPrincipal* aPrincipal, const char* aType) void Navigator::Init() { - Preferences::AddBoolVarCache(&sVibratorEnabled, - "dom.vibrator.enabled", true); - Preferences::AddUintVarCache(&sMaxVibrateMS, - "dom.vibrator.max_vibrate_ms", 10000); - Preferences::AddUintVarCache(&sMaxVibrateListLen, - "dom.vibrator.max_vibrate_list_len", 128); + // Add any Preferences::Add*VarCache(&sPref, "pref", default) here if needed. } Navigator::Navigator(nsPIDOMWindowInner* aWindow) @@ -705,82 +695,6 @@ Navigator::RefreshMIMEArray() } } -namespace { - -class VibrateWindowListener : public nsIDOMEventListener -{ -public: - VibrateWindowListener(nsPIDOMWindowInner* aWindow, nsIDocument* aDocument) - { - mWindow = do_GetWeakReference(aWindow); - mDocument = do_GetWeakReference(aDocument); - - NS_NAMED_LITERAL_STRING(visibilitychange, "visibilitychange"); - aDocument->AddSystemEventListener(visibilitychange, - this, /* listener */ - true, /* use capture */ - false /* wants untrusted */); - } - - void RemoveListener(); - - NS_DECL_ISUPPORTS - NS_DECL_NSIDOMEVENTLISTENER - -private: - virtual ~VibrateWindowListener() - { - } - - nsWeakPtr mWindow; - nsWeakPtr mDocument; -}; - -NS_IMPL_ISUPPORTS(VibrateWindowListener, nsIDOMEventListener) - -StaticRefPtr gVibrateWindowListener; - -static bool -MayVibrate(nsIDocument* doc) { - // Hidden documents cannot start or stop a vibration. - return (doc && !doc->Hidden()); -} - -NS_IMETHODIMP -VibrateWindowListener::HandleEvent(nsIDOMEvent* aEvent) -{ - nsCOMPtr doc = - do_QueryInterface(aEvent->InternalDOMEvent()->GetTarget()); - - if (!MayVibrate(doc)) { - // It's important that we call CancelVibrate(), not Vibrate() with an - // empty list, because Vibrate() will fail if we're no longer focused, but - // CancelVibrate() will succeed, so long as nobody else has started a new - // vibration pattern. - nsCOMPtr window = do_QueryReferent(mWindow); - hal::CancelVibrate(window); - RemoveListener(); - gVibrateWindowListener = nullptr; - // Careful: The line above might have deleted |this|! - } - - return NS_OK; -} - -void -VibrateWindowListener::RemoveListener() -{ - nsCOMPtr target = do_QueryReferent(mDocument); - if (!target) { - return; - } - NS_NAMED_LITERAL_STRING(visibilitychange, "visibilitychange"); - target->RemoveSystemEventListener(visibilitychange, this, - true /* use capture */); -} - -} // namespace - void Navigator::AddIdleObserver(MozIdleObserver& aIdleObserver, ErrorResult& aRv) { @@ -809,111 +723,6 @@ Navigator::RemoveIdleObserver(MozIdleObserver& aIdleObserver, ErrorResult& aRv) } } -void -Navigator::SetVibrationPermission(bool aPermitted, bool aPersistent) -{ - MOZ_ASSERT(NS_IsMainThread()); - - nsTArray pattern; - pattern.SwapElements(mRequestedVibrationPattern); - - if (!mWindow) { - return; - } - - nsCOMPtr doc = mWindow->GetExtantDoc(); - - if (!MayVibrate(doc)) { - return; - } - - if (aPermitted) { - // Add a listener to cancel the vibration if the document becomes hidden, - // and remove the old visibility listener, if there was one. - if (!gVibrateWindowListener) { - // If gVibrateWindowListener is null, this is the first time we've vibrated, - // and we need to register a listener to clear gVibrateWindowListener on - // shutdown. - ClearOnShutdown(&gVibrateWindowListener); - } else { - gVibrateWindowListener->RemoveListener(); - } - gVibrateWindowListener = new VibrateWindowListener(mWindow, doc); - hal::Vibrate(pattern, mWindow); - } - - if (aPersistent) { - AddPermission(doc->NodePrincipal(), kVibrationPermissionType, - aPermitted ? nsIPermissionManager::ALLOW_ACTION : - nsIPermissionManager::DENY_ACTION, - nsIPermissionManager::EXPIRE_SESSION, 0); - } -} - -bool -Navigator::Vibrate(uint32_t aDuration) -{ - AutoTArray pattern; - pattern.AppendElement(aDuration); - return Vibrate(pattern); -} - -bool -Navigator::Vibrate(const nsTArray& aPattern) -{ - MOZ_ASSERT(NS_IsMainThread()); - - if (!mWindow) { - return false; - } - - nsCOMPtr doc = mWindow->GetExtantDoc(); - - if (!MayVibrate(doc)) { - return false; - } - - nsTArray pattern(aPattern); - - if (pattern.Length() > sMaxVibrateListLen) { - pattern.SetLength(sMaxVibrateListLen); - } - - for (size_t i = 0; i < pattern.Length(); ++i) { - pattern[i] = std::min(sMaxVibrateMS, pattern[i]); - } - - // The spec says we check sVibratorEnabled after we've done the sanity - // checking on the pattern. - if (!sVibratorEnabled) { - return true; - } - - mRequestedVibrationPattern.SwapElements(pattern); - uint32_t permission = GetPermission(mWindow, kVibrationPermissionType); - - if (permission == nsIPermissionManager::ALLOW_ACTION || - mRequestedVibrationPattern.IsEmpty() || - (mRequestedVibrationPattern.Length() == 1 && - mRequestedVibrationPattern[0] == 0)) { - // Always allow cancelling vibration and respect session permissions. - SetVibrationPermission(true /* permitted */, false /* persistent */); - return true; - } - - nsCOMPtr obs = services::GetObserverService(); - if (!obs || permission == nsIPermissionManager::DENY_ACTION) { - // Abort without observer service or on denied session permission. - SetVibrationPermission(false /* permitted */, false /* persistent */); - return true; - } - - // Request user permission. - obs->NotifyObservers(ToSupports(this), "Vibration:Request", nullptr); - - return true; -} - //***************************************************************************** // Pointer Events interface //***************************************************************************** diff --git a/dom/base/Navigator.h b/dom/base/Navigator.h index 1e5575c057..df99844ca9 100644 --- a/dom/base/Navigator.h +++ b/dom/base/Navigator.h @@ -149,9 +149,6 @@ public: // NavigatorBinding::ClearCachedUserAgentValue(this); void ClearUserAgentCache(); - bool Vibrate(uint32_t aDuration); - bool Vibrate(const nsTArray& aDuration); - void SetVibrationPermission(bool aPermitted, bool aPersistent); uint32_t MaxTouchPoints(); void GetAppCodeName(nsString& aAppCodeName, ErrorResult& aRv) { diff --git a/dom/tests/mochitest/general/mochitest.ini b/dom/tests/mochitest/general/mochitest.ini index 9f2fad7857..67c35f01a6 100755 --- a/dom/tests/mochitest/general/mochitest.ini +++ b/dom/tests/mochitest/general/mochitest.ini @@ -122,7 +122,6 @@ run-if = e10s [test_storagePermissionsReject.html] [test_storagePermissionsRejectForeign.html] [test_stylesheetPI.html] -[test_vibrator.html] [test_WebKitCSSMatrix.html] [test_windowedhistoryframes.html] [test_windowProperties.html] diff --git a/dom/tests/mochitest/general/test_vibrator.html b/dom/tests/mochitest/general/test_vibrator.html deleted file mode 100644 index 2874c783be..0000000000 --- a/dom/tests/mochitest/general/test_vibrator.html +++ /dev/null @@ -1,93 +0,0 @@ - - - - Test for Vibrator - - - - - - - - - - - - diff --git a/dom/webidl/Navigator.webidl b/dom/webidl/Navigator.webidl index f34429de75..43d53cbac0 100644 --- a/dom/webidl/Navigator.webidl +++ b/dom/webidl/Navigator.webidl @@ -13,9 +13,9 @@ * http://www.w3.org/TR/beacon/#sec-beacon-method * https://html.spec.whatwg.org/#navigatorconcurrenthardware * - * © Copyright 2004-2011 Apple Computer, Inc., Mozilla Foundation, and - * Opera Software ASA. You are granted a license to use, reproduce - * and create derivative works of this document. + * © Copyright 2004-2020 Apple Computer, Inc., Mozilla Foundation, + * Opera Software ASA and Moonchild Productions. You are granted a license to use, + * reproduce and create derivative works of this document. */ // http://www.whatwg.org/specs/web-apps/current-work/#the-navigator-object @@ -124,14 +124,6 @@ interface NavigatorGeolocation { }; Navigator implements NavigatorGeolocation; -// http://www.w3.org/TR/vibration/#vibration-interface -partial interface Navigator { - // We don't support sequences in unions yet - //boolean vibrate ((unsigned long or sequence) pattern); - boolean vibrate(unsigned long duration); - boolean vibrate(sequence pattern); -}; - // http://www.w3.org/TR/pointerevents/#extensions-to-the-navigator-interface partial interface Navigator { [Pref="dom.w3c_pointer_events.enabled"] @@ -140,17 +132,6 @@ partial interface Navigator { // Mozilla-specific extensions -// Chrome-only interface for Vibration API permission handling. -partial interface Navigator { - /* Set permission state to device vibration. - * @param permitted permission state (true for allowing vibration) - * @param persistent make the permission session-persistent - */ - [ChromeOnly] - void setVibrationPermission(boolean permitted, - optional boolean persistent = true); -}; - callback interface MozIdleObserver { // Time is in seconds and is read only when idle observers are added // and removed. diff --git a/hal/Hal.cpp b/hal/Hal.cpp index f0167f5756..88c1fa50bb 100644 --- a/hal/Hal.cpp +++ b/hal/Hal.cpp @@ -94,87 +94,8 @@ WindowIsActive(nsPIDOMWindowInner* aWindow) return !document->Hidden(); } -StaticAutoPtr gLastIDToVibrate; - -void InitLastIDToVibrate() -{ - gLastIDToVibrate = new WindowIdentifier::IDArrayType(); - ClearOnShutdown(&gLastIDToVibrate); -} - } // namespace -void -Vibrate(const nsTArray& pattern, nsPIDOMWindowInner* window) -{ - Vibrate(pattern, WindowIdentifier(window)); -} - -void -Vibrate(const nsTArray& pattern, const WindowIdentifier &id) -{ - AssertMainThread(); - - // Only active windows may start vibrations. If |id| hasn't gone - // through the IPC layer -- that is, if our caller is the outside - // world, not hal_proxy -- check whether the window is active. If - // |id| has gone through IPC, don't check the window's visibility; - // only the window corresponding to the bottommost process has its - // visibility state set correctly. - if (!id.HasTraveledThroughIPC() && !WindowIsActive(id.GetWindow())) { - HAL_LOG("Vibrate: Window is inactive, dropping vibrate."); - return; - } - - if (!InSandbox()) { - if (!gLastIDToVibrate) { - InitLastIDToVibrate(); - } - *gLastIDToVibrate = id.AsArray(); - } - - // Don't forward our ID if we are not in the sandbox, because hal_impl - // doesn't need it, and we don't want it to be tempted to read it. The - // empty identifier will assert if it's used. - PROXY_IF_SANDBOXED(Vibrate(pattern, InSandbox() ? id : WindowIdentifier())); -} - -void -CancelVibrate(nsPIDOMWindowInner* window) -{ - CancelVibrate(WindowIdentifier(window)); -} - -void -CancelVibrate(const WindowIdentifier &id) -{ - AssertMainThread(); - - // Although only active windows may start vibrations, a window may - // cancel its own vibration even if it's no longer active. - // - // After a window is marked as inactive, it sends a CancelVibrate - // request. We want this request to cancel a playing vibration - // started by that window, so we certainly don't want to reject the - // cancellation request because the window is now inactive. - // - // But it could be the case that, after this window became inactive, - // some other window came along and started a vibration. We don't - // want this window's cancellation request to cancel that window's - // actively-playing vibration! - // - // To solve this problem, we keep track of the id of the last window - // to start a vibration, and only accepts cancellation requests from - // the same window. All other cancellation requests are ignored. - - if (InSandbox() || (gLastIDToVibrate && *gLastIDToVibrate == id.AsArray())) { - // Don't forward our ID if we are not in the sandbox, because hal_impl - // doesn't need it, and we don't want it to be tempted to read it. The - // empty identifier will assert if it's used. - PROXY_IF_SANDBOXED(CancelVibrate(InSandbox() ? id : WindowIdentifier())); - } -} - template class ObserversManager { diff --git a/hal/Hal.h b/hal/Hal.h index e2e5717905..ced295ca4c 100644 --- a/hal/Hal.h +++ b/hal/Hal.h @@ -50,41 +50,6 @@ typedef Observer SystemTimezoneChangeObserver; namespace MOZ_HAL_NAMESPACE { -/** - * Turn the default vibrator device on/off per the pattern specified - * by |pattern|. Each element in the pattern is the number of - * milliseconds to turn the vibrator on or off. The first element in - * |pattern| is an "on" element, the next is "off", and so on. - * - * If |pattern| is empty, any in-progress vibration is canceled. - * - * Only an active window within an active tab may call Vibrate; calls - * from inactive windows and windows on inactive tabs do nothing. - * - * If you're calling hal::Vibrate from the outside world, pass an - * nsIDOMWindow* in place of the WindowIdentifier parameter. - * The method with WindowIdentifier will be called automatically. - */ -void Vibrate(const nsTArray& pattern, - nsPIDOMWindowInner* aWindow); -void Vibrate(const nsTArray& pattern, - const hal::WindowIdentifier &id); - -/** - * Cancel a vibration started by the content window identified by - * WindowIdentifier. - * - * If the window was the last window to start a vibration, the - * cancellation request will go through even if the window is not - * active. - * - * As with hal::Vibrate(), if you're calling hal::CancelVibrate from the outside - * world, pass an nsIDOMWindow*. The method with WindowIdentifier will be called - * automatically. - */ -void CancelVibrate(nsPIDOMWindowInner* aWindow); -void CancelVibrate(const hal::WindowIdentifier &id); - /** * Determine whether the device's screen is currently enabled. */ diff --git a/hal/fallback/FallbackVibration.cpp b/hal/fallback/FallbackVibration.cpp deleted file mode 100644 index 57379646da..0000000000 --- a/hal/fallback/FallbackVibration.cpp +++ /dev/null @@ -1,22 +0,0 @@ -/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#include "Hal.h" - -using mozilla::hal::WindowIdentifier; - -namespace mozilla { -namespace hal_impl { - -void -Vibrate(const nsTArray& pattern, const hal::WindowIdentifier &) -{} - -void -CancelVibrate(const hal::WindowIdentifier &) -{} - -} // namespace hal_impl -} // namespace mozilla diff --git a/hal/moz.build b/hal/moz.build index 84c017f089..fefd56fcf1 100644 --- a/hal/moz.build +++ b/hal/moz.build @@ -29,7 +29,6 @@ if CONFIG['OS_TARGET'] == 'Linux': 'fallback/FallbackAlarm.cpp', 'fallback/FallbackScreenConfiguration.cpp', 'fallback/FallbackSensor.cpp', - 'fallback/FallbackVibration.cpp', 'linux/LinuxMemory.cpp', 'linux/LinuxPower.cpp', ] @@ -39,7 +38,6 @@ elif CONFIG['OS_TARGET'] == 'WINNT': 'fallback/FallbackMemory.cpp', 'fallback/FallbackPower.cpp', 'fallback/FallbackScreenConfiguration.cpp', - 'fallback/FallbackVibration.cpp', 'windows/WindowsSensor.cpp', ] elif CONFIG['MOZ_WIDGET_TOOLKIT'] == 'cocoa': @@ -48,7 +46,6 @@ elif CONFIG['MOZ_WIDGET_TOOLKIT'] == 'cocoa': 'fallback/FallbackMemory.cpp', 'fallback/FallbackPower.cpp', 'fallback/FallbackScreenConfiguration.cpp', - 'fallback/FallbackVibration.cpp', ] elif CONFIG['OS_TARGET'] in ('OpenBSD', 'NetBSD', 'FreeBSD', 'DragonFly'): UNIFIED_SOURCES += [ @@ -57,7 +54,6 @@ elif CONFIG['OS_TARGET'] in ('OpenBSD', 'NetBSD', 'FreeBSD', 'DragonFly'): 'fallback/FallbackPower.cpp', 'fallback/FallbackScreenConfiguration.cpp', 'fallback/FallbackSensor.cpp', - 'fallback/FallbackVibration.cpp', ] else: UNIFIED_SOURCES += [ @@ -66,7 +62,6 @@ else: 'fallback/FallbackPower.cpp', 'fallback/FallbackScreenConfiguration.cpp', 'fallback/FallbackSensor.cpp', - 'fallback/FallbackVibration.cpp', ] UNIFIED_SOURCES += [ diff --git a/hal/sandbox/PHal.ipdl b/hal/sandbox/PHal.ipdl index cfd021c104..5fa2b2b971 100644 --- a/hal/sandbox/PHal.ipdl +++ b/hal/sandbox/PHal.ipdl @@ -69,9 +69,6 @@ child: async NotifySystemTimezoneChange(SystemTimezoneChangeInformation aSystemTimezoneChangeInfo); parent: - async Vibrate(uint32_t[] pattern, uint64_t[] id, PBrowser browser); - async CancelVibrate(uint64_t[] id, PBrowser browser); - async EnableNetworkNotifications(); async DisableNetworkNotifications(); sync GetCurrentNetworkInformation() diff --git a/hal/sandbox/SandboxHal.cpp b/hal/sandbox/SandboxHal.cpp index fd84f7c391..9a214f0851 100644 --- a/hal/sandbox/SandboxHal.cpp +++ b/hal/sandbox/SandboxHal.cpp @@ -45,28 +45,6 @@ Hal() return sHal; } -void -Vibrate(const nsTArray& pattern, const WindowIdentifier &id) -{ - HAL_LOG("Vibrate: Sending to parent process."); - - AutoTArray p(pattern); - - WindowIdentifier newID(id); - newID.AppendProcessID(); - Hal()->SendVibrate(p, newID.AsArray(), TabChild::GetFrom(newID.GetWindow())); -} - -void -CancelVibrate(const WindowIdentifier &id) -{ - HAL_LOG("CancelVibrate: Sending to parent process."); - - WindowIdentifier newID(id); - newID.AppendProcessID(); - Hal()->SendCancelVibrate(newID.AsArray(), TabChild::GetFrom(newID.GetWindow())); -} - void EnableNetworkNotifications() { @@ -379,36 +357,6 @@ public: hal::UnregisterSystemTimezoneChangeObserver(this); } - virtual bool - RecvVibrate(InfallibleTArray&& pattern, - InfallibleTArray&& id, - PBrowserParent *browserParent) override - { - // We give all content vibration permission. - // TabParent *tabParent = TabParent::GetFrom(browserParent); - /* xxxkhuey wtf - nsCOMPtr window = - do_QueryInterface(tabParent->GetBrowserDOMWindow()); - */ - WindowIdentifier newID(id, nullptr); - hal::Vibrate(pattern, newID); - return true; - } - - virtual bool - RecvCancelVibrate(InfallibleTArray &&id, - PBrowserParent *browserParent) override - { - //TabParent *tabParent = TabParent::GetFrom(browserParent); - /* XXXkhuey wtf - nsCOMPtr window = - tabParent->GetBrowserDOMWindow(); - */ - WindowIdentifier newID(id, nullptr); - hal::CancelVibrate(newID); - return true; - } - virtual bool RecvEnableNetworkNotifications() override { // We give all content access to this network-status information. diff --git a/modules/libpref/init/all.js b/modules/libpref/init/all.js index 9ccd9ad5dd..8665dc7849 100644 --- a/modules/libpref/init/all.js +++ b/modules/libpref/init/all.js @@ -4746,10 +4746,6 @@ pref("dom.event.handling-user-input-time-limit", 1000); // Whether we should layerize all animated images (if otherwise possible). pref("layout.animated-image-layers.enabled", false); -pref("dom.vibrator.enabled", true); -pref("dom.vibrator.max_vibrate_ms", 10000); -pref("dom.vibrator.max_vibrate_list_len", 128); - // Abort API pref("dom.abortController.enabled", true); diff --git a/testing/web-platform/tests/vibration/OWNERS b/testing/web-platform/tests/vibration/OWNERS deleted file mode 100644 index 4020ed82ef..0000000000 --- a/testing/web-platform/tests/vibration/OWNERS +++ /dev/null @@ -1,3 +0,0 @@ -@dontcallmedom -@zqzhang -@xinliux diff --git a/testing/web-platform/tests/vibration/api-is-present.html b/testing/web-platform/tests/vibration/api-is-present.html deleted file mode 100644 index f5c976dff9..0000000000 --- a/testing/web-platform/tests/vibration/api-is-present.html +++ /dev/null @@ -1,27 +0,0 @@ - - - - - Vibration API: test that the vibrate() method is present (with or without vendor prefix) - - - - - - -

Description

-

- This test checks for the presence of the vibrate() method, taking - vendor prefixes into account. -

-
- - - - - - diff --git a/testing/web-platform/tests/vibration/cancel-when-hidden-manual.html b/testing/web-platform/tests/vibration/cancel-when-hidden-manual.html deleted file mode 100644 index 569970758a..0000000000 --- a/testing/web-platform/tests/vibration/cancel-when-hidden-manual.html +++ /dev/null @@ -1,38 +0,0 @@ - - -Vibration API: cancel ongoing vibrate() when hidden by switching tab/window - - - - - - -

Description

-

- After hitting the button below, your device must vibrate for a short period of time (roughly one - second). If it vibrates for a longer time (roughly five seconds, it should feel somewhat long) then - the test has failed. -

- - - - diff --git a/testing/web-platform/tests/vibration/cancel-with-0-manual.html b/testing/web-platform/tests/vibration/cancel-with-0-manual.html deleted file mode 100644 index 6890d5764a..0000000000 --- a/testing/web-platform/tests/vibration/cancel-with-0-manual.html +++ /dev/null @@ -1,31 +0,0 @@ - - - - - Vibration API: cancel ongoing vibrate() with 0 - - - - - - -

Description

-

- After hitting the button below, your device must vibrate for a short period of time (roughly one - second). If it vibrates for a longer time (roughly five seconds, it should feel somewhat long) then - the test has failed. -

- - - - - diff --git a/testing/web-platform/tests/vibration/cancel-with-array-0-manual.html b/testing/web-platform/tests/vibration/cancel-with-array-0-manual.html deleted file mode 100644 index 60689cc2c3..0000000000 --- a/testing/web-platform/tests/vibration/cancel-with-array-0-manual.html +++ /dev/null @@ -1,33 +0,0 @@ - - -Vibration API: cancel ongoing vibrate() with [0] - - - - - - -

Description

-

- After hitting the button below, your device must vibrate for a short period of time (roughly one - second). If it vibrates for a longer time (roughly five seconds, it should feel somewhat long) then - the test has failed. -

- - - - diff --git a/testing/web-platform/tests/vibration/cancel-with-empty-array-manual.html b/testing/web-platform/tests/vibration/cancel-with-empty-array-manual.html deleted file mode 100644 index 9d4be2b3ad..0000000000 --- a/testing/web-platform/tests/vibration/cancel-with-empty-array-manual.html +++ /dev/null @@ -1,31 +0,0 @@ - - - - - Vibration API: cancel ongoing vibrate() with [] - - - - - - -

Description

-

- After hitting the button below, your device must vibrate for a short period of time (roughly one - second). If it vibrates for a longer time (roughly five seconds, it should feel somewhat long) then - the test has failed. -

- - - - - diff --git a/testing/web-platform/tests/vibration/cancel-with-new-manual.html b/testing/web-platform/tests/vibration/cancel-with-new-manual.html deleted file mode 100644 index 1cd9daf172..0000000000 --- a/testing/web-platform/tests/vibration/cancel-with-new-manual.html +++ /dev/null @@ -1,32 +0,0 @@ - - - - - Vibration API: cancel ongoing vibrate() with a new call to vibrate - - - - - - -

Description

-

- After hitting the button below, your device must vibrate continuously for a short period of time (roughly one - second), then vibrate a series of short bursts. If the initial continuously vibration is longer (roughly five - seconds, it should feel somewhat long) or if there is no series of short vibration bursts then the test has - failed. -

- - - - - diff --git a/testing/web-platform/tests/vibration/idl.html b/testing/web-platform/tests/vibration/idl.html deleted file mode 100644 index 167090cd67..0000000000 --- a/testing/web-platform/tests/vibration/idl.html +++ /dev/null @@ -1,23 +0,0 @@ - - -IDL harness tests for Vibration API - -

Description

-

- This test validates the IDL defined by the Vibration API. -

-

- This test uses idlharness.js -

-
- - - - - diff --git a/testing/web-platform/tests/vibration/invalid-values.html b/testing/web-platform/tests/vibration/invalid-values.html deleted file mode 100644 index a544ac23c7..0000000000 --- a/testing/web-platform/tests/vibration/invalid-values.html +++ /dev/null @@ -1,79 +0,0 @@ - - -Vibration API: vibrate(invalid) - - - -

Description

-

- This test checks the vibrate() method with invalid parameter, - taking vendor prefixes into account. -

-
- - - - - diff --git a/testing/web-platform/tests/vibration/pattern-array-extra-manual.html b/testing/web-platform/tests/vibration/pattern-array-extra-manual.html deleted file mode 100644 index 3f5ccf386f..0000000000 --- a/testing/web-platform/tests/vibration/pattern-array-extra-manual.html +++ /dev/null @@ -1,27 +0,0 @@ - - - - - Vibration API: test a pattern array parameter to vibrate() with an extra (even) item - - - - - - -

Description

-

- After hitting the button below, your device must vibrate three times for one second, separated - by one second intervals. -

- - - - - diff --git a/testing/web-platform/tests/vibration/pattern-array-manual.html b/testing/web-platform/tests/vibration/pattern-array-manual.html deleted file mode 100644 index 43674bf8c5..0000000000 --- a/testing/web-platform/tests/vibration/pattern-array-manual.html +++ /dev/null @@ -1,26 +0,0 @@ - - - - - Vibration API: test a pattern array parameter to vibrate() - - - - - -

Description

-

- After hitting the button below, your device must vibrate three times for one second, separated - by one second intervals. -

- - - - - diff --git a/testing/web-platform/tests/vibration/pattern-array-with-0-manual.html b/testing/web-platform/tests/vibration/pattern-array-with-0-manual.html deleted file mode 100644 index dff2f1ed7a..0000000000 --- a/testing/web-platform/tests/vibration/pattern-array-with-0-manual.html +++ /dev/null @@ -1,26 +0,0 @@ - - -Vibration API: test a pattern array with 0ms vibration and still to vibrate() - - - - - -

Description

-

- After hitting the button below, your device must vibrate continuously for about two seconds, once. -

- -
- - - diff --git a/testing/web-platform/tests/vibration/silent-ignore.html b/testing/web-platform/tests/vibration/silent-ignore.html deleted file mode 100644 index c7447df51f..0000000000 --- a/testing/web-platform/tests/vibration/silent-ignore.html +++ /dev/null @@ -1,31 +0,0 @@ - - - - - Vibration API: test that calls to vibrate() are silently ignored when the device cannot vibrate - - - - - - -

Description

-

- This test is only useful on devices that do not have vibration capability. - If your device supports vibration, then skip this test. An implementation - supporting this API but running on a device that cannot vibrate must silently ignore the - call (we test that it doesn't throw). -

-
- - - - - - diff --git a/testing/web-platform/tests/vibration/simple-array-manual.html b/testing/web-platform/tests/vibration/simple-array-manual.html deleted file mode 100644 index 4a85bd6ad0..0000000000 --- a/testing/web-platform/tests/vibration/simple-array-manual.html +++ /dev/null @@ -1,23 +0,0 @@ - - - - - Vibration API: test a simple array parameter to vibrate() - - - - -

Description

-

- After hitting the button below, your device must vibrate continuously for about two seconds, once. -

- -
- - - - diff --git a/testing/web-platform/tests/vibration/simple-scalar-manual.html b/testing/web-platform/tests/vibration/simple-scalar-manual.html deleted file mode 100644 index 0c7637bbad..0000000000 --- a/testing/web-platform/tests/vibration/simple-scalar-manual.html +++ /dev/null @@ -1,25 +0,0 @@ - - - - - Vibration API: test a simple scalar parameter to vibrate() - - - - - -

Description

-

- After hitting the button below, your device must vibrate continuously for about two seconds, once. -

- - - - - From 889311cd749cf8ee550533b2dd7a7fbbd446b63b Mon Sep 17 00:00:00 2001 From: Moonchild Date: Fri, 13 Nov 2020 13:57:41 +0000 Subject: [PATCH 3/7] [libjar] Fix inflation logic. This has been broken for 11 years. About time it's fixed. Tag #1683 --- modules/libjar/nsJARInputStream.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/libjar/nsJARInputStream.cpp b/modules/libjar/nsJARInputStream.cpp index 6993dd578f..086c21ab4f 100644 --- a/modules/libjar/nsJARInputStream.cpp +++ b/modules/libjar/nsJARInputStream.cpp @@ -195,7 +195,7 @@ MOZ_WIN_MEM_TRY_BEGIN return ReadDirectory(aBuffer, aCount, aBytesRead); case MODE_INFLATE: - if (mFd) { + if (mZs.total_out < mOutSize) { rv = ContinueInflate(aBuffer, aCount, aBytesRead); } // be aggressive about releasing the file! From 390f3a62728a5cdd59c4711129dfc89e4470d11c Mon Sep 17 00:00:00 2001 From: Moonchild Date: Fri, 13 Nov 2020 15:59:29 +0000 Subject: [PATCH 4/7] Issue #1683 - Update Brotli lib to 1.0.9 --- modules/brotli/README.mozilla | 2 +- modules/brotli/common/constants.c | 15 + modules/brotli/common/constants.h | 136 + modules/brotli/common/context.c | 156 + modules/brotli/common/context.h | 156 +- modules/brotli/common/dictionary.c | 11 +- modules/brotli/common/platform.c | 22 + modules/brotli/common/platform.h | 60 +- modules/brotli/common/transform.c | 62 +- modules/brotli/common/transform.h | 5 + modules/brotli/common/version.h | 4 +- modules/brotli/dec/bit_reader.c | 28 + modules/brotli/dec/bit_reader.h | 74 +- modules/brotli/dec/decode.c | 604 ++-- modules/brotli/dec/huffman.h | 18 +- modules/brotli/dec/prefix.h | 18 - modules/brotli/dec/state.c | 23 +- modules/brotli/dec/state.h | 181 +- modules/brotli/enc/backward_references.c | 15 +- modules/brotli/enc/backward_references.h | 9 +- modules/brotli/enc/backward_references_hq.c | 84 +- modules/brotli/enc/backward_references_hq.h | 19 +- modules/brotli/enc/backward_references_inc.h | 38 +- modules/brotli/enc/block_splitter.c | 6 +- modules/brotli/enc/block_splitter_inc.h | 21 +- modules/brotli/enc/brotli_bit_stream.c | 43 +- modules/brotli/enc/cluster_inc.h | 9 +- modules/brotli/enc/command.c | 28 + modules/brotli/enc/command.h | 24 +- .../brotli/enc/compress_fragment_two_pass.c | 2 +- modules/brotli/enc/dictionary_hash.c | 2926 ++++++++++------- modules/brotli/enc/dictionary_hash.h | 3 +- modules/brotli/enc/encode.c | 143 +- modules/brotli/enc/encoder_dict.c | 5 +- modules/brotli/enc/encoder_dict.h | 4 +- modules/brotli/enc/entropy_encode.c | 2 + modules/brotli/enc/entropy_encode.h | 4 +- modules/brotli/enc/fast_log.c | 105 + modules/brotli/enc/fast_log.h | 121 +- modules/brotli/enc/find_match_length.h | 5 +- modules/brotli/enc/hash.h | 170 +- modules/brotli/enc/hash_composite_inc.h | 113 +- modules/brotli/enc/hash_forgetful_chain_inc.h | 137 +- modules/brotli/enc/hash_longest_match64_inc.h | 100 +- modules/brotli/enc/hash_longest_match_inc.h | 103 +- .../enc/hash_longest_match_quickly_inc.h | 151 +- modules/brotli/enc/hash_rolling_inc.h | 50 +- modules/brotli/enc/hash_to_binary_tree_inc.h | 77 +- modules/brotli/enc/memory.h | 36 +- modules/brotli/enc/metablock.c | 50 +- modules/brotli/enc/metablock_inc.h | 2 +- modules/brotli/enc/params.h | 4 +- modules/brotli/enc/ringbuffer.h | 5 +- modules/brotli/enc/utf8_util.c | 2 +- modules/brotli/enc/write_bits.h | 52 +- modules/brotli/include/brotli/encode.h | 23 +- modules/brotli/include/brotli/port.h | 14 + modules/brotli/moz.build | 5 + modules/brotli/tools/brotli.c | 83 +- modules/brotli/update.sh | 2 +- 60 files changed, 3966 insertions(+), 2404 deletions(-) create mode 100644 modules/brotli/common/constants.c create mode 100644 modules/brotli/common/context.c create mode 100644 modules/brotli/common/platform.c create mode 100644 modules/brotli/enc/command.c create mode 100644 modules/brotli/enc/fast_log.c diff --git a/modules/brotli/README.mozilla b/modules/brotli/README.mozilla index 47520e4535..400393b29a 100644 --- a/modules/brotli/README.mozilla +++ b/modules/brotli/README.mozilla @@ -11,4 +11,4 @@ The in-tree copy is updated by running sh update.sh from within the modules/brotli directory. -Current version: [commit d6d98957ca8ccb1ef45922e978bb10efca0ea541]. +Current version: 1.0.9 Re-release [commit e61745a6b7add50d380cfd7d3883dd6c62fc2c71]. diff --git a/modules/brotli/common/constants.c b/modules/brotli/common/constants.c new file mode 100644 index 0000000000..6bad9f613c --- /dev/null +++ b/modules/brotli/common/constants.c @@ -0,0 +1,15 @@ +/* Copyright 2013 Google Inc. All Rights Reserved. + + Distributed under MIT license. + See file LICENSE for detail or copy at https://opensource.org/licenses/MIT +*/ + +#include "./constants.h" + +const BrotliPrefixCodeRange + _kBrotliPrefixCodeRanges[BROTLI_NUM_BLOCK_LEN_SYMBOLS] = { + {1, 2}, {5, 2}, {9, 2}, {13, 2}, {17, 3}, {25, 3}, + {33, 3}, {41, 3}, {49, 4}, {65, 4}, {81, 4}, {97, 4}, + {113, 5}, {145, 5}, {177, 5}, {209, 5}, {241, 6}, {305, 6}, + {369, 7}, {497, 8}, {753, 9}, {1265, 10}, {2289, 11}, {4337, 12}, + {8433, 13}, {16625, 24}}; diff --git a/modules/brotli/common/constants.h b/modules/brotli/common/constants.h index d1b88d12af..e848195a0d 100644 --- a/modules/brotli/common/constants.h +++ b/modules/brotli/common/constants.h @@ -4,9 +4,18 @@ See file LICENSE for detail or copy at https://opensource.org/licenses/MIT */ +/** + * @file + * Common constants used in decoder and encoder API. + */ + #ifndef BROTLI_COMMON_CONSTANTS_H_ #define BROTLI_COMMON_CONSTANTS_H_ +#include "./platform.h" +#include +#include + /* Specification: 7.3. Encoding of the context map */ #define BROTLI_CONTEXT_MAP_MAX_RLE 16 @@ -29,12 +38,31 @@ #define BROTLI_INITIAL_REPEATED_CODE_LENGTH 8 /* "Large Window Brotli" */ + +/** + * The theoretical maximum number of distance bits specified for large window + * brotli, for 64-bit encoders and decoders. Even when in practice 32-bit + * encoders and decoders only support up to 30 max distance bits, the value is + * set to 62 because it affects the large window brotli file format. + * Specifically, it affects the encoding of simple huffman tree for distances, + * see Specification RFC 7932 chapter 3.4. + */ #define BROTLI_LARGE_MAX_DISTANCE_BITS 62U #define BROTLI_LARGE_MIN_WBITS 10 +/** + * The maximum supported large brotli window bits by the encoder and decoder. + * Large window brotli allows up to 62 bits, however the current encoder and + * decoder, designed for 32-bit integers, only support up to 30 bits maximum. + */ #define BROTLI_LARGE_MAX_WBITS 30 /* Specification: 4. Encoding of distances */ #define BROTLI_NUM_DISTANCE_SHORT_CODES 16 +/** + * Maximal number of "postfix" bits. + * + * Number of "postfix" bits is stored as 2 bits in meta-block header. + */ #define BROTLI_MAX_NPOSTFIX 3 #define BROTLI_MAX_NDIRECT 120 #define BROTLI_MAX_DISTANCE_BITS 24U @@ -45,9 +73,22 @@ #define BROTLI_NUM_DISTANCE_SYMBOLS \ BROTLI_DISTANCE_ALPHABET_SIZE( \ BROTLI_MAX_NDIRECT, BROTLI_MAX_NPOSTFIX, BROTLI_LARGE_MAX_DISTANCE_BITS) + +/* ((1 << 26) - 4) is the maximal distance that can be expressed in RFC 7932 + brotli stream using NPOSTFIX = 0 and NDIRECT = 0. With other NPOSTFIX and + NDIRECT values distances up to ((1 << 29) + 88) could be expressed. */ #define BROTLI_MAX_DISTANCE 0x3FFFFFC + +/* ((1 << 31) - 4) is the safe distance limit. Using this number as a limit + allows safe distance calculation without overflows, given the distance + alphabet size is limited to corresponding size + (see kLargeWindowDistanceCodeLimits). */ #define BROTLI_MAX_ALLOWED_DISTANCE 0x7FFFFFFC + +/* Specification: 4. Encoding of Literal Insertion Lengths and Copy Lengths */ +#define BROTLI_NUM_INS_COPY_CODES 24 + /* 7.1. Context modes and context ID lookup for literals */ /* "context IDs for literals are in the range of 0..63" */ #define BROTLI_LITERAL_CONTEXT_BITS 6 @@ -61,4 +102,99 @@ #define BROTLI_WINDOW_GAP 16 #define BROTLI_MAX_BACKWARD_LIMIT(W) (((size_t)1 << (W)) - BROTLI_WINDOW_GAP) +typedef struct BrotliDistanceCodeLimit { + uint32_t max_alphabet_size; + uint32_t max_distance; +} BrotliDistanceCodeLimit; + +/* This function calculates maximal size of distance alphabet, such that the + distances greater than the given values can not be represented. + + This limits are designed to support fast and safe 32-bit decoders. + "32-bit" means that signed integer values up to ((1 << 31) - 1) could be + safely expressed. + + Brotli distance alphabet symbols do not represent consecutive distance + ranges. Each distance alphabet symbol (excluding direct distances and short + codes), represent interleaved (for NPOSTFIX > 0) range of distances. + A "group" of consecutive (1 << NPOSTFIX) symbols represent non-interleaved + range. Two consecutive groups require the same amount of "extra bits". + + It is important that distance alphabet represents complete "groups". + To avoid complex logic on encoder side about interleaved ranges + it was decided to restrict both sides to complete distance code "groups". + */ +BROTLI_UNUSED_FUNCTION BrotliDistanceCodeLimit BrotliCalculateDistanceCodeLimit( + uint32_t max_distance, uint32_t npostfix, uint32_t ndirect) { + BrotliDistanceCodeLimit result; + /* Marking this function as unused, because not all files + including "constants.h" use it -> compiler warns about that. */ + BROTLI_UNUSED(&BrotliCalculateDistanceCodeLimit); + if (max_distance <= ndirect) { + /* This case never happens / exists only for the sake of completeness. */ + result.max_alphabet_size = max_distance + BROTLI_NUM_DISTANCE_SHORT_CODES; + result.max_distance = max_distance; + return result; + } else { + /* The first prohibited value. */ + uint32_t forbidden_distance = max_distance + 1; + /* Subtract "directly" encoded region. */ + uint32_t offset = forbidden_distance - ndirect - 1; + uint32_t ndistbits = 0; + uint32_t tmp; + uint32_t half; + uint32_t group; + /* Postfix for the last dcode in the group. */ + uint32_t postfix = (1u << npostfix) - 1; + uint32_t extra; + uint32_t start; + /* Remove postfix and "head-start". */ + offset = (offset >> npostfix) + 4; + /* Calculate the number of distance bits. */ + tmp = offset / 2; + /* Poor-man's log2floor, to avoid extra dependencies. */ + while (tmp != 0) {ndistbits++; tmp = tmp >> 1;} + /* One bit is covered with subrange addressing ("half"). */ + ndistbits--; + /* Find subrange. */ + half = (offset >> ndistbits) & 1; + /* Calculate the "group" part of dcode. */ + group = ((ndistbits - 1) << 1) | half; + /* Calculated "group" covers the prohibited distance value. */ + if (group == 0) { + /* This case is added for correctness; does not occur for limit > 128. */ + result.max_alphabet_size = ndirect + BROTLI_NUM_DISTANCE_SHORT_CODES; + result.max_distance = ndirect; + return result; + } + /* Decrement "group", so it is the last permitted "group". */ + group--; + /* After group was decremented, ndistbits and half must be recalculated. */ + ndistbits = (group >> 1) + 1; + /* The last available distance in the subrange has all extra bits set. */ + extra = (1u << ndistbits) - 1; + /* Calculate region start. NB: ndistbits >= 1. */ + start = (1u << (ndistbits + 1)) - 4; + /* Move to subregion. */ + start += (group & 1) << ndistbits; + /* Calculate the alphabet size. */ + result.max_alphabet_size = ((group << npostfix) | postfix) + ndirect + + BROTLI_NUM_DISTANCE_SHORT_CODES + 1; + /* Calculate the maximal distance representable by alphabet. */ + result.max_distance = ((start + extra) << npostfix) + postfix + ndirect + 1; + return result; + } +} + +/* Represents the range of values belonging to a prefix code: + [offset, offset + 2^nbits) */ +typedef struct { + uint16_t offset; + uint8_t nbits; +} BrotliPrefixCodeRange; + +/* "Soft-private", it is exported, but not "advertised" as API. */ +BROTLI_COMMON_API extern const BrotliPrefixCodeRange + _kBrotliPrefixCodeRanges[BROTLI_NUM_BLOCK_LEN_SYMBOLS]; + #endif /* BROTLI_COMMON_CONSTANTS_H_ */ diff --git a/modules/brotli/common/context.c b/modules/brotli/common/context.c new file mode 100644 index 0000000000..2c2dceba9b --- /dev/null +++ b/modules/brotli/common/context.c @@ -0,0 +1,156 @@ +#include "./context.h" + +#include + +/* Common context lookup table for all context modes. */ +const uint8_t _kBrotliContextLookupTable[2048] = { + /* CONTEXT_LSB6, last byte. */ + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, + 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, + 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, + 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, + 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, + 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, + 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, + 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, + 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, + 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, + 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, + 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, + 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, + + /* CONTEXT_LSB6, second last byte, */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + + /* CONTEXT_MSB6, last byte. */ + 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, + 4, 4, 4, 4, 5, 5, 5, 5, 6, 6, 6, 6, 7, 7, 7, 7, + 8, 8, 8, 8, 9, 9, 9, 9, 10, 10, 10, 10, 11, 11, 11, 11, + 12, 12, 12, 12, 13, 13, 13, 13, 14, 14, 14, 14, 15, 15, 15, 15, + 16, 16, 16, 16, 17, 17, 17, 17, 18, 18, 18, 18, 19, 19, 19, 19, + 20, 20, 20, 20, 21, 21, 21, 21, 22, 22, 22, 22, 23, 23, 23, 23, + 24, 24, 24, 24, 25, 25, 25, 25, 26, 26, 26, 26, 27, 27, 27, 27, + 28, 28, 28, 28, 29, 29, 29, 29, 30, 30, 30, 30, 31, 31, 31, 31, + 32, 32, 32, 32, 33, 33, 33, 33, 34, 34, 34, 34, 35, 35, 35, 35, + 36, 36, 36, 36, 37, 37, 37, 37, 38, 38, 38, 38, 39, 39, 39, 39, + 40, 40, 40, 40, 41, 41, 41, 41, 42, 42, 42, 42, 43, 43, 43, 43, + 44, 44, 44, 44, 45, 45, 45, 45, 46, 46, 46, 46, 47, 47, 47, 47, + 48, 48, 48, 48, 49, 49, 49, 49, 50, 50, 50, 50, 51, 51, 51, 51, + 52, 52, 52, 52, 53, 53, 53, 53, 54, 54, 54, 54, 55, 55, 55, 55, + 56, 56, 56, 56, 57, 57, 57, 57, 58, 58, 58, 58, 59, 59, 59, 59, + 60, 60, 60, 60, 61, 61, 61, 61, 62, 62, 62, 62, 63, 63, 63, 63, + + /* CONTEXT_MSB6, second last byte, */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + + /* CONTEXT_UTF8, last byte. */ + /* ASCII range. */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 4, 0, 0, 4, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 8, 12, 16, 12, 12, 20, 12, 16, 24, 28, 12, 12, 32, 12, 36, 12, + 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 32, 32, 24, 40, 28, 12, + 12, 48, 52, 52, 52, 48, 52, 52, 52, 48, 52, 52, 52, 52, 52, 48, + 52, 52, 52, 52, 52, 48, 52, 52, 52, 52, 52, 24, 12, 28, 12, 12, + 12, 56, 60, 60, 60, 56, 60, 60, 60, 56, 60, 60, 60, 60, 60, 56, + 60, 60, 60, 60, 60, 56, 60, 60, 60, 60, 60, 24, 12, 28, 12, 0, + /* UTF8 continuation byte range. */ + 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, + 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, + 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, + 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, + /* UTF8 lead byte range. */ + 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, + 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, + 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, + 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, + + /* CONTEXT_UTF8 second last byte. */ + /* ASCII range. */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, + 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, + 1, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 1, 1, 1, 1, 0, + /* UTF8 continuation byte range. */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + /* UTF8 lead byte range. */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + + /* CONTEXT_SIGNED, last byte, same as the above values shifted by 3 bits. */ + 0, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, + 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, + 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, + 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, + 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, + 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, + 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, + 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, + 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, + 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, + 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, + 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 56, + + /* CONTEXT_SIGNED, second last byte. */ + 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 7, +}; diff --git a/modules/brotli/common/context.h b/modules/brotli/common/context.h index 24b3eb48f5..685a279dc0 100644 --- a/modules/brotli/common/context.h +++ b/modules/brotli/common/context.h @@ -88,6 +88,7 @@ #ifndef BROTLI_COMMON_CONTEXT_H_ #define BROTLI_COMMON_CONTEXT_H_ +#include #include typedef enum ContextType { @@ -97,163 +98,14 @@ typedef enum ContextType { CONTEXT_SIGNED = 3 } ContextType; +/* "Soft-private", it is exported, but not "advertised" as API. */ /* Common context lookup table for all context modes. */ -static const uint8_t kContextLookup[2048] = { - /* CONTEXT_LSB6, last byte. */ - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, - 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, - 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, - 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, - 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, - 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, - 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, - 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, - 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, - 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, - 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, - 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, - 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, - - /* CONTEXT_LSB6, second last byte, */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - - /* CONTEXT_MSB6, last byte. */ - 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, - 4, 4, 4, 4, 5, 5, 5, 5, 6, 6, 6, 6, 7, 7, 7, 7, - 8, 8, 8, 8, 9, 9, 9, 9, 10, 10, 10, 10, 11, 11, 11, 11, - 12, 12, 12, 12, 13, 13, 13, 13, 14, 14, 14, 14, 15, 15, 15, 15, - 16, 16, 16, 16, 17, 17, 17, 17, 18, 18, 18, 18, 19, 19, 19, 19, - 20, 20, 20, 20, 21, 21, 21, 21, 22, 22, 22, 22, 23, 23, 23, 23, - 24, 24, 24, 24, 25, 25, 25, 25, 26, 26, 26, 26, 27, 27, 27, 27, - 28, 28, 28, 28, 29, 29, 29, 29, 30, 30, 30, 30, 31, 31, 31, 31, - 32, 32, 32, 32, 33, 33, 33, 33, 34, 34, 34, 34, 35, 35, 35, 35, - 36, 36, 36, 36, 37, 37, 37, 37, 38, 38, 38, 38, 39, 39, 39, 39, - 40, 40, 40, 40, 41, 41, 41, 41, 42, 42, 42, 42, 43, 43, 43, 43, - 44, 44, 44, 44, 45, 45, 45, 45, 46, 46, 46, 46, 47, 47, 47, 47, - 48, 48, 48, 48, 49, 49, 49, 49, 50, 50, 50, 50, 51, 51, 51, 51, - 52, 52, 52, 52, 53, 53, 53, 53, 54, 54, 54, 54, 55, 55, 55, 55, - 56, 56, 56, 56, 57, 57, 57, 57, 58, 58, 58, 58, 59, 59, 59, 59, - 60, 60, 60, 60, 61, 61, 61, 61, 62, 62, 62, 62, 63, 63, 63, 63, - - /* CONTEXT_MSB6, second last byte, */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - - /* CONTEXT_UTF8, last byte. */ - /* ASCII range. */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 4, 0, 0, 4, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 8, 12, 16, 12, 12, 20, 12, 16, 24, 28, 12, 12, 32, 12, 36, 12, - 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 32, 32, 24, 40, 28, 12, - 12, 48, 52, 52, 52, 48, 52, 52, 52, 48, 52, 52, 52, 52, 52, 48, - 52, 52, 52, 52, 52, 48, 52, 52, 52, 52, 52, 24, 12, 28, 12, 12, - 12, 56, 60, 60, 60, 56, 60, 60, 60, 56, 60, 60, 60, 60, 60, 56, - 60, 60, 60, 60, 60, 56, 60, 60, 60, 60, 60, 24, 12, 28, 12, 0, - /* UTF8 continuation byte range. */ - 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, - 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, - 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, - 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, - /* UTF8 lead byte range. */ - 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, - 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, - 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, - 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, - - /* CONTEXT_UTF8 second last byte. */ - /* ASCII range. */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, - 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, - 1, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, - 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 1, 1, 1, 1, 0, - /* UTF8 continuation byte range. */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - /* UTF8 lead byte range. */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - - /* CONTEXT_SIGNED, last byte, same as the above values shifted by 3 bits. */ - 0, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, - 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, - 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, - 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, - 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, - 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, - 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, - 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, - 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, - 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, - 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, - 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 56, - - /* CONTEXT_SIGNED, second last byte. */ - 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, - 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, - 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, - 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 7, -}; +BROTLI_COMMON_API extern const uint8_t _kBrotliContextLookupTable[2048]; typedef const uint8_t* ContextLut; /* typeof(MODE) == ContextType; returns ContextLut */ -#define BROTLI_CONTEXT_LUT(MODE) (&kContextLookup[(MODE) << 9]) +#define BROTLI_CONTEXT_LUT(MODE) (&_kBrotliContextLookupTable[(MODE) << 9]) /* typeof(LUT) == ContextLut */ #define BROTLI_CONTEXT(P1, P2, LUT) ((LUT)[P1] | ((LUT) + 256)[P2]) diff --git a/modules/brotli/common/dictionary.c b/modules/brotli/common/dictionary.c index 64822a381b..f9e30417c0 100644 --- a/modules/brotli/common/dictionary.c +++ b/modules/brotli/common/dictionary.c @@ -5,12 +5,13 @@ */ #include "./dictionary.h" +#include "./platform.h" #if defined(__cplusplus) || defined(c_plusplus) extern "C" { #endif -#ifndef BROTLI_EXTERNAL_DICTIONARY_DATA +#if !defined(BROTLI_EXTERNAL_DICTIONARY_DATA) static const uint8_t kBrotliDictionaryData[] = { 116,105,109,101,100,111,119,110,108,105,102,101,108,101,102,116,98,97,99,107,99, @@ -5862,7 +5863,11 @@ static const uint8_t kBrotliDictionaryData[] = ; #endif /* !BROTLI_EXTERNAL_DICTIONARY_DATA */ +#if !defined(BROTLI_EXTERNAL_DICTIONARY_DATA) +static const BrotliDictionary kBrotliDictionary = { +#else static BrotliDictionary kBrotliDictionary = { +#endif /* size_bits_by_length */ { 0, 0, 0, 0, 10, 10, 11, 11, @@ -5895,9 +5900,13 @@ const BrotliDictionary* BrotliGetDictionary() { } void BrotliSetDictionaryData(const uint8_t* data) { +#if defined(BROTLI_EXTERNAL_DICTIONARY_DATA) if (!!data && !kBrotliDictionary.data) { kBrotliDictionary.data = data; } +#else + BROTLI_UNUSED(data); // Appease -Werror=unused-parameter +#endif } #if defined(__cplusplus) || defined(c_plusplus) diff --git a/modules/brotli/common/platform.c b/modules/brotli/common/platform.c new file mode 100644 index 0000000000..aef39e93c4 --- /dev/null +++ b/modules/brotli/common/platform.c @@ -0,0 +1,22 @@ +/* Copyright 2016 Google Inc. All Rights Reserved. + + Distributed under MIT license. + See file LICENSE for detail or copy at https://opensource.org/licenses/MIT +*/ + +#include + +#include "./platform.h" +#include + +/* Default brotli_alloc_func */ +void* BrotliDefaultAllocFunc(void* opaque, size_t size) { + BROTLI_UNUSED(opaque); + return malloc(size); +} + +/* Default brotli_free_func */ +void BrotliDefaultFreeFunc(void* opaque, void* address) { + BROTLI_UNUSED(opaque); + free(address); +} diff --git a/modules/brotli/common/platform.h b/modules/brotli/common/platform.h index 84c448c4cf..f5ca4435bc 100644 --- a/modules/brotli/common/platform.h +++ b/modules/brotli/common/platform.h @@ -24,12 +24,11 @@ #define BROTLI_COMMON_PLATFORM_H_ #include /* memcpy */ -#include /* malloc, free */ #include #include -#if defined(OS_LINUX) || defined(OS_CYGWIN) +#if defined(OS_LINUX) || defined(OS_CYGWIN) || defined(__EMSCRIPTEN__) #include #elif defined(OS_FREEBSD) #include @@ -41,6 +40,10 @@ #define BROTLI_X_BIG_ENDIAN BIG_ENDIAN #endif +#if BROTLI_MSVC_VERSION_CHECK(12, 0, 0) +#include +#endif + #if defined(BROTLI_ENABLE_LOG) || defined(BROTLI_DEBUG) #include #include @@ -308,8 +311,7 @@ static BROTLI_INLINE void BrotliUnalignedWrite64(void* p, uint64_t v) { } #else /* BROTLI_ALIGNED_READ */ /* Unaligned memory access is allowed: just cast pointer to requested type. */ -#if defined(ADDRESS_SANITIZER) || defined(THREAD_SANITIZER) || \ - defined(MEMORY_SANITIZER) +#if BROTLI_SANITIZED /* Consider we have an unaligned load/store of 4 bytes from address 0x...05. AddressSanitizer will treat it as a 3-byte access to the range 05:07 and will miss a bug if 08 is the first unaddressable byte. @@ -334,7 +336,7 @@ extern "C" { #define BrotliUnalignedRead32 __sanitizer_unaligned_load32 #define BrotliUnalignedRead64 __sanitizer_unaligned_load64 #define BrotliUnalignedWrite64 __sanitizer_unaligned_store64 -#else +#else /* BROTLI_SANITIZED */ static BROTLI_INLINE uint16_t BrotliUnalignedRead16(const void* p) { return *(const uint16_t*)p; } @@ -356,7 +358,7 @@ static BROTLI_INLINE void BrotliUnalignedWrite64(void* p, uint64_t v) { typedef BROTLI_ALIGNED(1) uint64_t brotli_unaligned_uint64_t; static BROTLI_INLINE uint64_t BrotliUnalignedRead64(const void* p) { - return (uint64_t) ((brotli_unaligned_uint64_t*) p)[0]; + return (uint64_t) ((const brotli_unaligned_uint64_t*) p)[0]; } static BROTLI_INLINE void BrotliUnalignedWrite64(void* p, uint64_t v) { brotli_unaligned_uint64_t* dwords = (brotli_unaligned_uint64_t*) p; @@ -374,7 +376,7 @@ static BROTLI_INLINE void BrotliUnalignedWrite64(void* p, uint64_t v) { } #endif /* BROTLI_GNUC_HAS_ATTRIBUTE(aligned, 2, 7, 0) */ #endif /* BROTLI_64_BITS */ -#endif /* ASAN / TSAN / MSAN */ +#endif /* BROTLI_SANITIZED */ #endif /* BROTLI_ALIGNED_READ */ #if BROTLI_LITTLE_ENDIAN @@ -466,20 +468,20 @@ static BROTLI_INLINE void BROTLI_UNALIGNED_STORE64LE(void* p, uint64_t v) { #endif #if defined(BROTLI_ENABLE_LOG) -#define BROTLI_DCHECK(x) assert(x) #define BROTLI_LOG(x) printf x #else -#define BROTLI_DCHECK(x) #define BROTLI_LOG(x) #endif #if defined(BROTLI_DEBUG) || defined(BROTLI_ENABLE_LOG) +#define BROTLI_DCHECK(x) assert(x) static BROTLI_INLINE void BrotliDump(const char* f, int l, const char* fn) { fprintf(stderr, "%s:%d (%s)\n", f, l, fn); fflush(stderr); } #define BROTLI_DUMP() BrotliDump(__FILE__, __LINE__, __FUNCTION__) #else +#define BROTLI_DCHECK(x) #define BROTLI_DUMP() (void)(0) #endif @@ -523,17 +525,41 @@ BROTLI_MIN_MAX(size_t) BROTLI_MIN_MAX(uint32_t) BROTLI_MIN_MAX(uint8_t) (A)[(J)] = __brotli_swap_tmp; \ } -/* Default brotli_alloc_func */ -static void* BrotliDefaultAllocFunc(void* opaque, size_t size) { - BROTLI_UNUSED(opaque); - return malloc(size); +#if BROTLI_64_BITS +#if BROTLI_GNUC_HAS_BUILTIN(__builtin_ctzll, 3, 4, 0) || \ + BROTLI_INTEL_VERSION_CHECK(16, 0, 0) +#define BROTLI_TZCNT64 __builtin_ctzll +#elif BROTLI_MSVC_VERSION_CHECK(12, 0, 0) +#if defined(BROTLI_TARGET_X64) +#define BROTLI_TZCNT64 _tzcnt_u64 +#else /* BROTLI_TARGET_X64 */ +static BROTLI_INLINE uint32_t BrotliBsf64Msvc(uint64_t x) { + uint32_t lsb; + _BitScanForward64(&lsb, x); + return lsb; } +#define BROTLI_TZCNT64 BrotliBsf64Msvc +#endif /* BROTLI_TARGET_X64 */ +#endif /* __builtin_ctzll */ +#endif /* BROTLI_64_BITS */ + +#if BROTLI_GNUC_HAS_BUILTIN(__builtin_clz, 3, 4, 0) || \ + BROTLI_INTEL_VERSION_CHECK(16, 0, 0) +#define BROTLI_BSR32(x) (31u ^ (uint32_t)__builtin_clz(x)) +#elif BROTLI_MSVC_VERSION_CHECK(12, 0, 0) +static BROTLI_INLINE uint32_t BrotliBsr32Msvc(uint32_t x) { + unsigned long msb; + _BitScanReverse(&msb, x); + return (uint32_t)msb; +} +#define BROTLI_BSR32 BrotliBsr32Msvc +#endif /* __builtin_clz */ + +/* Default brotli_alloc_func */ +BROTLI_COMMON_API void* BrotliDefaultAllocFunc(void* opaque, size_t size); /* Default brotli_free_func */ -static void BrotliDefaultFreeFunc(void* opaque, void* address) { - BROTLI_UNUSED(opaque); - free(address); -} +BROTLI_COMMON_API void BrotliDefaultFreeFunc(void* opaque, void* address); BROTLI_UNUSED_FUNCTION void BrotliSuppressUnusedFunctions(void) { BROTLI_UNUSED(&BrotliSuppressUnusedFunctions); diff --git a/modules/brotli/common/transform.c b/modules/brotli/common/transform.c index 426e635fd3..f8fa4335e1 100644 --- a/modules/brotli/common/transform.c +++ b/modules/brotli/common/transform.c @@ -24,8 +24,8 @@ static const char kPrefixSuffix[217] = /* 8x _0 _ _3 _8 _C _E _ _1 _7 _F */ " not \3er \3al \4ful \4ive \5less \4es" /* Ax _5 _9 _D _2 _7 _D */ - "t \4ize \2\xc2\xa0\4ous \5 the \2e \0"; -/* Cx _2 _7___ ___ _A _F _5 _8 */ + "t \4ize \2\xc2\xa0\4ous \5 the \2e "; /* \0 - implicit trailing zero. */ +/* Cx _2 _7___ ___ _A _F _5 _8 */ static const uint16_t kPrefixSuffixMap[50] = { 0x00, 0x02, 0x05, 0x0E, 0x13, 0x16, 0x18, 0x1E, 0x23, 0x25, @@ -160,12 +160,13 @@ static const uint8_t kTransformsData[] = { 0, BROTLI_TRANSFORM_UPPERCASE_FIRST, 34, }; -static BrotliTransforms kBrotliTransforms = { +static const BrotliTransforms kBrotliTransforms = { sizeof(kPrefixSuffix), (const uint8_t*)kPrefixSuffix, kPrefixSuffixMap, sizeof(kTransformsData) / (3 * sizeof(kTransformsData[0])), kTransformsData, + NULL, /* no extra parameters */ {0, 12, 27, 23, 42, 63, 56, 48, 59, 64} }; @@ -190,6 +191,48 @@ static int ToUpperCase(uint8_t* p) { return 3; } +static int Shift(uint8_t* word, int word_len, uint16_t parameter) { + /* Limited sign extension: scalar < (1 << 24). */ + uint32_t scalar = + (parameter & 0x7FFFu) + (0x1000000u - (parameter & 0x8000u)); + if (word[0] < 0x80) { + /* 1-byte rune / 0sssssss / 7 bit scalar (ASCII). */ + scalar += (uint32_t)word[0]; + word[0] = (uint8_t)(scalar & 0x7Fu); + return 1; + } else if (word[0] < 0xC0) { + /* Continuation / 10AAAAAA. */ + return 1; + } else if (word[0] < 0xE0) { + /* 2-byte rune / 110sssss AAssssss / 11 bit scalar. */ + if (word_len < 2) return 1; + scalar += (uint32_t)((word[1] & 0x3Fu) | ((word[0] & 0x1Fu) << 6u)); + word[0] = (uint8_t)(0xC0 | ((scalar >> 6u) & 0x1F)); + word[1] = (uint8_t)((word[1] & 0xC0) | (scalar & 0x3F)); + return 2; + } else if (word[0] < 0xF0) { + /* 3-byte rune / 1110ssss AAssssss BBssssss / 16 bit scalar. */ + if (word_len < 3) return word_len; + scalar += (uint32_t)((word[2] & 0x3Fu) | ((word[1] & 0x3Fu) << 6u) | + ((word[0] & 0x0Fu) << 12u)); + word[0] = (uint8_t)(0xE0 | ((scalar >> 12u) & 0x0F)); + word[1] = (uint8_t)((word[1] & 0xC0) | ((scalar >> 6u) & 0x3F)); + word[2] = (uint8_t)((word[2] & 0xC0) | (scalar & 0x3F)); + return 3; + } else if (word[0] < 0xF8) { + /* 4-byte rune / 11110sss AAssssss BBssssss CCssssss / 21 bit scalar. */ + if (word_len < 4) return word_len; + scalar += (uint32_t)((word[3] & 0x3Fu) | ((word[2] & 0x3Fu) << 6u) | + ((word[1] & 0x3Fu) << 12u) | ((word[0] & 0x07u) << 18u)); + word[0] = (uint8_t)(0xF0 | ((scalar >> 18u) & 0x07)); + word[1] = (uint8_t)((word[1] & 0xC0) | ((scalar >> 12u) & 0x3F)); + word[2] = (uint8_t)((word[2] & 0xC0) | ((scalar >> 6u) & 0x3F)); + word[3] = (uint8_t)((word[3] & 0xC0) | (scalar & 0x3F)); + return 4; + } + return 1; +} + int BrotliTransformDictionaryWord(uint8_t* dst, const uint8_t* word, int len, const BrotliTransforms* transforms, int transform_idx) { int idx = 0; @@ -221,6 +264,19 @@ int BrotliTransformDictionaryWord(uint8_t* dst, const uint8_t* word, int len, uppercase += step; len -= step; } + } else if (t == BROTLI_TRANSFORM_SHIFT_FIRST) { + uint16_t param = (uint16_t)(transforms->params[transform_idx * 2] + + (transforms->params[transform_idx * 2 + 1] << 8u)); + Shift(&dst[idx - len], len, param); + } else if (t == BROTLI_TRANSFORM_SHIFT_ALL) { + uint16_t param = (uint16_t)(transforms->params[transform_idx * 2] + + (transforms->params[transform_idx * 2 + 1] << 8u)); + uint8_t* shift = &dst[idx - len]; + while (len > 0) { + int step = Shift(shift, len, param); + shift += step; + len -= step; + } } } { diff --git a/modules/brotli/common/transform.h b/modules/brotli/common/transform.h index 456c12db9b..b6f86cc7d5 100644 --- a/modules/brotli/common/transform.h +++ b/modules/brotli/common/transform.h @@ -37,6 +37,8 @@ enum BrotliWordTransformType { BROTLI_TRANSFORM_OMIT_FIRST_7 = 18, BROTLI_TRANSFORM_OMIT_FIRST_8 = 19, BROTLI_TRANSFORM_OMIT_FIRST_9 = 20, + BROTLI_TRANSFORM_SHIFT_FIRST = 21, + BROTLI_TRANSFORM_SHIFT_ALL = 22, BROTLI_NUM_TRANSFORM_TYPES /* Counts transforms, not a transform itself. */ }; @@ -50,6 +52,9 @@ typedef struct BrotliTransforms { uint32_t num_transforms; /* Each entry is a [prefix_id, transform, suffix_id] triplet. */ const uint8_t* transforms; + /* Shift for BROTLI_TRANSFORM_SHIFT_FIRST and BROTLI_TRANSFORM_SHIFT_ALL, + must be NULL if and only if no such transforms are present. */ + const uint8_t* params; /* Indices of transforms like ["", BROTLI_TRANSFORM_OMIT_LAST_#, ""]. 0-th element corresponds to ["", BROTLI_TRANSFORM_IDENTITY, ""]. -1, if cut-off transform does not exist. */ diff --git a/modules/brotli/common/version.h b/modules/brotli/common/version.h index 0d0d0c7967..01b2998e25 100644 --- a/modules/brotli/common/version.h +++ b/modules/brotli/common/version.h @@ -14,13 +14,13 @@ BrotliEncoderVersion methods. */ /* Semantic version, calculated as (MAJOR << 24) | (MINOR << 12) | PATCH */ -#define BROTLI_VERSION 0x1000007 +#define BROTLI_VERSION 0x1000009 /* This macro is used by build system to produce Libtool-friendly soname. See https://www.gnu.org/software/libtool/manual/html_node/Libtool-versioning.html */ /* ABI version, calculated as (CURRENT << 24) | (REVISION << 12) | AGE */ -#define BROTLI_ABI_VERSION 0x1007000 +#define BROTLI_ABI_VERSION 0x1009000 #endif /* BROTLI_COMMON_VERSION_H_ */ diff --git a/modules/brotli/dec/bit_reader.c b/modules/brotli/dec/bit_reader.c index 722fd906dd..7f7b256a40 100644 --- a/modules/brotli/dec/bit_reader.c +++ b/modules/brotli/dec/bit_reader.c @@ -15,6 +15,17 @@ extern "C" { #endif +const uint32_t kBrotliBitMask[33] = { 0x00000000, + 0x00000001, 0x00000003, 0x00000007, 0x0000000F, + 0x0000001F, 0x0000003F, 0x0000007F, 0x000000FF, + 0x000001FF, 0x000003FF, 0x000007FF, 0x00000FFF, + 0x00001FFF, 0x00003FFF, 0x00007FFF, 0x0000FFFF, + 0x0001FFFF, 0x0003FFFF, 0x0007FFFF, 0x000FFFFF, + 0x001FFFFF, 0x003FFFFF, 0x007FFFFF, 0x00FFFFFF, + 0x01FFFFFF, 0x03FFFFFF, 0x07FFFFFF, 0x0FFFFFFF, + 0x1FFFFFFF, 0x3FFFFFFF, 0x7FFFFFFF, 0xFFFFFFFF +}; + void BrotliInitBitReader(BrotliBitReader* const br) { br->val_ = 0; br->bit_pos_ = sizeof(br->val_) << 3; @@ -43,6 +54,23 @@ BROTLI_BOOL BrotliWarmupBitReader(BrotliBitReader* const br) { return BROTLI_TRUE; } +BROTLI_BOOL BrotliSafeReadBits32Slow(BrotliBitReader* const br, + uint32_t n_bits, uint32_t* val) { + uint32_t low_val; + uint32_t high_val; + BrotliBitReaderState memento; + BROTLI_DCHECK(n_bits <= 32); + BROTLI_DCHECK(n_bits > 24); + BrotliBitReaderSaveState(br, &memento); + if (!BrotliSafeReadBits(br, 16, &low_val) || + !BrotliSafeReadBits(br, n_bits - 16, &high_val)) { + BrotliBitReaderRestoreState(br, &memento); + return BROTLI_FALSE; + } + *val = low_val | (high_val << 16); + return BROTLI_TRUE; +} + #if defined(__cplusplus) || defined(c_plusplus) } /* extern "C" */ #endif diff --git a/modules/brotli/dec/bit_reader.h b/modules/brotli/dec/bit_reader.h index c06e91419f..22bc060cad 100644 --- a/modules/brotli/dec/bit_reader.h +++ b/modules/brotli/dec/bit_reader.h @@ -11,6 +11,7 @@ #include /* memcpy */ +#include "../common/constants.h" #include "../common/platform.h" #include @@ -20,16 +21,7 @@ extern "C" { #define BROTLI_SHORT_FILL_BIT_WINDOW_READ (sizeof(brotli_reg_t) >> 1) -static const uint32_t kBitMask[33] = { 0x00000000, - 0x00000001, 0x00000003, 0x00000007, 0x0000000F, - 0x0000001F, 0x0000003F, 0x0000007F, 0x000000FF, - 0x000001FF, 0x000003FF, 0x000007FF, 0x00000FFF, - 0x00001FFF, 0x00003FFF, 0x00007FFF, 0x0000FFFF, - 0x0001FFFF, 0x0003FFFF, 0x0007FFFF, 0x000FFFFF, - 0x001FFFFF, 0x003FFFFF, 0x007FFFFF, 0x00FFFFFF, - 0x01FFFFFF, 0x03FFFFFF, 0x07FFFFFF, 0x0FFFFFFF, - 0x1FFFFFFF, 0x3FFFFFFF, 0x7FFFFFFF, 0xFFFFFFFF -}; +BROTLI_INTERNAL extern const uint32_t kBrotliBitMask[33]; static BROTLI_INLINE uint32_t BitMask(uint32_t n) { if (BROTLI_IS_CONSTANT(n) || BROTLI_HAS_UBFX) { @@ -37,7 +29,7 @@ static BROTLI_INLINE uint32_t BitMask(uint32_t n) { "Unsigned Bit Field Extract" UBFX instruction on ARM. */ return ~((0xFFFFFFFFu) << n); } else { - return kBitMask[n]; + return kBrotliBitMask[n]; } } @@ -65,6 +57,12 @@ BROTLI_INTERNAL void BrotliInitBitReader(BrotliBitReader* const br); reading. */ BROTLI_INTERNAL BROTLI_BOOL BrotliWarmupBitReader(BrotliBitReader* const br); +/* Fallback for BrotliSafeReadBits32. Extracted as noninlined method to unburden + the main code-path. Never called for RFC brotli streams, required only for + "large-window" mode and other extensions. */ +BROTLI_INTERNAL BROTLI_NOINLINE BROTLI_BOOL BrotliSafeReadBits32Slow( + BrotliBitReader* const br, uint32_t n_bits, uint32_t* val); + static BROTLI_INLINE void BrotliBitReaderSaveState( BrotliBitReader* const from, BrotliBitReaderState* to) { to->val_ = from->val_; @@ -87,8 +85,11 @@ static BROTLI_INLINE uint32_t BrotliGetAvailableBits( } /* Returns amount of unread bytes the bit reader still has buffered from the - BrotliInput, including whole bytes in br->val_. */ + BrotliInput, including whole bytes in br->val_. Result is capped with + maximal ring-buffer size (larger number won't be utilized anyway). */ static BROTLI_INLINE size_t BrotliGetRemainingBytes(BrotliBitReader* br) { + static const size_t kCap = (size_t)1 << BROTLI_LARGE_MAX_WBITS; + if (br->avail_in > kCap) return kCap; return br->avail_in + (BrotliGetAvailableBits(br) >> 3); } @@ -237,15 +238,17 @@ static BROTLI_INLINE void BrotliBitReaderUnload(BrotliBitReader* br) { static BROTLI_INLINE void BrotliTakeBits( BrotliBitReader* const br, uint32_t n_bits, uint32_t* val) { *val = (uint32_t)BrotliGetBitsUnmasked(br) & BitMask(n_bits); - BROTLI_LOG(("[BrotliReadBits] %d %d %d val: %6x\n", + BROTLI_LOG(("[BrotliTakeBits] %d %d %d val: %6x\n", (int)br->avail_in, (int)br->bit_pos_, (int)n_bits, (int)*val)); BrotliDropBits(br, n_bits); } /* Reads the specified number of bits from |br| and advances the bit pos. - Assumes that there is enough input to perform BrotliFillBitWindow. */ -static BROTLI_INLINE uint32_t BrotliReadBits( + Assumes that there is enough input to perform BrotliFillBitWindow. + Up to 24 bits are allowed to be requested from this method. */ +static BROTLI_INLINE uint32_t BrotliReadBits24( BrotliBitReader* const br, uint32_t n_bits) { + BROTLI_DCHECK(n_bits <= 24); if (BROTLI_64_BITS || (n_bits <= 16)) { uint32_t val; BrotliFillBitWindow(br, n_bits); @@ -262,10 +265,32 @@ static BROTLI_INLINE uint32_t BrotliReadBits( } } +/* Same as BrotliReadBits24, but allows reading up to 32 bits. */ +static BROTLI_INLINE uint32_t BrotliReadBits32( + BrotliBitReader* const br, uint32_t n_bits) { + BROTLI_DCHECK(n_bits <= 32); + if (BROTLI_64_BITS || (n_bits <= 16)) { + uint32_t val; + BrotliFillBitWindow(br, n_bits); + BrotliTakeBits(br, n_bits, &val); + return val; + } else { + uint32_t low_val; + uint32_t high_val; + BrotliFillBitWindow(br, 16); + BrotliTakeBits(br, 16, &low_val); + BrotliFillBitWindow(br, 16); + BrotliTakeBits(br, n_bits - 16, &high_val); + return low_val | (high_val << 16); + } +} + /* Tries to read the specified amount of bits. Returns BROTLI_FALSE, if there - is not enough input. |n_bits| MUST be positive. */ + is not enough input. |n_bits| MUST be positive. + Up to 24 bits are allowed to be requested from this method. */ static BROTLI_INLINE BROTLI_BOOL BrotliSafeReadBits( BrotliBitReader* const br, uint32_t n_bits, uint32_t* val) { + BROTLI_DCHECK(n_bits <= 24); while (BrotliGetAvailableBits(br) < n_bits) { if (!BrotliPullByte(br)) { return BROTLI_FALSE; @@ -275,6 +300,23 @@ static BROTLI_INLINE BROTLI_BOOL BrotliSafeReadBits( return BROTLI_TRUE; } +/* Same as BrotliSafeReadBits, but allows reading up to 32 bits. */ +static BROTLI_INLINE BROTLI_BOOL BrotliSafeReadBits32( + BrotliBitReader* const br, uint32_t n_bits, uint32_t* val) { + BROTLI_DCHECK(n_bits <= 32); + if (BROTLI_64_BITS || (n_bits <= 24)) { + while (BrotliGetAvailableBits(br) < n_bits) { + if (!BrotliPullByte(br)) { + return BROTLI_FALSE; + } + } + BrotliTakeBits(br, n_bits, val); + return BROTLI_TRUE; + } else { + return BrotliSafeReadBits32Slow(br, n_bits, val); + } +} + /* Advances the bit reader position to the next byte boundary and verifies that any skipped bits are set to zero. */ static BROTLI_INLINE BROTLI_BOOL BrotliJumpToByteBoundary(BrotliBitReader* br) { diff --git a/modules/brotli/dec/decode.c b/modules/brotli/dec/decode.c index 08bd76ca16..ae5a3d3fa3 100644 --- a/modules/brotli/dec/decode.c +++ b/modules/brotli/dec/decode.c @@ -41,7 +41,8 @@ extern "C" { /* We need the slack region for the following reasons: - doing up to two 16-byte copies for fast backward copying - - inserting transformed dictionary word (5 prefix + 24 base + 8 suffix) */ + - inserting transformed dictionary word: + 5 prefix + 24 base + 8 suffix */ static const uint32_t kRingBufferWriteAheadSlack = 42; static const uint8_t kCodeLengthCodeOrder[BROTLI_CODE_LENGTH_CODES] = { @@ -274,7 +275,8 @@ static BrotliDecoderErrorCode BROTLI_NOINLINE DecodeMetaBlockLength( s->loop_counter = i; return BROTLI_DECODER_NEEDS_MORE_INPUT; } - if (i + 1 == s->size_nibbles && s->size_nibbles > 4 && bits == 0) { + if (i + 1 == (int)s->size_nibbles && s->size_nibbles > 4 && + bits == 0) { return BROTLI_FAILURE(BROTLI_DECODER_ERROR_FORMAT_EXUBERANT_NIBBLE); } s->meta_block_remaining_len |= (int)(bits << (i * 4)); @@ -323,7 +325,8 @@ static BrotliDecoderErrorCode BROTLI_NOINLINE DecodeMetaBlockLength( s->loop_counter = i; return BROTLI_DECODER_NEEDS_MORE_INPUT; } - if (i + 1 == s->size_nibbles && s->size_nibbles > 1 && bits == 0) { + if (i + 1 == (int)s->size_nibbles && s->size_nibbles > 1 && + bits == 0) { return BROTLI_FAILURE( BROTLI_DECODER_ERROR_FORMAT_EXUBERANT_META_NIBBLE); } @@ -470,32 +473,34 @@ static BROTLI_INLINE uint32_t Log2Floor(uint32_t x) { Totally 1..4 symbols are read, 1..11 bits each. The list of symbols MUST NOT contain duplicates. */ static BrotliDecoderErrorCode ReadSimpleHuffmanSymbols( - uint32_t alphabet_size, uint32_t max_symbol, BrotliDecoderState* s) { + uint32_t alphabet_size_max, uint32_t alphabet_size_limit, + BrotliDecoderState* s) { /* max_bits == 1..11; symbol == 0..3; 1..44 bits will be read. */ BrotliBitReader* br = &s->br; - uint32_t max_bits = Log2Floor(alphabet_size - 1); - uint32_t i = s->sub_loop_counter; - uint32_t num_symbols = s->symbol; + BrotliMetablockHeaderArena* h = &s->arena.header; + uint32_t max_bits = Log2Floor(alphabet_size_max - 1); + uint32_t i = h->sub_loop_counter; + uint32_t num_symbols = h->symbol; while (i <= num_symbols) { uint32_t v; if (BROTLI_PREDICT_FALSE(!BrotliSafeReadBits(br, max_bits, &v))) { - s->sub_loop_counter = i; - s->substate_huffman = BROTLI_STATE_HUFFMAN_SIMPLE_READ; + h->sub_loop_counter = i; + h->substate_huffman = BROTLI_STATE_HUFFMAN_SIMPLE_READ; return BROTLI_DECODER_NEEDS_MORE_INPUT; } - if (v >= max_symbol) { + if (v >= alphabet_size_limit) { return BROTLI_FAILURE(BROTLI_DECODER_ERROR_FORMAT_SIMPLE_HUFFMAN_ALPHABET); } - s->symbols_lists_array[i] = (uint16_t)v; - BROTLI_LOG_UINT(s->symbols_lists_array[i]); + h->symbols_lists_array[i] = (uint16_t)v; + BROTLI_LOG_UINT(h->symbols_lists_array[i]); ++i; } for (i = 0; i < num_symbols; ++i) { uint32_t k = i + 1; for (; k <= num_symbols; ++k) { - if (s->symbols_lists_array[i] == s->symbols_lists_array[k]) { + if (h->symbols_lists_array[i] == h->symbols_lists_array[k]) { return BROTLI_FAILURE(BROTLI_DECODER_ERROR_FORMAT_SIMPLE_HUFFMAN_SAME); } } @@ -588,27 +593,28 @@ static BROTLI_INLINE void ProcessRepeatedCodeLength(uint32_t code_len, static BrotliDecoderErrorCode ReadSymbolCodeLengths( uint32_t alphabet_size, BrotliDecoderState* s) { BrotliBitReader* br = &s->br; - uint32_t symbol = s->symbol; - uint32_t repeat = s->repeat; - uint32_t space = s->space; - uint32_t prev_code_len = s->prev_code_len; - uint32_t repeat_code_len = s->repeat_code_len; - uint16_t* symbol_lists = s->symbol_lists; - uint16_t* code_length_histo = s->code_length_histo; - int* next_symbol = s->next_symbol; + BrotliMetablockHeaderArena* h = &s->arena.header; + uint32_t symbol = h->symbol; + uint32_t repeat = h->repeat; + uint32_t space = h->space; + uint32_t prev_code_len = h->prev_code_len; + uint32_t repeat_code_len = h->repeat_code_len; + uint16_t* symbol_lists = h->symbol_lists; + uint16_t* code_length_histo = h->code_length_histo; + int* next_symbol = h->next_symbol; if (!BrotliWarmupBitReader(br)) { return BROTLI_DECODER_NEEDS_MORE_INPUT; } while (symbol < alphabet_size && space > 0) { - const HuffmanCode* p = s->table; + const HuffmanCode* p = h->table; uint32_t code_len; BROTLI_HC_MARK_TABLE_FOR_FAST_LOAD(p); if (!BrotliCheckInputAmount(br, BROTLI_SHORT_FILL_BIT_WINDOW_READ)) { - s->symbol = symbol; - s->repeat = repeat; - s->prev_code_len = prev_code_len; - s->repeat_code_len = repeat_code_len; - s->space = space; + h->symbol = symbol; + h->repeat = repeat; + h->prev_code_len = prev_code_len; + h->repeat_code_len = repeat_code_len; + h->space = space; return BROTLI_DECODER_NEEDS_MORE_INPUT; } BrotliFillBitWindow16(br); @@ -630,16 +636,17 @@ static BrotliDecoderErrorCode ReadSymbolCodeLengths( symbol_lists, code_length_histo, next_symbol); } } - s->space = space; + h->space = space; return BROTLI_DECODER_SUCCESS; } static BrotliDecoderErrorCode SafeReadSymbolCodeLengths( uint32_t alphabet_size, BrotliDecoderState* s) { BrotliBitReader* br = &s->br; + BrotliMetablockHeaderArena* h = &s->arena.header; BROTLI_BOOL get_byte = BROTLI_FALSE; - while (s->symbol < alphabet_size && s->space > 0) { - const HuffmanCode* p = s->table; + while (h->symbol < alphabet_size && h->space > 0) { + const HuffmanCode* p = h->table; uint32_t code_len; uint32_t available_bits; uint32_t bits = 0; @@ -659,9 +666,9 @@ static BrotliDecoderErrorCode SafeReadSymbolCodeLengths( code_len = BROTLI_HC_FAST_LOAD_VALUE(p); /* code_len == 0..17 */ if (code_len < BROTLI_REPEAT_PREVIOUS_CODE_LENGTH) { BrotliDropBits(br, BROTLI_HC_FAST_LOAD_BITS(p)); - ProcessSingleCodeLength(code_len, &s->symbol, &s->repeat, &s->space, - &s->prev_code_len, s->symbol_lists, s->code_length_histo, - s->next_symbol); + ProcessSingleCodeLength(code_len, &h->symbol, &h->repeat, &h->space, + &h->prev_code_len, h->symbol_lists, h->code_length_histo, + h->next_symbol); } else { /* code_len == 16..17, extra_bits == 2..3 */ uint32_t extra_bits = code_len - 14U; uint32_t repeat_delta = (bits >> BROTLI_HC_FAST_LOAD_BITS(p)) & @@ -672,9 +679,9 @@ static BrotliDecoderErrorCode SafeReadSymbolCodeLengths( } BrotliDropBits(br, BROTLI_HC_FAST_LOAD_BITS(p) + extra_bits); ProcessRepeatedCodeLength(code_len, repeat_delta, alphabet_size, - &s->symbol, &s->repeat, &s->space, &s->prev_code_len, - &s->repeat_code_len, s->symbol_lists, s->code_length_histo, - s->next_symbol); + &h->symbol, &h->repeat, &h->space, &h->prev_code_len, + &h->repeat_code_len, h->symbol_lists, h->code_length_histo, + h->next_symbol); } } return BROTLI_DECODER_SUCCESS; @@ -684,9 +691,10 @@ static BrotliDecoderErrorCode SafeReadSymbolCodeLengths( Each code is 2..4 bits long. In total 30..72 bits are used. */ static BrotliDecoderErrorCode ReadCodeLengthCodeLengths(BrotliDecoderState* s) { BrotliBitReader* br = &s->br; - uint32_t num_codes = s->repeat; - unsigned space = s->space; - uint32_t i = s->sub_loop_counter; + BrotliMetablockHeaderArena* h = &s->arena.header; + uint32_t num_codes = h->repeat; + unsigned space = h->space; + uint32_t i = h->sub_loop_counter; for (; i < BROTLI_CODE_LENGTH_CODES; ++i) { const uint8_t code_len_idx = kCodeLengthCodeOrder[i]; uint32_t ix; @@ -699,21 +707,21 @@ static BrotliDecoderErrorCode ReadCodeLengthCodeLengths(BrotliDecoderState* s) { ix = 0; } if (kCodeLengthPrefixLength[ix] > available_bits) { - s->sub_loop_counter = i; - s->repeat = num_codes; - s->space = space; - s->substate_huffman = BROTLI_STATE_HUFFMAN_COMPLEX; + h->sub_loop_counter = i; + h->repeat = num_codes; + h->space = space; + h->substate_huffman = BROTLI_STATE_HUFFMAN_COMPLEX; return BROTLI_DECODER_NEEDS_MORE_INPUT; } } v = kCodeLengthPrefixValue[ix]; BrotliDropBits(br, kCodeLengthPrefixLength[ix]); - s->code_length_code_lengths[code_len_idx] = (uint8_t)v; - BROTLI_LOG_ARRAY_INDEX(s->code_length_code_lengths, code_len_idx); + h->code_length_code_lengths[code_len_idx] = (uint8_t)v; + BROTLI_LOG_ARRAY_INDEX(h->code_length_code_lengths, code_len_idx); if (v != 0) { space = space - (32U >> v); ++num_codes; - ++s->code_length_histo[v]; + ++h->code_length_histo[v]; if (space - 1U >= 32U) { /* space is 0 or wrapped around. */ break; @@ -737,49 +745,48 @@ static BrotliDecoderErrorCode ReadCodeLengthCodeLengths(BrotliDecoderState* s) { encoded with predefined entropy code. 32 - 74 bits are used. B.2) Decoded table is used to decode code lengths of symbols in resulting Huffman table. In worst case 3520 bits are read. */ -static BrotliDecoderErrorCode ReadHuffmanCode(uint32_t alphabet_size, - uint32_t max_symbol, +static BrotliDecoderErrorCode ReadHuffmanCode(uint32_t alphabet_size_max, + uint32_t alphabet_size_limit, HuffmanCode* table, uint32_t* opt_table_size, BrotliDecoderState* s) { BrotliBitReader* br = &s->br; - /* Unnecessary masking, but might be good for safety. */ - alphabet_size &= 0x7FF; + BrotliMetablockHeaderArena* h = &s->arena.header; /* State machine. */ for (;;) { - switch (s->substate_huffman) { + switch (h->substate_huffman) { case BROTLI_STATE_HUFFMAN_NONE: - if (!BrotliSafeReadBits(br, 2, &s->sub_loop_counter)) { + if (!BrotliSafeReadBits(br, 2, &h->sub_loop_counter)) { return BROTLI_DECODER_NEEDS_MORE_INPUT; } - BROTLI_LOG_UINT(s->sub_loop_counter); + BROTLI_LOG_UINT(h->sub_loop_counter); /* The value is used as follows: 1 for simple code; 0 for no skipping, 2 skips 2 code lengths, 3 skips 3 code lengths */ - if (s->sub_loop_counter != 1) { - s->space = 32; - s->repeat = 0; /* num_codes */ - memset(&s->code_length_histo[0], 0, sizeof(s->code_length_histo[0]) * + if (h->sub_loop_counter != 1) { + h->space = 32; + h->repeat = 0; /* num_codes */ + memset(&h->code_length_histo[0], 0, sizeof(h->code_length_histo[0]) * (BROTLI_HUFFMAN_MAX_CODE_LENGTH_CODE_LENGTH + 1)); - memset(&s->code_length_code_lengths[0], 0, - sizeof(s->code_length_code_lengths)); - s->substate_huffman = BROTLI_STATE_HUFFMAN_COMPLEX; + memset(&h->code_length_code_lengths[0], 0, + sizeof(h->code_length_code_lengths)); + h->substate_huffman = BROTLI_STATE_HUFFMAN_COMPLEX; continue; } /* Fall through. */ case BROTLI_STATE_HUFFMAN_SIMPLE_SIZE: /* Read symbols, codes & code lengths directly. */ - if (!BrotliSafeReadBits(br, 2, &s->symbol)) { /* num_symbols */ - s->substate_huffman = BROTLI_STATE_HUFFMAN_SIMPLE_SIZE; + if (!BrotliSafeReadBits(br, 2, &h->symbol)) { /* num_symbols */ + h->substate_huffman = BROTLI_STATE_HUFFMAN_SIMPLE_SIZE; return BROTLI_DECODER_NEEDS_MORE_INPUT; } - s->sub_loop_counter = 0; + h->sub_loop_counter = 0; /* Fall through. */ case BROTLI_STATE_HUFFMAN_SIMPLE_READ: { BrotliDecoderErrorCode result = - ReadSimpleHuffmanSymbols(alphabet_size, max_symbol, s); + ReadSimpleHuffmanSymbols(alphabet_size_max, alphabet_size_limit, s); if (result != BROTLI_DECODER_SUCCESS) { return result; } @@ -788,21 +795,21 @@ static BrotliDecoderErrorCode ReadHuffmanCode(uint32_t alphabet_size, case BROTLI_STATE_HUFFMAN_SIMPLE_BUILD: { uint32_t table_size; - if (s->symbol == 3) { + if (h->symbol == 3) { uint32_t bits; if (!BrotliSafeReadBits(br, 1, &bits)) { - s->substate_huffman = BROTLI_STATE_HUFFMAN_SIMPLE_BUILD; + h->substate_huffman = BROTLI_STATE_HUFFMAN_SIMPLE_BUILD; return BROTLI_DECODER_NEEDS_MORE_INPUT; } - s->symbol += bits; + h->symbol += bits; } - BROTLI_LOG_UINT(s->symbol); + BROTLI_LOG_UINT(h->symbol); table_size = BrotliBuildSimpleHuffmanTable( - table, HUFFMAN_TABLE_BITS, s->symbols_lists_array, s->symbol); + table, HUFFMAN_TABLE_BITS, h->symbols_lists_array, h->symbol); if (opt_table_size) { *opt_table_size = table_size; } - s->substate_huffman = BROTLI_STATE_HUFFMAN_NONE; + h->substate_huffman = BROTLI_STATE_HUFFMAN_NONE; return BROTLI_DECODER_SUCCESS; } @@ -813,44 +820,45 @@ static BrotliDecoderErrorCode ReadHuffmanCode(uint32_t alphabet_size, if (result != BROTLI_DECODER_SUCCESS) { return result; } - BrotliBuildCodeLengthsHuffmanTable(s->table, - s->code_length_code_lengths, - s->code_length_histo); - memset(&s->code_length_histo[0], 0, sizeof(s->code_length_histo)); + BrotliBuildCodeLengthsHuffmanTable(h->table, + h->code_length_code_lengths, + h->code_length_histo); + memset(&h->code_length_histo[0], 0, sizeof(h->code_length_histo)); for (i = 0; i <= BROTLI_HUFFMAN_MAX_CODE_LENGTH; ++i) { - s->next_symbol[i] = (int)i - (BROTLI_HUFFMAN_MAX_CODE_LENGTH + 1); - s->symbol_lists[s->next_symbol[i]] = 0xFFFF; + h->next_symbol[i] = (int)i - (BROTLI_HUFFMAN_MAX_CODE_LENGTH + 1); + h->symbol_lists[h->next_symbol[i]] = 0xFFFF; } - s->symbol = 0; - s->prev_code_len = BROTLI_INITIAL_REPEATED_CODE_LENGTH; - s->repeat = 0; - s->repeat_code_len = 0; - s->space = 32768; - s->substate_huffman = BROTLI_STATE_HUFFMAN_LENGTH_SYMBOLS; + h->symbol = 0; + h->prev_code_len = BROTLI_INITIAL_REPEATED_CODE_LENGTH; + h->repeat = 0; + h->repeat_code_len = 0; + h->space = 32768; + h->substate_huffman = BROTLI_STATE_HUFFMAN_LENGTH_SYMBOLS; } /* Fall through. */ case BROTLI_STATE_HUFFMAN_LENGTH_SYMBOLS: { uint32_t table_size; - BrotliDecoderErrorCode result = ReadSymbolCodeLengths(max_symbol, s); + BrotliDecoderErrorCode result = ReadSymbolCodeLengths( + alphabet_size_limit, s); if (result == BROTLI_DECODER_NEEDS_MORE_INPUT) { - result = SafeReadSymbolCodeLengths(max_symbol, s); + result = SafeReadSymbolCodeLengths(alphabet_size_limit, s); } if (result != BROTLI_DECODER_SUCCESS) { return result; } - if (s->space != 0) { - BROTLI_LOG(("[ReadHuffmanCode] space = %d\n", (int)s->space)); + if (h->space != 0) { + BROTLI_LOG(("[ReadHuffmanCode] space = %d\n", (int)h->space)); return BROTLI_FAILURE(BROTLI_DECODER_ERROR_FORMAT_HUFFMAN_SPACE); } table_size = BrotliBuildHuffmanTable( - table, HUFFMAN_TABLE_BITS, s->symbol_lists, s->code_length_histo); + table, HUFFMAN_TABLE_BITS, h->symbol_lists, h->code_length_histo); if (opt_table_size) { *opt_table_size = table_size; } - s->substate_huffman = BROTLI_STATE_HUFFMAN_NONE; + h->substate_huffman = BROTLI_STATE_HUFFMAN_NONE; return BROTLI_DECODER_SUCCESS; } @@ -867,8 +875,8 @@ static BROTLI_INLINE uint32_t ReadBlockLength(const HuffmanCode* table, uint32_t code; uint32_t nbits; code = ReadSymbol(table, br); - nbits = kBlockLengthPrefixCode[code].nbits; /* nbits == 2..24 */ - return kBlockLengthPrefixCode[code].offset + BrotliReadBits(br, nbits); + nbits = _kBrotliPrefixCodeRanges[code].nbits; /* nbits == 2..24 */ + return _kBrotliPrefixCodeRanges[code].offset + BrotliReadBits24(br, nbits); } /* WARNING: if state is not BROTLI_STATE_READ_BLOCK_LENGTH_NONE, then @@ -886,13 +894,14 @@ static BROTLI_INLINE BROTLI_BOOL SafeReadBlockLength( } { uint32_t bits; - uint32_t nbits = kBlockLengthPrefixCode[index].nbits; /* nbits == 2..24 */ + uint32_t nbits = _kBrotliPrefixCodeRanges[index].nbits; + uint32_t offset = _kBrotliPrefixCodeRanges[index].offset; if (!BrotliSafeReadBits(br, nbits, &bits)) { s->block_length_index = index; s->substate_read_block_length = BROTLI_STATE_READ_BLOCK_LENGTH_SUFFIX; return BROTLI_FALSE; } - *result = kBlockLengthPrefixCode[index].offset + bits; + *result = offset + bits; s->substate_read_block_length = BROTLI_STATE_READ_BLOCK_LENGTH_NONE; return BROTLI_TRUE; } @@ -952,22 +961,22 @@ static BROTLI_NOINLINE void InverseMoveToFrontTransform( /* Decodes a series of Huffman table using ReadHuffmanCode function. */ static BrotliDecoderErrorCode HuffmanTreeGroupDecode( HuffmanTreeGroup* group, BrotliDecoderState* s) { - if (s->substate_tree_group != BROTLI_STATE_TREE_GROUP_LOOP) { - s->next = group->codes; - s->htree_index = 0; - s->substate_tree_group = BROTLI_STATE_TREE_GROUP_LOOP; + BrotliMetablockHeaderArena* h = &s->arena.header; + if (h->substate_tree_group != BROTLI_STATE_TREE_GROUP_LOOP) { + h->next = group->codes; + h->htree_index = 0; + h->substate_tree_group = BROTLI_STATE_TREE_GROUP_LOOP; } - while (s->htree_index < group->num_htrees) { + while (h->htree_index < group->num_htrees) { uint32_t table_size; - BrotliDecoderErrorCode result = - ReadHuffmanCode(group->alphabet_size, group->max_symbol, - s->next, &table_size, s); + BrotliDecoderErrorCode result = ReadHuffmanCode(group->alphabet_size_max, + group->alphabet_size_limit, h->next, &table_size, s); if (result != BROTLI_DECODER_SUCCESS) return result; - group->htrees[s->htree_index] = s->next; - s->next += table_size; - ++s->htree_index; + group->htrees[h->htree_index] = h->next; + h->next += table_size; + ++h->htree_index; } - s->substate_tree_group = BROTLI_STATE_TREE_GROUP_NONE; + h->substate_tree_group = BROTLI_STATE_TREE_GROUP_NONE; return BROTLI_DECODER_SUCCESS; } @@ -985,15 +994,16 @@ static BrotliDecoderErrorCode DecodeContextMap(uint32_t context_map_size, BrotliDecoderState* s) { BrotliBitReader* br = &s->br; BrotliDecoderErrorCode result = BROTLI_DECODER_SUCCESS; + BrotliMetablockHeaderArena* h = &s->arena.header; - switch ((int)s->substate_context_map) { + switch ((int)h->substate_context_map) { case BROTLI_STATE_CONTEXT_MAP_NONE: result = DecodeVarLenUint8(s, br, num_htrees); if (result != BROTLI_DECODER_SUCCESS) { return result; } (*num_htrees)++; - s->context_index = 0; + h->context_index = 0; BROTLI_LOG_UINT(context_map_size); BROTLI_LOG_UINT(*num_htrees); *context_map_arg = @@ -1005,7 +1015,7 @@ static BrotliDecoderErrorCode DecodeContextMap(uint32_t context_map_size, memset(*context_map_arg, 0, (size_t)context_map_size); return BROTLI_DECODER_SUCCESS; } - s->substate_context_map = BROTLI_STATE_CONTEXT_MAP_READ_PREFIX; + h->substate_context_map = BROTLI_STATE_CONTEXT_MAP_READ_PREFIX; /* Fall through. */ case BROTLI_STATE_CONTEXT_MAP_READ_PREFIX: { @@ -1016,38 +1026,38 @@ static BrotliDecoderErrorCode DecodeContextMap(uint32_t context_map_size, return BROTLI_DECODER_NEEDS_MORE_INPUT; } if ((bits & 1) != 0) { /* Use RLE for zeros. */ - s->max_run_length_prefix = (bits >> 1) + 1; + h->max_run_length_prefix = (bits >> 1) + 1; BrotliDropBits(br, 5); } else { - s->max_run_length_prefix = 0; + h->max_run_length_prefix = 0; BrotliDropBits(br, 1); } - BROTLI_LOG_UINT(s->max_run_length_prefix); - s->substate_context_map = BROTLI_STATE_CONTEXT_MAP_HUFFMAN; + BROTLI_LOG_UINT(h->max_run_length_prefix); + h->substate_context_map = BROTLI_STATE_CONTEXT_MAP_HUFFMAN; } /* Fall through. */ case BROTLI_STATE_CONTEXT_MAP_HUFFMAN: { - uint32_t alphabet_size = *num_htrees + s->max_run_length_prefix; + uint32_t alphabet_size = *num_htrees + h->max_run_length_prefix; result = ReadHuffmanCode(alphabet_size, alphabet_size, - s->context_map_table, NULL, s); + h->context_map_table, NULL, s); if (result != BROTLI_DECODER_SUCCESS) return result; - s->code = 0xFFFF; - s->substate_context_map = BROTLI_STATE_CONTEXT_MAP_DECODE; + h->code = 0xFFFF; + h->substate_context_map = BROTLI_STATE_CONTEXT_MAP_DECODE; } /* Fall through. */ case BROTLI_STATE_CONTEXT_MAP_DECODE: { - uint32_t context_index = s->context_index; - uint32_t max_run_length_prefix = s->max_run_length_prefix; + uint32_t context_index = h->context_index; + uint32_t max_run_length_prefix = h->max_run_length_prefix; uint8_t* context_map = *context_map_arg; - uint32_t code = s->code; + uint32_t code = h->code; BROTLI_BOOL skip_preamble = (code != 0xFFFF); while (context_index < context_map_size || skip_preamble) { if (!skip_preamble) { - if (!SafeReadSymbol(s->context_map_table, br, &code)) { - s->code = 0xFFFF; - s->context_index = context_index; + if (!SafeReadSymbol(h->context_map_table, br, &code)) { + h->code = 0xFFFF; + h->context_index = context_index; return BROTLI_DECODER_NEEDS_MORE_INPUT; } BROTLI_LOG_UINT(code); @@ -1068,8 +1078,8 @@ static BrotliDecoderErrorCode DecodeContextMap(uint32_t context_map_size, { uint32_t reps; if (!BrotliSafeReadBits(br, code, &reps)) { - s->code = code; - s->context_index = context_index; + h->code = code; + h->context_index = context_index; return BROTLI_DECODER_NEEDS_MORE_INPUT; } reps += 1U << code; @@ -1089,13 +1099,13 @@ static BrotliDecoderErrorCode DecodeContextMap(uint32_t context_map_size, case BROTLI_STATE_CONTEXT_MAP_TRANSFORM: { uint32_t bits; if (!BrotliSafeReadBits(br, 1, &bits)) { - s->substate_context_map = BROTLI_STATE_CONTEXT_MAP_TRANSFORM; + h->substate_context_map = BROTLI_STATE_CONTEXT_MAP_TRANSFORM; return BROTLI_DECODER_NEEDS_MORE_INPUT; } if (bits != 0) { InverseMoveToFrontTransform(*context_map_arg, context_map_size, s); } - s->substate_context_map = BROTLI_STATE_CONTEXT_MAP_NONE; + h->substate_context_map = BROTLI_STATE_CONTEXT_MAP_NONE; return BROTLI_DECODER_SUCCESS; } @@ -1457,32 +1467,28 @@ static BrotliDecoderErrorCode ReadContextModes(BrotliDecoderState* s) { } static BROTLI_INLINE void TakeDistanceFromRingBuffer(BrotliDecoderState* s) { - if (s->distance_code == 0) { - --s->dist_rb_idx; - s->distance_code = s->dist_rb[s->dist_rb_idx & 3]; + int offset = s->distance_code - 3; + if (s->distance_code <= 3) { /* Compensate double distance-ring-buffer roll for dictionary items. */ - s->distance_context = 1; + s->distance_context = 1 >> s->distance_code; + s->distance_code = s->dist_rb[(s->dist_rb_idx - offset) & 3]; + s->dist_rb_idx -= s->distance_context; } else { - int distance_code = s->distance_code << 1; - /* kDistanceShortCodeIndexOffset has 2-bit values from LSB: - 3, 2, 1, 0, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2 */ - const uint32_t kDistanceShortCodeIndexOffset = 0xAAAFFF1B; - /* kDistanceShortCodeValueOffset has 2-bit values from LSB: - -0, 0,-0, 0,-1, 1,-2, 2,-3, 3,-1, 1,-2, 2,-3, 3 */ - const uint32_t kDistanceShortCodeValueOffset = 0xFA5FA500; - int v = (s->dist_rb_idx + - (int)(kDistanceShortCodeIndexOffset >> distance_code)) & 0x3; - s->distance_code = s->dist_rb[v]; - v = (int)(kDistanceShortCodeValueOffset >> distance_code) & 0x3; - if ((distance_code & 0x3) != 0) { - s->distance_code += v; + int index_delta = 3; + int delta; + int base = s->distance_code - 10; + if (s->distance_code < 10) { + base = s->distance_code - 4; } else { - s->distance_code -= v; - if (s->distance_code <= 0) { - /* A huge distance will cause a BROTLI_FAILURE() soon. - This is a little faster than failing here. */ - s->distance_code = 0x7FFFFFFF; - } + index_delta = 2; + } + /* Unpack one of six 4-bit values. */ + delta = ((0x605142 >> (4 * base)) & 0xF) - 3; + s->distance_code = s->dist_rb[(s->dist_rb_idx + index_delta) & 0x3] + delta; + if (s->distance_code <= 0) { + /* A huge distance will cause a BROTLI_FAILURE() soon. + This is a little faster than failing here. */ + s->distance_code = 0x7FFFFFFF; } } } @@ -1497,62 +1503,153 @@ static BROTLI_INLINE BROTLI_BOOL SafeReadBits( } } +static BROTLI_INLINE BROTLI_BOOL SafeReadBits32( + BrotliBitReader* const br, uint32_t n_bits, uint32_t* val) { + if (n_bits != 0) { + return BrotliSafeReadBits32(br, n_bits, val); + } else { + *val = 0; + return BROTLI_TRUE; + } +} + +/* + RFC 7932 Section 4 with "..." shortenings and "[]" emendations. + + Each distance ... is represented with a pair ... + The distance code is encoded using a prefix code... The number of extra bits + can be 0..24... Two additional parameters: NPOSTFIX (0..3), and ... + NDIRECT (0..120) ... are encoded in the meta-block header... + + The first 16 distance symbols ... reference past distances... ring buffer ... + Next NDIRECT distance symbols ... represent distances from 1 to NDIRECT... + [For] distance symbols 16 + NDIRECT and greater ... the number of extra bits + ... is given by the following formula: + + [ xcode = dcode - NDIRECT - 16 ] + ndistbits = 1 + [ xcode ] >> (NPOSTFIX + 1) + + ... +*/ + +/* + RFC 7932 Section 9.2 with "..." shortenings and "[]" emendations. + + ... to get the actual value of the parameter NDIRECT, left-shift this + four-bit number by NPOSTFIX bits ... +*/ + +/* Remaining formulas from RFC 7932 Section 4 could be rewritten as following: + + alphabet_size = 16 + NDIRECT + (max_distbits << (NPOSTFIX + 1)) + + half = ((xcode >> NPOSTFIX) & 1) << ndistbits + postfix = xcode & ((1 << NPOSTFIX) - 1) + range_start = 2 * (1 << ndistbits - 1 - 1) + + distance = (range_start + half + extra) << NPOSTFIX + postfix + NDIRECT + 1 + + NB: ndistbits >= 1 -> range_start >= 0 + NB: range_start has factor 2, as the range is covered by 2 "halves" + NB: extra -1 offset in range_start formula covers the absence of + ndistbits = 0 case + NB: when NPOSTFIX = 0, NDIRECT is not greater than 15 + + In other words, xcode has the following binary structure - XXXHPPP: + - XXX represent the number of extra distance bits + - H selects upper / lower range of distances + - PPP represent "postfix" + + "Regular" distance encoding has NPOSTFIX = 0; omitting the postfix part + simplifies distance calculation. + + Using NPOSTFIX > 0 allows cheaper encoding of regular structures, e.g. where + most of distances have the same reminder of division by 2/4/8. For example, + the table of int32_t values that come from different sources; if it is likely + that 3 highest bytes of values from the same source are the same, then + copy distance often looks like 4x + y. + + Distance calculation could be rewritten to: + + ndistbits = NDISTBITS(NDIRECT, NPOSTFIX)[dcode] + distance = OFFSET(NDIRECT, NPOSTFIX)[dcode] + extra << NPOSTFIX + + NDISTBITS and OFFSET could be pre-calculated, as NDIRECT and NPOSTFIX could + change only once per meta-block. +*/ + +/* Calculates distance lookup table. + NB: it is possible to have all 64 tables precalculated. */ +static void CalculateDistanceLut(BrotliDecoderState* s) { + BrotliMetablockBodyArena* b = &s->arena.body; + uint32_t npostfix = s->distance_postfix_bits; + uint32_t ndirect = s->num_direct_distance_codes; + uint32_t alphabet_size_limit = s->distance_hgroup.alphabet_size_limit; + uint32_t postfix = 1u << npostfix; + uint32_t j; + uint32_t bits = 1; + uint32_t half = 0; + + /* Skip short codes. */ + uint32_t i = BROTLI_NUM_DISTANCE_SHORT_CODES; + + /* Fill direct codes. */ + for (j = 0; j < ndirect; ++j) { + b->dist_extra_bits[i] = 0; + b->dist_offset[i] = j + 1; + ++i; + } + + /* Fill regular distance codes. */ + while (i < alphabet_size_limit) { + uint32_t base = ndirect + ((((2 + half) << bits) - 4) << npostfix) + 1; + /* Always fill the complete group. */ + for (j = 0; j < postfix; ++j) { + b->dist_extra_bits[i] = (uint8_t)bits; + b->dist_offset[i] = base + j; + ++i; + } + bits = bits + half; + half = half ^ 1; + } +} + /* Precondition: s->distance_code < 0. */ static BROTLI_INLINE BROTLI_BOOL ReadDistanceInternal( int safe, BrotliDecoderState* s, BrotliBitReader* br) { - int distval; + BrotliMetablockBodyArena* b = &s->arena.body; + uint32_t code; + uint32_t bits; BrotliBitReaderState memento; HuffmanCode* distance_tree = s->distance_hgroup.htrees[s->dist_htree_index]; if (!safe) { - s->distance_code = (int)ReadSymbol(distance_tree, br); + code = ReadSymbol(distance_tree, br); } else { - uint32_t code; BrotliBitReaderSaveState(br, &memento); if (!SafeReadSymbol(distance_tree, br, &code)) { return BROTLI_FALSE; } - s->distance_code = (int)code; } + --s->block_length[2]; /* Convert the distance code to the actual distance by possibly - looking up past distances from the s->ringbuffer. */ + looking up past distances from the s->dist_rb. */ s->distance_context = 0; - if ((s->distance_code & ~0xF) == 0) { + if ((code & ~0xFu) == 0) { + s->distance_code = (int)code; TakeDistanceFromRingBuffer(s); - --s->block_length[2]; return BROTLI_TRUE; } - distval = s->distance_code - (int)s->num_direct_distance_codes; - if (distval >= 0) { - uint32_t nbits; - int postfix; - int offset; - if (!safe && (s->distance_postfix_bits == 0)) { - nbits = ((uint32_t)distval >> 1) + 1; - offset = ((2 + (distval & 1)) << nbits) - 4; - s->distance_code = (int)s->num_direct_distance_codes + offset + - (int)BrotliReadBits(br, nbits); - } else { - /* This branch also works well when s->distance_postfix_bits == 0. */ - uint32_t bits; - postfix = distval & s->distance_postfix_mask; - distval >>= s->distance_postfix_bits; - nbits = ((uint32_t)distval >> 1) + 1; - if (safe) { - if (!SafeReadBits(br, nbits, &bits)) { - s->distance_code = -1; /* Restore precondition. */ - BrotliBitReaderRestoreState(br, &memento); - return BROTLI_FALSE; - } - } else { - bits = BrotliReadBits(br, nbits); - } - offset = ((2 + (distval & 1)) << nbits) - 4; - s->distance_code = (int)s->num_direct_distance_codes + - ((offset + (int)bits) << s->distance_postfix_bits) + postfix; + if (!safe) { + bits = BrotliReadBits32(br, b->dist_extra_bits[code]); + } else { + if (!SafeReadBits32(br, b->dist_extra_bits[code], &bits)) { + ++s->block_length[2]; + BrotliBitReaderRestoreState(br, &memento); + return BROTLI_FALSE; } } - s->distance_code = s->distance_code - BROTLI_NUM_DISTANCE_SHORT_CODES + 1; - --s->block_length[2]; + s->distance_code = + (int)(b->dist_offset[code] + (bits << s->distance_postfix_bits)); return BROTLI_TRUE; } @@ -1588,9 +1685,9 @@ static BROTLI_INLINE BROTLI_BOOL ReadCommandInternal( *insert_length = v.insert_len_offset; if (!safe) { if (BROTLI_PREDICT_FALSE(v.insert_len_extra_bits != 0)) { - insert_len_extra = BrotliReadBits(br, v.insert_len_extra_bits); + insert_len_extra = BrotliReadBits24(br, v.insert_len_extra_bits); } - copy_length = BrotliReadBits(br, v.copy_len_extra_bits); + copy_length = BrotliReadBits24(br, v.copy_len_extra_bits); } else { if (!SafeReadBits(br, v.insert_len_extra_bits, &insert_len_extra) || !SafeReadBits(br, v.copy_len_extra_bits, ©_length)) { @@ -1935,21 +2032,6 @@ static BROTLI_NOINLINE BrotliDecoderErrorCode SafeProcessCommands( return ProcessCommandsInternal(1, s); } -/* Returns the maximum number of distance symbols which can only represent - distances not exceeding BROTLI_MAX_ALLOWED_DISTANCE. */ -static uint32_t BrotliMaxDistanceSymbol(uint32_t ndirect, uint32_t npostfix) { - static const uint32_t bound[BROTLI_MAX_NPOSTFIX + 1] = {0, 4, 12, 28}; - static const uint32_t diff[BROTLI_MAX_NPOSTFIX + 1] = {73, 126, 228, 424}; - uint32_t postfix = 1U << npostfix; - if (ndirect < bound[npostfix]) { - return ndirect + diff[npostfix] + postfix; - } else if (ndirect > bound[npostfix] + postfix) { - return ndirect + diff[npostfix]; - } else { - return bound[npostfix] + diff[npostfix] + postfix; - } -} - BrotliDecoderResult BrotliDecoderDecompress( size_t encoded_size, const uint8_t* encoded_buffer, size_t* decoded_size, uint8_t* decoded_buffer) { @@ -2167,33 +2249,23 @@ BrotliDecoderResult BrotliDecoderDecompressStream( s->state = BROTLI_STATE_UNCOMPRESSED; break; } + s->state = BROTLI_STATE_BEFORE_COMPRESSED_METABLOCK_HEADER; + /* Fall through. */ + + case BROTLI_STATE_BEFORE_COMPRESSED_METABLOCK_HEADER: { + BrotliMetablockHeaderArena* h = &s->arena.header; s->loop_counter = 0; + /* Initialize compressed metablock header arena. */ + h->sub_loop_counter = 0; + /* Make small negative indexes addressable. */ + h->symbol_lists = + &h->symbols_lists_array[BROTLI_HUFFMAN_MAX_CODE_LENGTH + 1]; + h->substate_huffman = BROTLI_STATE_HUFFMAN_NONE; + h->substate_tree_group = BROTLI_STATE_TREE_GROUP_NONE; + h->substate_context_map = BROTLI_STATE_CONTEXT_MAP_NONE; s->state = BROTLI_STATE_HUFFMAN_CODE_0; - break; - - case BROTLI_STATE_UNCOMPRESSED: { - result = CopyUncompressedBlockToOutput( - available_out, next_out, total_out, s); - if (result != BROTLI_DECODER_SUCCESS) { - break; - } - s->state = BROTLI_STATE_METABLOCK_DONE; - break; } - - case BROTLI_STATE_METADATA: - for (; s->meta_block_remaining_len > 0; --s->meta_block_remaining_len) { - uint32_t bits; - /* Read one byte and ignore it. */ - if (!BrotliSafeReadBits(br, 8, &bits)) { - result = BROTLI_DECODER_NEEDS_MORE_INPUT; - break; - } - } - if (result == BROTLI_DECODER_SUCCESS) { - s->state = BROTLI_STATE_METABLOCK_DONE; - } - break; + /* Fall through. */ case BROTLI_STATE_HUFFMAN_CODE_0: if (s->loop_counter >= 3) { @@ -2247,6 +2319,30 @@ BrotliDecoderResult BrotliDecoderDecompressStream( break; } + case BROTLI_STATE_UNCOMPRESSED: { + result = CopyUncompressedBlockToOutput( + available_out, next_out, total_out, s); + if (result != BROTLI_DECODER_SUCCESS) { + break; + } + s->state = BROTLI_STATE_METABLOCK_DONE; + break; + } + + case BROTLI_STATE_METADATA: + for (; s->meta_block_remaining_len > 0; --s->meta_block_remaining_len) { + uint32_t bits; + /* Read one byte and ignore it. */ + if (!BrotliSafeReadBits(br, 8, &bits)) { + result = BROTLI_DECODER_NEEDS_MORE_INPUT; + break; + } + } + if (result == BROTLI_DECODER_SUCCESS) { + s->state = BROTLI_STATE_METABLOCK_DONE; + } + break; + case BROTLI_STATE_METABLOCK_HEADER_2: { uint32_t bits; if (!BrotliSafeReadBits(br, 6, &bits)) { @@ -2255,11 +2351,9 @@ BrotliDecoderResult BrotliDecoderDecompressStream( } s->distance_postfix_bits = bits & BitMask(2); bits >>= 2; - s->num_direct_distance_codes = BROTLI_NUM_DISTANCE_SHORT_CODES + - (bits << s->distance_postfix_bits); + s->num_direct_distance_codes = bits << s->distance_postfix_bits; BROTLI_LOG_UINT(s->num_direct_distance_codes); BROTLI_LOG_UINT(s->distance_postfix_bits); - s->distance_postfix_mask = (int)BitMask(s->distance_postfix_bits); s->context_modes = (uint8_t*)BROTLI_DECODER_ALLOC(s, (size_t)s->num_block_types[0]); if (s->context_modes == 0) { @@ -2291,17 +2385,19 @@ BrotliDecoderResult BrotliDecoderDecompressStream( /* Fall through. */ case BROTLI_STATE_CONTEXT_MAP_2: { - uint32_t num_direct_codes = - s->num_direct_distance_codes - BROTLI_NUM_DISTANCE_SHORT_CODES; - uint32_t num_distance_codes = BROTLI_DISTANCE_ALPHABET_SIZE( - s->distance_postfix_bits, num_direct_codes, - (s->large_window ? BROTLI_LARGE_MAX_DISTANCE_BITS : - BROTLI_MAX_DISTANCE_BITS)); - uint32_t max_distance_symbol = (s->large_window ? - BrotliMaxDistanceSymbol( - num_direct_codes, s->distance_postfix_bits) : - num_distance_codes); + uint32_t npostfix = s->distance_postfix_bits; + uint32_t ndirect = s->num_direct_distance_codes; + uint32_t distance_alphabet_size_max = BROTLI_DISTANCE_ALPHABET_SIZE( + npostfix, ndirect, BROTLI_MAX_DISTANCE_BITS); + uint32_t distance_alphabet_size_limit = distance_alphabet_size_max; BROTLI_BOOL allocation_success = BROTLI_TRUE; + if (s->large_window) { + BrotliDistanceCodeLimit limit = BrotliCalculateDistanceCodeLimit( + BROTLI_MAX_ALLOWED_DISTANCE, npostfix, ndirect); + distance_alphabet_size_max = BROTLI_DISTANCE_ALPHABET_SIZE( + npostfix, ndirect, BROTLI_LARGE_MAX_DISTANCE_BITS); + distance_alphabet_size_limit = limit.max_alphabet_size; + } result = DecodeContextMap( s->num_block_types[2] << BROTLI_DISTANCE_CONTEXT_BITS, &s->num_dist_htrees, &s->dist_context_map, s); @@ -2315,8 +2411,8 @@ BrotliDecoderResult BrotliDecoderDecompressStream( s, &s->insert_copy_hgroup, BROTLI_NUM_COMMAND_SYMBOLS, BROTLI_NUM_COMMAND_SYMBOLS, s->num_block_types[1]); allocation_success &= BrotliDecoderHuffmanTreeGroupInit( - s, &s->distance_hgroup, num_distance_codes, - max_distance_symbol, s->num_dist_htrees); + s, &s->distance_hgroup, distance_alphabet_size_max, + distance_alphabet_size_limit, s->num_dist_htrees); if (!allocation_success) { return SaveErrorCode(s, BROTLI_FAILURE(BROTLI_DECODER_ERROR_ALLOC_TREE_GROUPS)); @@ -2338,18 +2434,24 @@ BrotliDecoderResult BrotliDecoderDecompressStream( result = HuffmanTreeGroupDecode(hgroup, s); if (result != BROTLI_DECODER_SUCCESS) break; s->loop_counter++; - if (s->loop_counter >= 3) { - PrepareLiteralDecoding(s); - s->dist_context_map_slice = s->dist_context_map; - s->htree_command = s->insert_copy_hgroup.htrees[0]; - if (!BrotliEnsureRingBuffer(s)) { - result = BROTLI_FAILURE(BROTLI_DECODER_ERROR_ALLOC_RING_BUFFER_2); - break; - } - s->state = BROTLI_STATE_COMMAND_BEGIN; + if (s->loop_counter < 3) { + break; } - break; + s->state = BROTLI_STATE_BEFORE_COMPRESSED_METABLOCK_BODY; } + /* Fall through. */ + + case BROTLI_STATE_BEFORE_COMPRESSED_METABLOCK_BODY: + PrepareLiteralDecoding(s); + s->dist_context_map_slice = s->dist_context_map; + s->htree_command = s->insert_copy_hgroup.htrees[0]; + if (!BrotliEnsureRingBuffer(s)) { + result = BROTLI_FAILURE(BROTLI_DECODER_ERROR_ALLOC_RING_BUFFER_2); + break; + } + CalculateDistanceLut(s); + s->state = BROTLI_STATE_COMMAND_BEGIN; + /* Fall through. */ case BROTLI_STATE_COMMAND_BEGIN: /* Fall through. */ diff --git a/modules/brotli/dec/huffman.h b/modules/brotli/dec/huffman.h index b9f0716c16..a8fbc45347 100644 --- a/modules/brotli/dec/huffman.h +++ b/modules/brotli/dec/huffman.h @@ -18,12 +18,6 @@ extern "C" { #define BROTLI_HUFFMAN_MAX_CODE_LENGTH 15 -/* Maximum possible Huffman table size for an alphabet size of (index * 32), - max code length 15 and root table bits 8. */ -static const uint16_t kMaxHuffmanTableSize[] = { - 256, 402, 436, 468, 500, 534, 566, 598, 630, 662, 694, 726, 758, 790, 822, - 854, 886, 920, 952, 984, 1016, 1048, 1080, 1112, 1144, 1176, 1208, 1240, 1272, - 1304, 1336, 1368, 1400, 1432, 1464, 1496, 1528}; /* BROTLI_NUM_BLOCK_LEN_SYMBOLS == 26 */ #define BROTLI_HUFFMAN_MAX_SIZE_26 396 /* BROTLI_MAX_BLOCK_TYPE_SYMBOLS == 258 */ @@ -82,7 +76,7 @@ typedef BROTLI_ALIGNED(4) uint32_t HuffmanCode; static BROTLI_INLINE HuffmanCode ConstructHuffmanCode(const uint8_t bits, const uint16_t value) { - return ((value & 0xFFFF) << 16) | (bits & 0xFF); + return (HuffmanCode) ((value & 0xFFFF) << 16) | (bits & 0xFF); } #define BROTLI_HC_MARK_TABLE_FOR_FAST_LOAD(H) uint32_t __fastload_##H = (*H) @@ -100,7 +94,7 @@ BROTLI_INTERNAL void BrotliBuildCodeLengthsHuffmanTable(HuffmanCode* root_table, /* Builds Huffman lookup table assuming code lengths are in symbol order. Returns size of resulting table. */ BROTLI_INTERNAL uint32_t BrotliBuildHuffmanTable(HuffmanCode* root_table, - int root_bits, const uint16_t* const symbol_lists, uint16_t* count_arg); + int root_bits, const uint16_t* const symbol_lists, uint16_t* count); /* Builds a simple Huffman table. The |num_symbols| parameter is to be interpreted as follows: 0 means 1 symbol, 1 means 2 symbols, @@ -110,13 +104,13 @@ BROTLI_INTERNAL uint32_t BrotliBuildSimpleHuffmanTable(HuffmanCode* table, int root_bits, uint16_t* symbols, uint32_t num_symbols); /* Contains a collection of Huffman trees with the same alphabet size. */ -/* max_symbol is needed due to simple codes since log2(alphabet_size) could be - greater than log2(max_symbol). */ +/* alphabet_size_limit is needed due to simple codes, since + log2(alphabet_size_max) could be greater than log2(alphabet_size_limit). */ typedef struct { HuffmanCode** htrees; HuffmanCode* codes; - uint16_t alphabet_size; - uint16_t max_symbol; + uint16_t alphabet_size_max; + uint16_t alphabet_size_limit; uint16_t num_htrees; } HuffmanTreeGroup; diff --git a/modules/brotli/dec/prefix.h b/modules/brotli/dec/prefix.h index 3ea062d84a..481a2c7917 100644 --- a/modules/brotli/dec/prefix.h +++ b/modules/brotli/dec/prefix.h @@ -13,24 +13,6 @@ #include "../common/constants.h" #include -/* Represents the range of values belonging to a prefix code: - [offset, offset + 2^nbits) */ -struct PrefixCodeRange { - uint16_t offset; - uint8_t nbits; -}; - -static const struct PrefixCodeRange - kBlockLengthPrefixCode[BROTLI_NUM_BLOCK_LEN_SYMBOLS] = { - { 1, 2}, { 5, 2}, { 9, 2}, { 13, 2}, - { 17, 3}, { 25, 3}, { 33, 3}, { 41, 3}, - { 49, 4}, { 65, 4}, { 81, 4}, { 97, 4}, - { 113, 5}, { 145, 5}, { 177, 5}, { 209, 5}, - { 241, 6}, { 305, 6}, { 369, 7}, { 497, 8}, - { 753, 9}, { 1265, 10}, {2289, 11}, {4337, 12}, - {8433, 13}, {16625, 24} -}; - typedef struct CmdLutElement { uint8_t insert_len_extra_bits; uint8_t copy_len_extra_bits; diff --git a/modules/brotli/dec/state.c b/modules/brotli/dec/state.c index e0b37c2dcd..f847836dda 100644 --- a/modules/brotli/dec/state.c +++ b/modules/brotli/dec/state.c @@ -33,10 +33,7 @@ BROTLI_BOOL BrotliDecoderStateInit(BrotliDecoderState* s, s->state = BROTLI_STATE_UNINITED; s->large_window = 0; s->substate_metablock_header = BROTLI_STATE_METABLOCK_HEADER_NONE; - s->substate_tree_group = BROTLI_STATE_TREE_GROUP_NONE; - s->substate_context_map = BROTLI_STATE_CONTEXT_MAP_NONE; s->substate_uncompressed = BROTLI_STATE_UNCOMPRESSED_NONE; - s->substate_huffman = BROTLI_STATE_HUFFMAN_NONE; s->substate_decode_uint8 = BROTLI_STATE_DECODE_UINT8_NONE; s->substate_read_block_length = BROTLI_STATE_READ_BLOCK_LENGTH_NONE; @@ -59,8 +56,6 @@ BROTLI_BOOL BrotliDecoderStateInit(BrotliDecoderState* s, s->context_map_slice = NULL; s->dist_context_map_slice = NULL; - s->sub_loop_counter = 0; - s->literal_hgroup.codes = NULL; s->literal_hgroup.htrees = NULL; s->insert_copy_hgroup.codes = NULL; @@ -84,9 +79,6 @@ BROTLI_BOOL BrotliDecoderStateInit(BrotliDecoderState* s, s->block_type_trees = NULL; s->block_len_trees = NULL; - /* Make small negative indexes addressable. */ - s->symbol_lists = &s->symbols_lists_array[BROTLI_HUFFMAN_MAX_CODE_LENGTH + 1]; - s->mtf_upper_bound = 63; s->dictionary = BrotliGetDictionary(); @@ -142,17 +134,20 @@ void BrotliDecoderStateCleanup(BrotliDecoderState* s) { } BROTLI_BOOL BrotliDecoderHuffmanTreeGroupInit(BrotliDecoderState* s, - HuffmanTreeGroup* group, uint32_t alphabet_size, uint32_t max_symbol, - uint32_t ntrees) { - /* Pack two allocations into one */ - const size_t max_table_size = kMaxHuffmanTableSize[(alphabet_size + 31) >> 5]; + HuffmanTreeGroup* group, uint32_t alphabet_size_max, + uint32_t alphabet_size_limit, uint32_t ntrees) { + /* 376 = 256 (1-st level table) + 4 + 7 + 15 + 31 + 63 (2-nd level mix-tables) + This number is discovered "unlimited" "enough" calculator; it is actually + a wee bigger than required in several cases (especially for alphabets with + less than 16 symbols). */ + const size_t max_table_size = alphabet_size_limit + 376; const size_t code_size = sizeof(HuffmanCode) * ntrees * max_table_size; const size_t htree_size = sizeof(HuffmanCode*) * ntrees; /* Pointer alignment is, hopefully, wider than sizeof(HuffmanCode). */ HuffmanCode** p = (HuffmanCode**)BROTLI_DECODER_ALLOC(s, code_size + htree_size); - group->alphabet_size = (uint16_t)alphabet_size; - group->max_symbol = (uint16_t)max_symbol; + group->alphabet_size_max = (uint16_t)alphabet_size_max; + group->alphabet_size_limit = (uint16_t)alphabet_size_limit; group->num_htrees = (uint16_t)ntrees; group->htrees = p; group->codes = (HuffmanCode*)(&p[ntrees]); diff --git a/modules/brotli/dec/state.h b/modules/brotli/dec/state.h index d28b63920e..54dab698ba 100644 --- a/modules/brotli/dec/state.h +++ b/modules/brotli/dec/state.h @@ -21,6 +21,95 @@ extern "C" { #endif +/* Graphviz diagram that describes state transitions: + +digraph States { + graph [compound=true] + concentrate=true + node [shape="box"] + + UNINITED -> {LARGE_WINDOW_BITS -> INITIALIZE} + subgraph cluster_metablock_workflow { + style="rounded" + label=< METABLOCK CYCLE > + METABLOCK_BEGIN -> METABLOCK_HEADER + METABLOCK_HEADER:sw -> METADATA + METABLOCK_HEADER:s -> UNCOMPRESSED + METABLOCK_HEADER:se -> METABLOCK_DONE:ne + METADATA:s -> METABLOCK_DONE:w + UNCOMPRESSED:s -> METABLOCK_DONE:n + METABLOCK_DONE:e -> METABLOCK_BEGIN:e [constraint="false"] + } + INITIALIZE -> METABLOCK_BEGIN + METABLOCK_DONE -> DONE + + subgraph cluster_compressed_metablock { + style="rounded" + label=< COMPRESSED METABLOCK > + + subgraph cluster_command { + style="rounded" + label=< HOT LOOP > + + _METABLOCK_DONE_PORT_ [shape=point style=invis] + + { + // Set different shape for nodes returning from "compressed metablock". + node [shape=invhouse]; CMD_INNER CMD_POST_DECODE_LITERALS; + CMD_POST_WRAP_COPY; CMD_INNER_WRITE; CMD_POST_WRITE_1; + } + + CMD_BEGIN -> CMD_INNER -> CMD_POST_DECODE_LITERALS -> CMD_POST_WRAP_COPY + + // IO ("write") nodes are not in the hot loop! + CMD_INNER_WRITE [style=dashed] + CMD_INNER -> CMD_INNER_WRITE + CMD_POST_WRITE_1 [style=dashed] + CMD_POST_DECODE_LITERALS -> CMD_POST_WRITE_1 + CMD_POST_WRITE_2 [style=dashed] + CMD_POST_WRAP_COPY -> CMD_POST_WRITE_2 + + CMD_POST_WRITE_1 -> CMD_BEGIN:s [constraint="false"] + CMD_INNER_WRITE -> {CMD_INNER CMD_POST_DECODE_LITERALS} + [constraint="false"] + CMD_BEGIN:ne -> CMD_POST_DECODE_LITERALS [constraint="false"] + CMD_POST_WRAP_COPY -> CMD_BEGIN [constraint="false"] + CMD_POST_DECODE_LITERALS -> CMD_BEGIN:ne [constraint="false"] + CMD_POST_WRITE_2 -> CMD_POST_WRAP_COPY [constraint="false"] + {rank=same; CMD_BEGIN; CMD_INNER; CMD_POST_DECODE_LITERALS; + CMD_POST_WRAP_COPY} + {rank=same; CMD_INNER_WRITE; CMD_POST_WRITE_1; CMD_POST_WRITE_2} + + {CMD_INNER CMD_POST_DECODE_LITERALS CMD_POST_WRAP_COPY} -> + _METABLOCK_DONE_PORT_ [style=invis] + {CMD_INNER_WRITE CMD_POST_WRITE_1} -> _METABLOCK_DONE_PORT_ + [constraint="false" style=invis] + } + + BEFORE_COMPRESSED_METABLOCK_HEADER:s -> HUFFMAN_CODE_0:n + HUFFMAN_CODE_0 -> HUFFMAN_CODE_1 -> HUFFMAN_CODE_2 -> HUFFMAN_CODE_3 + HUFFMAN_CODE_0 -> METABLOCK_HEADER_2 -> CONTEXT_MODES -> CONTEXT_MAP_1 + CONTEXT_MAP_1 -> CONTEXT_MAP_2 -> TREE_GROUP + TREE_GROUP -> BEFORE_COMPRESSED_METABLOCK_BODY:e + BEFORE_COMPRESSED_METABLOCK_BODY:s -> CMD_BEGIN:n + + HUFFMAN_CODE_3:e -> HUFFMAN_CODE_0:ne [constraint="false"] + {rank=same; HUFFMAN_CODE_0; HUFFMAN_CODE_1; HUFFMAN_CODE_2; HUFFMAN_CODE_3} + {rank=same; METABLOCK_HEADER_2; CONTEXT_MODES; CONTEXT_MAP_1; CONTEXT_MAP_2; + TREE_GROUP} + } + METABLOCK_HEADER:e -> BEFORE_COMPRESSED_METABLOCK_HEADER:n + + _METABLOCK_DONE_PORT_ -> METABLOCK_DONE:se + [constraint="false" ltail=cluster_command] + + UNINITED [shape=Mdiamond]; + DONE [shape=Msquare]; +} + + + */ + typedef enum { BROTLI_STATE_UNINITED, BROTLI_STATE_LARGE_WINDOW_BITS, @@ -39,6 +128,7 @@ typedef enum { BROTLI_STATE_METABLOCK_DONE, BROTLI_STATE_COMMAND_POST_WRITE_1, BROTLI_STATE_COMMAND_POST_WRITE_2, + BROTLI_STATE_BEFORE_COMPRESSED_METABLOCK_HEADER, BROTLI_STATE_HUFFMAN_CODE_0, BROTLI_STATE_HUFFMAN_CODE_1, BROTLI_STATE_HUFFMAN_CODE_2, @@ -46,6 +136,7 @@ typedef enum { BROTLI_STATE_CONTEXT_MAP_1, BROTLI_STATE_CONTEXT_MAP_2, BROTLI_STATE_TREE_GROUP, + BROTLI_STATE_BEFORE_COMPRESSED_METABLOCK_BODY, BROTLI_STATE_DONE } BrotliRunningState; @@ -98,6 +189,50 @@ typedef enum { BROTLI_STATE_READ_BLOCK_LENGTH_SUFFIX } BrotliRunningReadBlockLengthState; +typedef struct BrotliMetablockHeaderArena { + BrotliRunningTreeGroupState substate_tree_group; + BrotliRunningContextMapState substate_context_map; + BrotliRunningHuffmanState substate_huffman; + + uint32_t sub_loop_counter; + + uint32_t repeat_code_len; + uint32_t prev_code_len; + + /* For ReadHuffmanCode. */ + uint32_t symbol; + uint32_t repeat; + uint32_t space; + + /* Huffman table for "histograms". */ + HuffmanCode table[32]; + /* List of heads of symbol chains. */ + uint16_t* symbol_lists; + /* Storage from symbol_lists. */ + uint16_t symbols_lists_array[BROTLI_HUFFMAN_MAX_CODE_LENGTH + 1 + + BROTLI_NUM_COMMAND_SYMBOLS]; + /* Tails of symbol chains. */ + int next_symbol[32]; + uint8_t code_length_code_lengths[BROTLI_CODE_LENGTH_CODES]; + /* Population counts for the code lengths. */ + uint16_t code_length_histo[16]; + + /* For HuffmanTreeGroupDecode. */ + int htree_index; + HuffmanCode* next; + + /* For DecodeContextMap. */ + uint32_t context_index; + uint32_t max_run_length_prefix; + uint32_t code; + HuffmanCode context_map_table[BROTLI_HUFFMAN_MAX_SIZE_272]; +} BrotliMetablockHeaderArena; + +typedef struct BrotliMetablockBodyArena { + uint8_t dist_extra_bits[544]; + uint32_t dist_offset[544]; +} BrotliMetablockBodyArena; + struct BrotliDecoderStateStruct { BrotliRunningState state; @@ -110,7 +245,8 @@ struct BrotliDecoderStateStruct { brotli_free_func free_func; void* memory_manager_opaque; - /* Temporary storage for remaining input. */ + /* Temporary storage for remaining input. Brotli stream format is designed in + a way, that 64 bits are enough to make progress in decoding. */ union { uint64_t u64; uint8_t u8[8]; @@ -125,7 +261,6 @@ struct BrotliDecoderStateStruct { int dist_rb_idx; int dist_rb[4]; int error_code; - uint32_t sub_loop_counter; uint8_t* ringbuffer; uint8_t* ringbuffer_end; HuffmanCode* htree_command; @@ -153,13 +288,10 @@ struct BrotliDecoderStateStruct { uint32_t block_type_rb[6]; uint32_t distance_postfix_bits; uint32_t num_direct_distance_codes; - int distance_postfix_mask; uint32_t num_dist_htrees; uint8_t* dist_context_map; HuffmanCode* literal_htree; uint8_t dist_htree_index; - uint32_t repeat_code_len; - uint32_t prev_code_len; int copy_length; int distance_code; @@ -168,33 +300,6 @@ struct BrotliDecoderStateStruct { size_t rb_roundtrips; /* how many times we went around the ring-buffer */ size_t partial_pos_out; /* how much output to the user in total */ - /* For ReadHuffmanCode. */ - uint32_t symbol; - uint32_t repeat; - uint32_t space; - - HuffmanCode table[32]; - /* List of heads of symbol chains. */ - uint16_t* symbol_lists; - /* Storage from symbol_lists. */ - uint16_t symbols_lists_array[BROTLI_HUFFMAN_MAX_CODE_LENGTH + 1 + - BROTLI_NUM_COMMAND_SYMBOLS]; - /* Tails of symbol chains. */ - int next_symbol[32]; - uint8_t code_length_code_lengths[BROTLI_CODE_LENGTH_CODES]; - /* Population counts for the code lengths. */ - uint16_t code_length_histo[16]; - - /* For HuffmanTreeGroupDecode. */ - int htree_index; - HuffmanCode* next; - - /* For DecodeContextMap. */ - uint32_t context_index; - uint32_t max_run_length_prefix; - uint32_t code; - HuffmanCode context_map_table[BROTLI_HUFFMAN_MAX_SIZE_272]; - /* For InverseMoveToFrontTransform. */ uint32_t mtf_upper_bound; uint32_t mtf[64 + 1]; @@ -203,10 +308,7 @@ struct BrotliDecoderStateStruct { /* States inside function calls. */ BrotliRunningMetablockHeaderState substate_metablock_header; - BrotliRunningTreeGroupState substate_tree_group; - BrotliRunningContextMapState substate_context_map; BrotliRunningUncompressedState substate_uncompressed; - BrotliRunningHuffmanState substate_huffman; BrotliRunningDecodeUint8State substate_decode_uint8; BrotliRunningReadBlockLengthState substate_read_block_length; @@ -229,6 +331,11 @@ struct BrotliDecoderStateStruct { const BrotliTransforms* transforms; uint32_t trivial_literal_contexts[8]; /* 256 bits */ + + union { + BrotliMetablockHeaderArena header; + BrotliMetablockBodyArena body; + } arena; }; typedef struct BrotliDecoderStateStruct BrotliDecoderStateInternal; @@ -241,8 +348,8 @@ BROTLI_INTERNAL void BrotliDecoderStateMetablockBegin(BrotliDecoderState* s); BROTLI_INTERNAL void BrotliDecoderStateCleanupAfterMetablock( BrotliDecoderState* s); BROTLI_INTERNAL BROTLI_BOOL BrotliDecoderHuffmanTreeGroupInit( - BrotliDecoderState* s, HuffmanTreeGroup* group, uint32_t alphabet_size, - uint32_t max_symbol, uint32_t ntrees); + BrotliDecoderState* s, HuffmanTreeGroup* group, uint32_t alphabet_size_max, + uint32_t alphabet_size_limit, uint32_t ntrees); #define BROTLI_DECODER_ALLOC(S, L) S->alloc_func(S->memory_manager_opaque, L) diff --git a/modules/brotli/enc/backward_references.c b/modules/brotli/enc/backward_references.c index cd023d9b41..a07a617a09 100644 --- a/modules/brotli/enc/backward_references.c +++ b/modules/brotli/enc/backward_references.c @@ -9,6 +9,7 @@ #include "./backward_references.h" #include "../common/constants.h" +#include "../common/context.h" #include "../common/dictionary.h" #include "../common/platform.h" #include @@ -119,17 +120,17 @@ static BROTLI_INLINE size_t ComputeDistanceCode(size_t distance, #undef CAT #undef EXPAND_CAT -void BrotliCreateBackwardReferences( - size_t num_bytes, size_t position, const uint8_t* ringbuffer, - size_t ringbuffer_mask, const BrotliEncoderParams* params, - HasherHandle hasher, int* dist_cache, size_t* last_insert_len, +void BrotliCreateBackwardReferences(size_t num_bytes, + size_t position, const uint8_t* ringbuffer, size_t ringbuffer_mask, + ContextLut literal_context_lut, const BrotliEncoderParams* params, + Hasher* hasher, int* dist_cache, size_t* last_insert_len, Command* commands, size_t* num_commands, size_t* num_literals) { switch (params->hasher.type) { #define CASE_(N) \ case N: \ - CreateBackwardReferencesNH ## N( \ - num_bytes, position, ringbuffer, \ - ringbuffer_mask, params, hasher, dist_cache, \ + CreateBackwardReferencesNH ## N(num_bytes, \ + position, ringbuffer, ringbuffer_mask, \ + literal_context_lut, params, hasher, dist_cache, \ last_insert_len, commands, num_commands, num_literals); \ return; FOR_GENERIC_HASHERS(CASE_) diff --git a/modules/brotli/enc/backward_references.h b/modules/brotli/enc/backward_references.h index 3a4146647c..9589cc1541 100644 --- a/modules/brotli/enc/backward_references.h +++ b/modules/brotli/enc/backward_references.h @@ -10,6 +10,7 @@ #define BROTLI_ENC_BACKWARD_REFERENCES_H_ #include "../common/constants.h" +#include "../common/context.h" #include "../common/dictionary.h" #include "../common/platform.h" #include @@ -25,10 +26,10 @@ extern "C" { initially the total amount of commands output by previous CreateBackwardReferences calls, and must be incremented by the amount written by this call. */ -BROTLI_INTERNAL void BrotliCreateBackwardReferences( - size_t num_bytes, size_t position, const uint8_t* ringbuffer, - size_t ringbuffer_mask, const BrotliEncoderParams* params, - HasherHandle hasher, int* dist_cache, size_t* last_insert_len, +BROTLI_INTERNAL void BrotliCreateBackwardReferences(size_t num_bytes, + size_t position, const uint8_t* ringbuffer, size_t ringbuffer_mask, + ContextLut literal_context_lut, const BrotliEncoderParams* params, + Hasher* hasher, int* dist_cache, size_t* last_insert_len, Command* commands, size_t* num_commands, size_t* num_literals); #if defined(__cplusplus) || defined(c_plusplus) diff --git a/modules/brotli/enc/backward_references_hq.c b/modules/brotli/enc/backward_references_hq.c index 96b0e708de..5651caeb7a 100644 --- a/modules/brotli/enc/backward_references_hq.c +++ b/modules/brotli/enc/backward_references_hq.c @@ -11,6 +11,7 @@ #include /* memcpy, memset */ #include "../common/constants.h" +#include "../common/context.h" #include "../common/platform.h" #include #include "./command.h" @@ -26,6 +27,7 @@ extern "C" { #endif +/* BrotliCalculateDistanceCodeLimit(BROTLI_MAX_ALLOWED_DISTANCE, 3, 120). */ #define BROTLI_MAX_EFFECTIVE_DISTANCE_ALPHABET_SIZE 544 static const float kInfinity = 1.7e38f; /* ~= 2 ^ 127 */ @@ -86,14 +88,10 @@ typedef struct ZopfliCostModel { static void InitZopfliCostModel( MemoryManager* m, ZopfliCostModel* self, const BrotliDistanceParams* dist, size_t num_bytes) { - uint32_t distance_histogram_size = dist->alphabet_size; - if (distance_histogram_size > BROTLI_MAX_EFFECTIVE_DISTANCE_ALPHABET_SIZE) { - distance_histogram_size = BROTLI_MAX_EFFECTIVE_DISTANCE_ALPHABET_SIZE; - } self->num_bytes_ = num_bytes; self->literal_costs_ = BROTLI_ALLOC(m, float, num_bytes + 2); - self->cost_dist_ = BROTLI_ALLOC(m, float, dist->alphabet_size); - self->distance_histogram_size = distance_histogram_size; + self->cost_dist_ = BROTLI_ALLOC(m, float, dist->alphabet_size_limit); + self->distance_histogram_size = dist->alphabet_size_limit; if (BROTLI_IS_OOM(m)) return; } @@ -408,9 +406,12 @@ static size_t UpdateNodes( const int* starting_dist_cache, const size_t num_matches, const BackwardMatch* matches, const ZopfliCostModel* model, StartPosQueue* queue, ZopfliNode* nodes) { + const size_t stream_offset = params->stream_offset; const size_t cur_ix = block_start + pos; const size_t cur_ix_masked = cur_ix & ringbuffer_mask; const size_t max_distance = BROTLI_MIN(size_t, cur_ix, max_backward_limit); + const size_t dictionary_start = BROTLI_MIN(size_t, + cur_ix + stream_offset, max_backward_limit); const size_t max_len = num_bytes - pos; const size_t max_zopfli_len = MaxZopfliLen(params); const size_t max_iters = MaxZopfliCandidates(params); @@ -419,8 +420,8 @@ static size_t UpdateNodes( size_t k; size_t gap = 0; - EvaluateNode(block_start, pos, max_backward_limit, gap, starting_dist_cache, - model, queue, nodes); + EvaluateNode(block_start + stream_offset, pos, max_backward_limit, gap, + starting_dist_cache, model, queue, nodes); { const PosData* posdata = StartPosQueueAt(queue, 0); @@ -453,7 +454,7 @@ static size_t UpdateNodes( if (cur_ix_masked + best_len > ringbuffer_mask) { break; } - if (BROTLI_PREDICT_FALSE(backward > max_distance + gap)) { + if (BROTLI_PREDICT_FALSE(backward > dictionary_start + gap)) { /* Word dictionary -> ignore. */ continue; } @@ -472,6 +473,8 @@ static size_t UpdateNodes( &ringbuffer[cur_ix_masked], max_len); } else { + /* "Gray" area. It is addressable by decoder, but this encoder + instance does not have that data -> should not touch it. */ continue; } { @@ -506,7 +509,7 @@ static size_t UpdateNodes( BackwardMatch match = matches[j]; size_t dist = match.distance; BROTLI_BOOL is_dictionary_match = - TO_BROTLI_BOOL(dist > max_distance + gap); + TO_BROTLI_BOOL(dist > dictionary_start + gap); /* We already tried all possible last distance matches, so we can use normal distance code here. */ size_t dist_code = dist + BROTLI_NUM_DISTANCE_SHORT_CODES - 1; @@ -569,6 +572,7 @@ void BrotliZopfliCreateCommands(const size_t num_bytes, const size_t block_start, const ZopfliNode* nodes, int* dist_cache, size_t* last_insert_len, const BrotliEncoderParams* params, Command* commands, size_t* num_literals) { + const size_t stream_offset = params->stream_offset; const size_t max_backward_limit = BROTLI_MAX_BACKWARD_LIMIT(params->lgwin); size_t pos = 0; uint32_t offset = nodes[0].u.next; @@ -587,9 +591,10 @@ void BrotliZopfliCreateCommands(const size_t num_bytes, { size_t distance = ZopfliNodeCopyDistance(next); size_t len_code = ZopfliNodeLengthCode(next); - size_t max_distance = - BROTLI_MIN(size_t, block_start + pos, max_backward_limit); - BROTLI_BOOL is_dictionary = TO_BROTLI_BOOL(distance > max_distance + gap); + size_t dictionary_start = BROTLI_MIN(size_t, + block_start + pos + stream_offset, max_backward_limit); + BROTLI_BOOL is_dictionary = + TO_BROTLI_BOOL(distance > dictionary_start + gap); size_t dist_code = ZopfliNodeDistanceCode(next); InitCommand(&commands[i], ¶ms->dist, insert_length, copy_length, (int)len_code - (int)copy_length, dist_code); @@ -613,6 +618,7 @@ static size_t ZopfliIterate(size_t num_bytes, size_t position, const BrotliEncoderParams* params, const size_t gap, const int* dist_cache, const ZopfliCostModel* model, const uint32_t* num_matches, const BackwardMatch* matches, ZopfliNode* nodes) { + const size_t stream_offset = params->stream_offset; const size_t max_backward_limit = BROTLI_MAX_BACKWARD_LIMIT(params->lgwin); const size_t max_zopfli_len = MaxZopfliLen(params); StartPosQueue queue; @@ -637,7 +643,7 @@ static size_t ZopfliIterate(size_t num_bytes, size_t position, while (skip) { i++; if (i + 3 >= num_bytes) break; - EvaluateNode(position, i, max_backward_limit, gap, + EvaluateNode(position + stream_offset, i, max_backward_limit, gap, dist_cache, model, &queue, nodes); cur_match_pos += num_matches[i]; skip--; @@ -650,8 +656,9 @@ static size_t ZopfliIterate(size_t num_bytes, size_t position, /* REQUIRES: nodes != NULL and len(nodes) >= num_bytes + 1 */ size_t BrotliZopfliComputeShortestPath(MemoryManager* m, size_t num_bytes, size_t position, const uint8_t* ringbuffer, size_t ringbuffer_mask, - const BrotliEncoderParams* params, - const int* dist_cache, HasherHandle hasher, ZopfliNode* nodes) { + ContextLut literal_context_lut, const BrotliEncoderParams* params, + const int* dist_cache, Hasher* hasher, ZopfliNode* nodes) { + const size_t stream_offset = params->stream_offset; const size_t max_backward_limit = BROTLI_MAX_BACKWARD_LIMIT(params->lgwin); const size_t max_zopfli_len = MaxZopfliLen(params); ZopfliCostModel model; @@ -662,6 +669,7 @@ size_t BrotliZopfliComputeShortestPath(MemoryManager* m, size_t num_bytes, size_t i; size_t gap = 0; size_t lz_matches_offset = 0; + BROTLI_UNUSED(literal_context_lut); nodes[0].length = 0; nodes[0].u.cost = 0; InitZopfliCostModel(m, &model, ¶ms->dist, num_bytes); @@ -672,12 +680,14 @@ size_t BrotliZopfliComputeShortestPath(MemoryManager* m, size_t num_bytes, for (i = 0; i + HashTypeLengthH10() - 1 < num_bytes; i++) { const size_t pos = position + i; const size_t max_distance = BROTLI_MIN(size_t, pos, max_backward_limit); + const size_t dictionary_start = BROTLI_MIN(size_t, + pos + stream_offset, max_backward_limit); size_t skip; size_t num_matches; - num_matches = FindAllMatchesH10(hasher, + num_matches = FindAllMatchesH10(&hasher->privat._H10, ¶ms->dictionary, ringbuffer, ringbuffer_mask, pos, num_bytes - i, max_distance, - gap, params, &matches[lz_matches_offset]); + dictionary_start + gap, params, &matches[lz_matches_offset]); if (num_matches > 0 && BackwardMatchLength(&matches[num_matches - 1]) > max_zopfli_len) { matches[0] = matches[num_matches - 1]; @@ -692,13 +702,14 @@ size_t BrotliZopfliComputeShortestPath(MemoryManager* m, size_t num_bytes, } if (skip > 1) { /* Add the tail of the copy to the hasher. */ - StoreRangeH10(hasher, ringbuffer, ringbuffer_mask, pos + 1, BROTLI_MIN( + StoreRangeH10(&hasher->privat._H10, + ringbuffer, ringbuffer_mask, pos + 1, BROTLI_MIN( size_t, pos + skip, store_end)); skip--; while (skip) { i++; if (i + HashTypeLengthH10() - 1 >= num_bytes) break; - EvaluateNode(position, i, max_backward_limit, gap, + EvaluateNode(position + stream_offset, i, max_backward_limit, gap, dist_cache, &model, &queue, nodes); skip--; } @@ -710,15 +721,14 @@ size_t BrotliZopfliComputeShortestPath(MemoryManager* m, size_t num_bytes, void BrotliCreateZopfliBackwardReferences(MemoryManager* m, size_t num_bytes, size_t position, const uint8_t* ringbuffer, size_t ringbuffer_mask, - const BrotliEncoderParams* params, - HasherHandle hasher, int* dist_cache, size_t* last_insert_len, + ContextLut literal_context_lut, const BrotliEncoderParams* params, + Hasher* hasher, int* dist_cache, size_t* last_insert_len, Command* commands, size_t* num_commands, size_t* num_literals) { - ZopfliNode* nodes; - nodes = BROTLI_ALLOC(m, ZopfliNode, num_bytes + 1); - if (BROTLI_IS_OOM(m)) return; + ZopfliNode* nodes = BROTLI_ALLOC(m, ZopfliNode, num_bytes + 1); + if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(nodes)) return; BrotliInitZopfliNodes(nodes, num_bytes + 1); *num_commands += BrotliZopfliComputeShortestPath(m, num_bytes, - position, ringbuffer, ringbuffer_mask, params, + position, ringbuffer, ringbuffer_mask, literal_context_lut, params, dist_cache, hasher, nodes); if (BROTLI_IS_OOM(m)) return; BrotliZopfliCreateCommands(num_bytes, position, nodes, dist_cache, @@ -728,9 +738,10 @@ void BrotliCreateZopfliBackwardReferences(MemoryManager* m, size_t num_bytes, void BrotliCreateHqZopfliBackwardReferences(MemoryManager* m, size_t num_bytes, size_t position, const uint8_t* ringbuffer, size_t ringbuffer_mask, - const BrotliEncoderParams* params, - HasherHandle hasher, int* dist_cache, size_t* last_insert_len, + ContextLut literal_context_lut, const BrotliEncoderParams* params, + Hasher* hasher, int* dist_cache, size_t* last_insert_len, Command* commands, size_t* num_commands, size_t* num_literals) { + const size_t stream_offset = params->stream_offset; const size_t max_backward_limit = BROTLI_MAX_BACKWARD_LIMIT(params->lgwin); uint32_t* num_matches = BROTLI_ALLOC(m, uint32_t, num_bytes); size_t matches_size = 4 * num_bytes; @@ -747,10 +758,16 @@ void BrotliCreateHqZopfliBackwardReferences(MemoryManager* m, size_t num_bytes, BackwardMatch* matches = BROTLI_ALLOC(m, BackwardMatch, matches_size); size_t gap = 0; size_t shadow_matches = 0; - if (BROTLI_IS_OOM(m)) return; + BROTLI_UNUSED(literal_context_lut); + if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(num_matches) || + BROTLI_IS_NULL(matches)) { + return; + } for (i = 0; i + HashTypeLengthH10() - 1 < num_bytes; ++i) { const size_t pos = position + i; size_t max_distance = BROTLI_MIN(size_t, pos, max_backward_limit); + size_t dictionary_start = BROTLI_MIN(size_t, + pos + stream_offset, max_backward_limit); size_t max_length = num_bytes - i; size_t num_found_matches; size_t cur_match_end; @@ -759,10 +776,10 @@ void BrotliCreateHqZopfliBackwardReferences(MemoryManager* m, size_t num_bytes, BROTLI_ENSURE_CAPACITY(m, BackwardMatch, matches, matches_size, cur_match_pos + MAX_NUM_MATCHES_H10 + shadow_matches); if (BROTLI_IS_OOM(m)) return; - num_found_matches = FindAllMatchesH10(hasher, + num_found_matches = FindAllMatchesH10(&hasher->privat._H10, ¶ms->dictionary, ringbuffer, ringbuffer_mask, pos, max_length, - max_distance, gap, params, + max_distance, dictionary_start + gap, params, &matches[cur_match_pos + shadow_matches]); cur_match_end = cur_match_pos + num_found_matches; for (j = cur_match_pos; j + 1 < cur_match_end; ++j) { @@ -777,7 +794,8 @@ void BrotliCreateHqZopfliBackwardReferences(MemoryManager* m, size_t num_bytes, matches[cur_match_pos++] = matches[cur_match_end - 1]; num_matches[i] = 1; /* Add the tail of the copy to the hasher. */ - StoreRangeH10(hasher, ringbuffer, ringbuffer_mask, pos + 1, + StoreRangeH10(&hasher->privat._H10, + ringbuffer, ringbuffer_mask, pos + 1, BROTLI_MIN(size_t, pos + match_len, store_end)); memset(&num_matches[i + 1], 0, skip * sizeof(num_matches[0])); i += skip; @@ -791,7 +809,7 @@ void BrotliCreateHqZopfliBackwardReferences(MemoryManager* m, size_t num_bytes, memcpy(orig_dist_cache, dist_cache, 4 * sizeof(dist_cache[0])); orig_num_commands = *num_commands; nodes = BROTLI_ALLOC(m, ZopfliNode, num_bytes + 1); - if (BROTLI_IS_OOM(m)) return; + if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(nodes)) return; InitZopfliCostModel(m, &model, ¶ms->dist, num_bytes); if (BROTLI_IS_OOM(m)) return; for (i = 0; i < 2; i++) { diff --git a/modules/brotli/enc/backward_references_hq.h b/modules/brotli/enc/backward_references_hq.h index 1e4275d403..36b75f250d 100644 --- a/modules/brotli/enc/backward_references_hq.h +++ b/modules/brotli/enc/backward_references_hq.h @@ -10,6 +10,7 @@ #define BROTLI_ENC_BACKWARD_REFERENCES_HQ_H_ #include "../common/constants.h" +#include "../common/context.h" #include "../common/dictionary.h" #include "../common/platform.h" #include @@ -23,15 +24,17 @@ extern "C" { #endif BROTLI_INTERNAL void BrotliCreateZopfliBackwardReferences(MemoryManager* m, - size_t num_bytes, size_t position, const uint8_t* ringbuffer, - size_t ringbuffer_mask, const BrotliEncoderParams* params, - HasherHandle hasher, int* dist_cache, size_t* last_insert_len, + size_t num_bytes, + size_t position, const uint8_t* ringbuffer, size_t ringbuffer_mask, + ContextLut literal_context_lut, const BrotliEncoderParams* params, + Hasher* hasher, int* dist_cache, size_t* last_insert_len, Command* commands, size_t* num_commands, size_t* num_literals); BROTLI_INTERNAL void BrotliCreateHqZopfliBackwardReferences(MemoryManager* m, - size_t num_bytes, size_t position, const uint8_t* ringbuffer, - size_t ringbuffer_mask, const BrotliEncoderParams* params, - HasherHandle hasher, int* dist_cache, size_t* last_insert_len, + size_t num_bytes, + size_t position, const uint8_t* ringbuffer, size_t ringbuffer_mask, + ContextLut literal_context_lut, const BrotliEncoderParams* params, + Hasher* hasher, int* dist_cache, size_t* last_insert_len, Command* commands, size_t* num_commands, size_t* num_literals); typedef struct ZopfliNode { @@ -77,8 +80,8 @@ BROTLI_INTERNAL void BrotliInitZopfliNodes(ZopfliNode* array, size_t length); BROTLI_INTERNAL size_t BrotliZopfliComputeShortestPath( MemoryManager* m, size_t num_bytes, size_t position, const uint8_t* ringbuffer, size_t ringbuffer_mask, - const BrotliEncoderParams* params, - const int* dist_cache, HasherHandle hasher, ZopfliNode* nodes); + ContextLut literal_context_lut, const BrotliEncoderParams* params, + const int* dist_cache, Hasher* hasher, ZopfliNode* nodes); BROTLI_INTERNAL void BrotliZopfliCreateCommands( const size_t num_bytes, const size_t block_start, const ZopfliNode* nodes, diff --git a/modules/brotli/enc/backward_references_inc.h b/modules/brotli/enc/backward_references_inc.h index c18cdb00cb..766bf91ffd 100644 --- a/modules/brotli/enc/backward_references_inc.h +++ b/modules/brotli/enc/backward_references_inc.h @@ -10,11 +10,13 @@ static BROTLI_NOINLINE void EXPORT_FN(CreateBackwardReferences)( size_t num_bytes, size_t position, const uint8_t* ringbuffer, size_t ringbuffer_mask, - const BrotliEncoderParams* params, - HasherHandle hasher, int* dist_cache, size_t* last_insert_len, + ContextLut literal_context_lut, const BrotliEncoderParams* params, + Hasher* hasher, int* dist_cache, size_t* last_insert_len, Command* commands, size_t* num_commands, size_t* num_literals) { + HASHER()* privat = &hasher->privat.FN(_); /* Set maximum distance, see section 9.1. of the spec. */ const size_t max_backward_limit = BROTLI_MAX_BACKWARD_LIMIT(params->lgwin); + const size_t position_offset = params->stream_offset; const Command* const orig_commands = commands; size_t insert_length = *last_insert_len; @@ -31,19 +33,23 @@ static BROTLI_NOINLINE void EXPORT_FN(CreateBackwardReferences)( /* Minimum score to accept a backward reference. */ const score_t kMinScore = BROTLI_SCORE_BASE + 100; - FN(PrepareDistanceCache)(hasher, dist_cache); + BROTLI_UNUSED(literal_context_lut); + + FN(PrepareDistanceCache)(privat, dist_cache); while (position + FN(HashTypeLength)() < pos_end) { size_t max_length = pos_end - position; size_t max_distance = BROTLI_MIN(size_t, position, max_backward_limit); + size_t dictionary_start = BROTLI_MIN(size_t, + position + position_offset, max_backward_limit); HasherSearchResult sr; sr.len = 0; sr.len_code_delta = 0; sr.distance = 0; sr.score = kMinScore; - FN(FindLongestMatch)(hasher, ¶ms->dictionary, + FN(FindLongestMatch)(privat, ¶ms->dictionary, ringbuffer, ringbuffer_mask, dist_cache, position, max_length, - max_distance, gap, params->dist.max_distance, &sr); + max_distance, dictionary_start + gap, params->dist.max_distance, &sr); if (sr.score > kMinScore) { /* Found a match. Let's look for something even better ahead. */ int delayed_backward_references_in_row = 0; @@ -57,10 +63,13 @@ static BROTLI_NOINLINE void EXPORT_FN(CreateBackwardReferences)( sr2.distance = 0; sr2.score = kMinScore; max_distance = BROTLI_MIN(size_t, position + 1, max_backward_limit); - FN(FindLongestMatch)(hasher, + dictionary_start = BROTLI_MIN(size_t, + position + 1 + position_offset, max_backward_limit); + FN(FindLongestMatch)(privat, ¶ms->dictionary, ringbuffer, ringbuffer_mask, dist_cache, position + 1, max_length, - max_distance, gap, params->dist.max_distance, &sr2); + max_distance, dictionary_start + gap, params->dist.max_distance, + &sr2); if (sr2.score >= sr.score + cost_diff_lazy) { /* Ok, let's just write one byte for now and start a match from the next byte. */ @@ -76,18 +85,19 @@ static BROTLI_NOINLINE void EXPORT_FN(CreateBackwardReferences)( } apply_random_heuristics = position + 2 * sr.len + random_heuristics_window_size; - max_distance = BROTLI_MIN(size_t, position, max_backward_limit); + dictionary_start = BROTLI_MIN(size_t, + position + position_offset, max_backward_limit); { /* The first 16 codes are special short-codes, and the minimum offset is 1. */ size_t distance_code = ComputeDistanceCode( - sr.distance, max_distance + gap, dist_cache); - if ((sr.distance <= (max_distance + gap)) && distance_code > 0) { + sr.distance, dictionary_start + gap, dist_cache); + if ((sr.distance <= (dictionary_start + gap)) && distance_code > 0) { dist_cache[3] = dist_cache[2]; dist_cache[2] = dist_cache[1]; dist_cache[1] = dist_cache[0]; dist_cache[0] = (int)sr.distance; - FN(PrepareDistanceCache)(hasher, dist_cache); + FN(PrepareDistanceCache)(privat, dist_cache); } InitCommand(commands++, ¶ms->dist, insert_length, sr.len, sr.len_code_delta, distance_code); @@ -105,7 +115,7 @@ static BROTLI_NOINLINE void EXPORT_FN(CreateBackwardReferences)( range_start = BROTLI_MIN(size_t, range_end, BROTLI_MAX(size_t, range_start, position + sr.len - (sr.distance << 2))); } - FN(StoreRange)(hasher, ringbuffer, ringbuffer_mask, range_start, + FN(StoreRange)(privat, ringbuffer, ringbuffer_mask, range_start, range_end); } position += sr.len; @@ -131,7 +141,7 @@ static BROTLI_NOINLINE void EXPORT_FN(CreateBackwardReferences)( size_t pos_jump = BROTLI_MIN(size_t, position + 16, pos_end - kMargin); for (; position < pos_jump; position += 4) { - FN(Store)(hasher, ringbuffer, ringbuffer_mask, position); + FN(Store)(privat, ringbuffer, ringbuffer_mask, position); insert_length += 4; } } else { @@ -140,7 +150,7 @@ static BROTLI_NOINLINE void EXPORT_FN(CreateBackwardReferences)( size_t pos_jump = BROTLI_MIN(size_t, position + 8, pos_end - kMargin); for (; position < pos_jump; position += 2) { - FN(Store)(hasher, ringbuffer, ringbuffer_mask, position); + FN(Store)(privat, ringbuffer, ringbuffer_mask, position); insert_length += 2; } } diff --git a/modules/brotli/enc/block_splitter.c b/modules/brotli/enc/block_splitter.c index d308eca59d..deb7c2e151 100644 --- a/modules/brotli/enc/block_splitter.c +++ b/modules/brotli/enc/block_splitter.c @@ -132,7 +132,7 @@ void BrotliSplitBlock(MemoryManager* m, { size_t literals_count = CountLiterals(cmds, num_commands); uint8_t* literals = BROTLI_ALLOC(m, uint8_t, literals_count); - if (BROTLI_IS_OOM(m)) return; + if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(literals)) return; /* Create a continuous array of literals. */ CopyLiteralsToByteArray(cmds, num_commands, data, pos, mask, literals); /* Create the block split on the array of literals. @@ -150,7 +150,7 @@ void BrotliSplitBlock(MemoryManager* m, /* Compute prefix codes for commands. */ uint16_t* insert_and_copy_codes = BROTLI_ALLOC(m, uint16_t, num_commands); size_t i; - if (BROTLI_IS_OOM(m)) return; + if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(insert_and_copy_codes)) return; for (i = 0; i < num_commands; ++i) { insert_and_copy_codes[i] = cmds[i].cmd_prefix_; } @@ -170,7 +170,7 @@ void BrotliSplitBlock(MemoryManager* m, uint16_t* distance_prefixes = BROTLI_ALLOC(m, uint16_t, num_commands); size_t j = 0; size_t i; - if (BROTLI_IS_OOM(m)) return; + if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(distance_prefixes)) return; for (i = 0; i < num_commands; ++i) { const Command* cmd = &cmds[i]; if (CommandCopyLen(cmd) && cmd->cmd_prefix_ >= 128) { diff --git a/modules/brotli/enc/block_splitter_inc.h b/modules/brotli/enc/block_splitter_inc.h index 023712b84d..e612d6a370 100644 --- a/modules/brotli/enc/block_splitter_inc.h +++ b/modules/brotli/enc/block_splitter_inc.h @@ -219,7 +219,12 @@ static void FN(ClusterBlocks)(MemoryManager* m, uint32_t symbols[HISTOGRAMS_PER_BATCH] = { 0 }; uint32_t remap[HISTOGRAMS_PER_BATCH] = { 0 }; - if (BROTLI_IS_OOM(m)) return; + if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(histogram_symbols) || + BROTLI_IS_NULL(block_lengths) || BROTLI_IS_NULL(all_histograms) || + BROTLI_IS_NULL(cluster_size) || BROTLI_IS_NULL(histograms) || + BROTLI_IS_NULL(pairs)) { + return; + } memset(block_lengths, 0, num_blocks * sizeof(uint32_t)); @@ -278,11 +283,11 @@ static void FN(ClusterBlocks)(MemoryManager* m, if (pairs_capacity < max_num_pairs + 1) { BROTLI_FREE(m, pairs); pairs = BROTLI_ALLOC(m, HistogramPair, max_num_pairs + 1); - if (BROTLI_IS_OOM(m)) return; + if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(pairs)) return; } clusters = BROTLI_ALLOC(m, uint32_t, num_clusters); - if (BROTLI_IS_OOM(m)) return; + if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(clusters)) return; for (i = 0; i < num_clusters; ++i) { clusters[i] = (uint32_t)i; } @@ -294,7 +299,7 @@ static void FN(ClusterBlocks)(MemoryManager* m, BROTLI_FREE(m, cluster_size); new_index = BROTLI_ALLOC(m, uint32_t, num_clusters); - if (BROTLI_IS_OOM(m)) return; + if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(new_index)) return; for (i = 0; i < num_clusters; ++i) new_index[i] = kInvalidIndex; pos = 0; { @@ -386,7 +391,7 @@ static void FN(SplitByteVector)(MemoryManager* m, return; } histograms = BROTLI_ALLOC(m, HistogramType, num_histograms); - if (BROTLI_IS_OOM(m)) return; + if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(histograms)) return; /* Find good entropy codes. */ FN(InitialEntropyCodes)(data, length, sampling_stride_length, @@ -405,7 +410,11 @@ static void FN(SplitByteVector)(MemoryManager* m, uint16_t* new_id = BROTLI_ALLOC(m, uint16_t, num_histograms); const size_t iters = params->quality < HQ_ZOPFLIFICATION_QUALITY ? 3 : 10; size_t i; - if (BROTLI_IS_OOM(m)) return; + if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(block_ids) || + BROTLI_IS_NULL(insert_cost) || BROTLI_IS_NULL(cost) || + BROTLI_IS_NULL(switch_signal) || BROTLI_IS_NULL(new_id)) { + return; + } for (i = 0; i < iters; ++i) { num_blocks = FN(FindBlocks)(data, length, block_switch_cost, diff --git a/modules/brotli/enc/brotli_bit_stream.c b/modules/brotli/enc/brotli_bit_stream.c index aaf2dad7db..9348a97e1b 100644 --- a/modules/brotli/enc/brotli_bit_stream.c +++ b/modules/brotli/enc/brotli_bit_stream.c @@ -34,33 +34,18 @@ extern "C" { BROTLI_DISTANCE_ALPHABET_SIZE(0, 0, BROTLI_LARGE_MAX_DISTANCE_BITS) /* MAX_SIMPLE_DISTANCE_ALPHABET_SIZE == 140 */ -/* Represents the range of values belonging to a prefix code: - [offset, offset + 2^nbits) */ -typedef struct PrefixCodeRange { - uint32_t offset; - uint32_t nbits; -} PrefixCodeRange; - -static const PrefixCodeRange - kBlockLengthPrefixCode[BROTLI_NUM_BLOCK_LEN_SYMBOLS] = { - { 1, 2}, { 5, 2}, { 9, 2}, {13, 2}, {17, 3}, { 25, 3}, { 33, 3}, - {41, 3}, {49, 4}, {65, 4}, {81, 4}, {97, 4}, {113, 5}, {145, 5}, - {177, 5}, { 209, 5}, { 241, 6}, { 305, 6}, { 369, 7}, { 497, 8}, - {753, 9}, {1265, 10}, {2289, 11}, {4337, 12}, {8433, 13}, {16625, 24} -}; - static BROTLI_INLINE uint32_t BlockLengthPrefixCode(uint32_t len) { uint32_t code = (len >= 177) ? (len >= 753 ? 20 : 14) : (len >= 41 ? 7 : 0); while (code < (BROTLI_NUM_BLOCK_LEN_SYMBOLS - 1) && - len >= kBlockLengthPrefixCode[code + 1].offset) ++code; + len >= _kBrotliPrefixCodeRanges[code + 1].offset) ++code; return code; } static BROTLI_INLINE void GetBlockLengthPrefixCode(uint32_t len, size_t* code, uint32_t* n_extra, uint32_t* extra) { *code = BlockLengthPrefixCode(len); - *n_extra = kBlockLengthPrefixCode[*code].nbits; - *extra = len - kBlockLengthPrefixCode[*code].offset; + *n_extra = _kBrotliPrefixCodeRanges[*code].nbits; + *extra = len - _kBrotliPrefixCodeRanges[*code].offset; } typedef struct BlockTypeCodeCalculator { @@ -450,7 +435,7 @@ void BrotliBuildAndStoreHuffmanTreeFast(MemoryManager* m, const size_t max_tree_size = 2 * length + 1; HuffmanTree* tree = BROTLI_ALLOC(m, HuffmanTree, max_tree_size); uint32_t count_limit; - if (BROTLI_IS_OOM(m)) return; + if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(tree)) return; for (count_limit = 1; ; count_limit *= 2) { HuffmanTree* node = tree; size_t l; @@ -714,7 +699,7 @@ static void EncodeContextMap(MemoryManager* m, } rle_symbols = BROTLI_ALLOC(m, uint32_t, context_map_size); - if (BROTLI_IS_OOM(m)) return; + if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(rle_symbols)) return; MoveToFrontTransform(context_map, context_map_size, rle_symbols); RunLengthCodeZeros(context_map_size, rle_symbols, &num_rle_symbols, &max_run_length_prefix); @@ -956,23 +941,21 @@ void BrotliStoreMetaBlock(MemoryManager* m, size_t pos = start_pos; size_t i; - uint32_t num_distance_symbols = params->dist.alphabet_size; - uint32_t num_effective_distance_symbols = num_distance_symbols; + uint32_t num_distance_symbols = params->dist.alphabet_size_max; + uint32_t num_effective_distance_symbols = params->dist.alphabet_size_limit; HuffmanTree* tree; ContextLut literal_context_lut = BROTLI_CONTEXT_LUT(literal_context_mode); BlockEncoder literal_enc; BlockEncoder command_enc; BlockEncoder distance_enc; const BrotliDistanceParams* dist = ¶ms->dist; - if (params->large_window && - num_effective_distance_symbols > BROTLI_NUM_HISTOGRAM_DISTANCE_SYMBOLS) { - num_effective_distance_symbols = BROTLI_NUM_HISTOGRAM_DISTANCE_SYMBOLS; - } + BROTLI_DCHECK( + num_effective_distance_symbols <= BROTLI_NUM_HISTOGRAM_DISTANCE_SYMBOLS); StoreCompressedMetaBlockHeader(is_last, length, storage_ix, storage); tree = BROTLI_ALLOC(m, HuffmanTree, MAX_HUFFMAN_TREE_SIZE); - if (BROTLI_IS_OOM(m)) return; + if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(tree)) return; InitBlockEncoder(&literal_enc, BROTLI_NUM_LITERAL_SYMBOLS, mb->literal_split.num_types, mb->literal_split.types, mb->literal_split.lengths, mb->literal_split.num_blocks); @@ -1163,7 +1146,7 @@ void BrotliStoreMetaBlockTrivial(MemoryManager* m, uint8_t dist_depth[MAX_SIMPLE_DISTANCE_ALPHABET_SIZE]; uint16_t dist_bits[MAX_SIMPLE_DISTANCE_ALPHABET_SIZE]; HuffmanTree* tree; - uint32_t num_distance_symbols = params->dist.alphabet_size; + uint32_t num_distance_symbols = params->dist.alphabet_size_max; StoreCompressedMetaBlockHeader(is_last, length, storage_ix, storage); @@ -1177,7 +1160,7 @@ void BrotliStoreMetaBlockTrivial(MemoryManager* m, BrotliWriteBits(13, 0, storage_ix, storage); tree = BROTLI_ALLOC(m, HuffmanTree, MAX_HUFFMAN_TREE_SIZE); - if (BROTLI_IS_OOM(m)) return; + if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(tree)) return; BuildAndStoreHuffmanTree(lit_histo.data_, BROTLI_NUM_LITERAL_SYMBOLS, BROTLI_NUM_LITERAL_SYMBOLS, tree, lit_depth, lit_bits, @@ -1206,7 +1189,7 @@ void BrotliStoreMetaBlockFast(MemoryManager* m, BROTLI_BOOL is_last, const BrotliEncoderParams* params, const Command* commands, size_t n_commands, size_t* storage_ix, uint8_t* storage) { - uint32_t num_distance_symbols = params->dist.alphabet_size; + uint32_t num_distance_symbols = params->dist.alphabet_size_max; uint32_t distance_alphabet_bits = Log2FloorNonZero(num_distance_symbols - 1) + 1; diff --git a/modules/brotli/enc/cluster_inc.h b/modules/brotli/enc/cluster_inc.h index 22ecb3cca8..3d4f40e601 100644 --- a/modules/brotli/enc/cluster_inc.h +++ b/modules/brotli/enc/cluster_inc.h @@ -215,7 +215,7 @@ BROTLI_INTERNAL size_t FN(BrotliHistogramReindex)(MemoryManager* m, uint32_t next_index; HistogramType* tmp; size_t i; - if (BROTLI_IS_OOM(m)) return 0; + if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(new_index)) return 0; for (i = 0; i < length; ++i) { new_index[i] = kInvalidIndex; } @@ -229,7 +229,7 @@ BROTLI_INTERNAL size_t FN(BrotliHistogramReindex)(MemoryManager* m, /* TODO: by using idea of "cycle-sort" we can avoid allocation of tmp and reduce the number of copying by the factor of 2. */ tmp = BROTLI_ALLOC(m, HistogramType, next_index); - if (BROTLI_IS_OOM(m)) return 0; + if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(tmp)) return 0; next_index = 0; for (i = 0; i < length; ++i) { if (new_index[symbols[i]] == next_index) { @@ -259,7 +259,10 @@ BROTLI_INTERNAL void FN(BrotliClusterHistograms)( HistogramPair* pairs = BROTLI_ALLOC(m, HistogramPair, pairs_capacity + 1); size_t i; - if (BROTLI_IS_OOM(m)) return; + if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(cluster_size) || + BROTLI_IS_NULL(clusters) || BROTLI_IS_NULL(pairs)) { + return; + } for (i = 0; i < in_size; ++i) { cluster_size[i] = 1; diff --git a/modules/brotli/enc/command.c b/modules/brotli/enc/command.c new file mode 100644 index 0000000000..5e6c249196 --- /dev/null +++ b/modules/brotli/enc/command.c @@ -0,0 +1,28 @@ +/* Copyright 2013 Google Inc. All Rights Reserved. + + Distributed under MIT license. + See file LICENSE for detail or copy at https://opensource.org/licenses/MIT +*/ + +#include "./command.h" + +#include + +#if defined(__cplusplus) || defined(c_plusplus) +extern "C" { +#endif + +const uint32_t kBrotliInsBase[BROTLI_NUM_INS_COPY_CODES] = { + 0, 1, 2, 3, 4, 5, 6, 8, 10, 14, 18, 26, + 34, 50, 66, 98, 130, 194, 322, 578, 1090, 2114, 6210, 22594}; +const uint32_t kBrotliInsExtra[BROTLI_NUM_INS_COPY_CODES] = { + 0, 0, 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 7, 8, 9, 10, 12, 14, 24}; +const uint32_t kBrotliCopyBase[BROTLI_NUM_INS_COPY_CODES] = { + 2, 3, 4, 5, 6, 7, 8, 9, 10, 12, 14, 18, + 22, 30, 38, 54, 70, 102, 134, 198, 326, 582, 1094, 2118}; +const uint32_t kBrotliCopyExtra[BROTLI_NUM_INS_COPY_CODES] = { + 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 7, 8, 9, 10, 24}; + +#if defined(__cplusplus) || defined(c_plusplus) +} /* extern "C" */ +#endif diff --git a/modules/brotli/enc/command.h b/modules/brotli/enc/command.h index 1aac85689b..d84e373d00 100644 --- a/modules/brotli/enc/command.h +++ b/modules/brotli/enc/command.h @@ -20,14 +20,14 @@ extern "C" { #endif -static uint32_t kInsBase[] = { 0, 1, 2, 3, 4, 5, 6, 8, 10, 14, 18, 26, 34, 50, - 66, 98, 130, 194, 322, 578, 1090, 2114, 6210, 22594 }; -static uint32_t kInsExtra[] = { 0, 0, 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, - 5, 5, 6, 7, 8, 9, 10, 12, 14, 24 }; -static uint32_t kCopyBase[] = { 2, 3, 4, 5, 6, 7, 8, 9, 10, 12, 14, 18, 22, 30, - 38, 54, 70, 102, 134, 198, 326, 582, 1094, 2118 }; -static uint32_t kCopyExtra[] = { 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, - 4, 4, 5, 5, 6, 7, 8, 9, 10, 24 }; +BROTLI_INTERNAL extern const uint32_t + kBrotliInsBase[BROTLI_NUM_INS_COPY_CODES]; +BROTLI_INTERNAL extern const uint32_t + kBrotliInsExtra[BROTLI_NUM_INS_COPY_CODES]; +BROTLI_INTERNAL extern const uint32_t + kBrotliCopyBase[BROTLI_NUM_INS_COPY_CODES]; +BROTLI_INTERNAL extern const uint32_t + kBrotliCopyExtra[BROTLI_NUM_INS_COPY_CODES]; static BROTLI_INLINE uint16_t GetInsertLengthCode(size_t insertlen) { if (insertlen < 6) { @@ -89,19 +89,19 @@ static BROTLI_INLINE void GetLengthCode(size_t insertlen, size_t copylen, } static BROTLI_INLINE uint32_t GetInsertBase(uint16_t inscode) { - return kInsBase[inscode]; + return kBrotliInsBase[inscode]; } static BROTLI_INLINE uint32_t GetInsertExtra(uint16_t inscode) { - return kInsExtra[inscode]; + return kBrotliInsExtra[inscode]; } static BROTLI_INLINE uint32_t GetCopyBase(uint16_t copycode) { - return kCopyBase[copycode]; + return kBrotliCopyBase[copycode]; } static BROTLI_INLINE uint32_t GetCopyExtra(uint16_t copycode) { - return kCopyExtra[copycode]; + return kBrotliCopyExtra[copycode]; } typedef struct Command { diff --git a/modules/brotli/enc/compress_fragment_two_pass.c b/modules/brotli/enc/compress_fragment_two_pass.c index f8a5606384..ca68b38139 100644 --- a/modules/brotli/enc/compress_fragment_two_pass.c +++ b/modules/brotli/enc/compress_fragment_two_pass.c @@ -524,7 +524,7 @@ static void StoreCommands(MemoryManager* m, static BROTLI_BOOL ShouldCompress( const uint8_t* input, size_t input_size, size_t num_literals) { double corpus_size = (double)input_size; - if (num_literals < MIN_RATIO * corpus_size) { + if ((double)num_literals < MIN_RATIO * corpus_size) { return BROTLI_TRUE; } else { uint32_t literal_histo[256] = { 0 }; diff --git a/modules/brotli/enc/dictionary_hash.c b/modules/brotli/enc/dictionary_hash.c index 3677d7ddb4..16d853fe5a 100644 --- a/modules/brotli/enc/dictionary_hash.c +++ b/modules/brotli/enc/dictionary_hash.c @@ -13,1107 +13,1833 @@ extern "C" { #endif -BROTLI_INTERNAL const uint16_t kStaticDictionaryHash[32768] = { -32072,0,0,0,0,0,0,0,0,21860,0,0,0,0,0,0,0,40486,0,0,0,0,0,45798,0,0,0,0,0,0,1292 -,0,0,0,0,4964,278,23717,0,19972,0,0,0,0,0,0,0,0,0,0,0,0,2126,16102,0,0,0,14437,0 -,0,0,0,0,0,0,26727,2253,0,0,17252,0,0,0,0,0,0,0,0,0,3622,0,0,0,0,22984,0,0,0,0,0 -,0,16647,0,34247,0,0,0,0,0,48486,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2511,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,19532,0,0,24004,0,0,0,9828,0 -,0,0,0,0,0,0,0,0,0,0,0,0,0,0,30853,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 -,0,0,0,0,0,0,0,0,0,0,31974,0,0,0,0,0,0,0,0,20650,2404,0,20773,1677,9031,0,6404,0 -,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,51879,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6761,7206 -,0,0,21992,22983,0,0,3529,0,1864,0,0,0,0,0,0,11046,0,0,9641,0,0,0,6507,0,0,36934 -,21576,62375,0,0,0,0,0,0,0,0,0,8294,0,0,0,0,0,0,0,40807,0,0,0,39398,8136,0,0,0,0 -,0,0,0,8875,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7941,0,0,25609,0,0,0,936, -3716,3213,15687,0,0,0,0,0,52519,0,17381,0,0,0,0,1320,5797,0,21029,0,0,6472,807,0 -,0,0,0,0,0,0,0,0,0,13545,0,0,0,3624,0,0,0,29674,30820,0,31237,0,6596,0,0,0,0,0,0 -,0,0,0,64070,0,0,0,0,0,0,0,0,0,0,0,22278,0,37446,0,0,0,0,7240,423,0,24612,21705, -17636,0,0,0,0,0,0,1833,0,0,0,328,6021,0,0,0,19974,0,0,0,0,0,0,0,0,0,62119,4178,0 -,0,0,0,12100,8617,0,0,16900,0,36678,0,0,0,35366,0,51718,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,20998,0,62086,0,0,0,0,0,5542,0,0,0,0,0,0,0,0,0,0,0,14629,10952,25927,0,0,0 -,0,19849,0,0,0,0,0,0,0,30952,3046,14314,12998,0,0,0,15268,0,40582,30216,62118,0, -0,0,20132,0,0,0,0,0,12005,0,0,0,52358,0,0,0,0,24778,0,44,33095,0,0,0,0,0,26372,0 -,0,0,0,0,3781,0,0,17928,9479,0,0,0,0,0,0,0,0,32297,28613,0,0,0,0,0,0,0,0,0,0,0,0 -,0,47174,11723,0,0,0,0,0,0,0,0,0,2536,55143,0,0,6410,0,0,0,0,0,0,0,0,56294,11914 -,0,529,0,30184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8261,0,0,28808,58854,22633, -965,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,64135,0,0,331,3684,0,1605,0,0,0,0,0,0, -0,0,0,0,16650,37,0,23622,3144,15429,0,0,0,0,0,0,0,0,0,0,22443,69,0,0,0,0,0,0,0,0 -,17832,0,0,0,0,0,0,0,0,0,11113,0,0,0,0,18309,0,0,0,0,0,0,0,0,0,26630,0,0,25512, -25895,0,0,0,0,0,0,0,0,0,0,0,16901,0,0,0,27558,0,0,9418,0,0,0,3508,0,0,0,0,0,0,0, -0,37990,9289,8517,0,0,0,0,1578,1604,23944,0,0,14916,12781,0,0,0,0,0,0,0,12105,0, -16617,0,0,0,0,0,0,0,0,0,0,0,0,21348,11240,28870,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,5772,0,0,27812,0,0,0,0,0,0,0,8324,0,0,0,0,0,0,0,0,0,0,16748,1157,0,0,18794, -16324,25898,935,8333,0,0,0,0,0,0,0,0,18246,0,18086,0,46854,0,0,0,0,0,0,339,0,0, -25188,12780,12166,6409,0,0,0,0,16516,0,27012,28395,0,0,0,0,0,0,0,1420,0,0,0,9768 -,52967,0,0,0,0,0,0,0,0,0,0,0,0,0,0,25163,324,0,0,0,0,0,0,0,0,0,64998,0,0,0,0,0, -21893,0,0,0,0,0,47366,0,0,0,870,0,0,0,12646,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,26020,16360,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1809,0,0,0,6601,15878,0,0,0,0,0, -29092,0,28516,0,0,0,0,0,0,0,0,0,21988,0,0,0,42950,0,0,0,0,0,0,0,0,0,0,5133,1318, -0,0,0,0,0,0,0,0,0,0,0,54982,24904,0,0,0,0,0,0,0,0,0,0,51526,0,0,0,0,0,3685,0,0,0 -,0,10062,9412,0,0,0,31460,5708,6181,0,0,0,0,0,0,0,0,0,5575,0,0,0,0,0,0,0,0,0,0, -27144,57478,0,0,0,0,0,0,7084,0,21993,53126,0,0,0,0,8397,0,0,5733,0,0,0,0,0,2116, -0,24742,0,11271,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1133,0,4873,0,0,38310,0,0,0,0,0, -0,0,0,0,0,0,0,17932,0,0,18053,0,0,0,25510,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,17798,0, -26214,0,0,0,0,0,0,0,0,23016,17415,20392,164,0,0,0,0,0,0,0,0,0,0,0,3239,0,46119,0 -,0,0,28580,0,0,0,0,0,0,0,0,0,7621,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,41478,0,0,31016, -55334,10056,1924,0,0,0,0,0,36614,0,36711,0,0,0,0,0,0,0,0,0,0,13994,59303,0,0,0,0 -,0,0,0,0,0,0,0,0,0,0,0,26501,0,5639,0,0,0,0,0,0,13897,1253,0,0,0,0,0,5095,0,0,0, -28869,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8646,0,0,0,0,25641,17796,0,0,0,0,0,0,0, -13316,620,6309,11819,0,0,0,0,0,0,0,0,0,904,1095,0,24229,0,0,28744,49703,0,23077, -0,0,0,0,32392,0,0,0,0,35271,0,28740,5866,0,0,0,0,0,0,0,4361,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7917,8869,0,0,0,13924,0,0,0,0, -0,41958,0,0,0,0,0,0,6766,13989,0,0,0,903,0,0,24010,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 -,0,0,0,0,0,64390,0,22468,0,25861,0,0,0,0,23656,5317,0,0,0,0,0,0,23017,5445,16009 -,0,0,0,0,0,0,0,0,48006,10473,0,0,14404,0,0,0,42183,0,0,0,51270,0,0,10602,24132,0 -,0,0,0,0,43782,0,0,17834,0,0,0,25576,27205,0,0,0,0,0,0,0,0,29066,0,0,0,0,0,626, -1988,14700,0,0,0,0,0,0,0,0,0,0,0,0,57670,0,0,0,0,0,0,0,0,0,44710,0,0,0,0,3848, -7623,0,0,0,0,0,0,0,0,0,0,0,42374,0,0,0,0,0,0,0,0,19272,6436,0,0,5256,0,0,0,0,0,0 -,0,0,0,0,0,0,0,0,19685,0,0,0,0,0,0,0,0,0,0,0,0,0,39783,0,0,0,0,30984,0,0,0,0,0,0 -,28230,0,0,0,29028,10538,3205,0,0,0,0,0,0,0,0,0,0,0,5636,840,295,0,0,8488,8198,0 -,0,0,0,0,0,0,0,0,20580,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4074,19526,0,0,0,0, -31144,64038,0,0,0,0,0,0,16716,0,0,0,0,0,0,0,0,0,0,0,17706,0,0,0,0,0,0,50630,0, -50503,0,0,0,0,0,0,0,0,0,0,0,25446,0,0,0,13831,0,0,0,0,0,0,2696,4039,0,0,0,0, -25288,0,12076,2054,0,48934,0,0,0,0,16969,59431,17259,35335,0,0,0,0,0,0,0,0,0,0,0 -,0,31275,0,0,0,1097,0,0,0,0,0,0,0,0,0,0,0,776,839,0,0,29386,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,5864,12134,0,0,0,0,0,0,0,25349,0,0,0,0,0,0,0,0,0,61447 -,0,0,0,0,0,0,0,0,0,24678,0,0,0,63335,0,28836,8142,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4494,0,0,0,0,0,14088,1188,0,16260,0,0,0, -16421,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,276,0,0,17060,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,24076,29445,0,33543,0,4901,0 -,0,12522,0,0,62471,0,0,0,0,0,0,0,0,0,0,4046,0,0,0,0,20486,0,15460,2217,51719,0,0 -,0,0,0,23495,0,0,0,0,0,0,15370,0,15849,0,15113,0,0,0,0,0,0,0,0,27972,7337,0,0,0, -0,30342,0,0,0,0,0,0,0,0,32299,23940,0,17766,0,0,0,0,0,0,6184,0,20904,0,0,0,0,0,0 -,0,0,0,0,31492,0,0,0,5509,0,0,0,0,0,0,0,0,2669,50182,0,0,12299,0,0,0,0,0,0,0, -5257,28167,0,0,0,0,0,0,0,0,0,0,0,11750,3890,0,0,26500,0,0,0,0,0,0,0,49318,0,0,0, -0,0,0,0,10981,0,0,0,0,0,0,0,0,17961,1831,0,0,0,0,0,0,0,29638,0,0,0,0,26473,0, -6216,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,711,0,0,0,0,0,0,0,0,0,0,28683,39975 -,0,0,0,0,0,51654,0,0,0,27527,0,0,0,0,0,0,0,0,30859,3268,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28772,0,18212,0,0,0,0,25448,65446,0,0,0,0, -0,0,3337,1670,0,0,0,0,0,19332,0,0,0,0,24936,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1043,0 -,0,0,0,15814,0,21670,0,0,0,0,0,0,0,16263,0,0,0,0,0,0,0,0,0,32454,0,30630,0,0, -20170,9926,0,0,0,18247,0,0,14376,0,2056,17191,0,0,0,0,0,0,0,7812,0,0,0,0,0,0,0,0 -,0,0,0,0,0,0,22474,52806,1588,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,10825,0, -0,0,0,40934,0,0,0,0,0,0,0,28677,0,0,5714,0,0,0,0,0,0,0,0,0,0,0,0,0,25865,22246,0 -,0,0,0,17256,35751,0,0,0,0,0,0,0,0,8236,0,32108,0,0,0,43,14342,0,16517,0,0,30732 -,0,4012,133,0,40583,971,23942,0,0,27275,0,0,0,204,0,0,27140,7564,44327,27592, -57958,0,0,0,0,22344,25701,0,0,0,0,0,0,0,19524,31755,0,0,28102,0,59111,0,0,0,0,0, -0,0,12261,0,44934,0,0,0,0,31560,0,11114,0,0,0,0,0,0,0,0,0,0,0,18953,18311,0, -45159,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2059,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -19399,0,0,0,0,0,0,0,0,0,0,0,0,0,58534,0,0,0,0,0,0,0,0,0,0,0,0,22411,23943,0,0,0, -0,0,0,11690,0,0,4069,0,0,2668,6342,0,0,0,0,0,0,27658,1766,0,0,0,0,23240,56070,0, -0,0,0,0,0,0,0,0,0,0,0,0,34119,0,24453,0,0,0,0,21867,0,17610,9894,0,0,27976,38790 -,0,0,0,43654,0,31559,12202,23142,0,0,0,50343,0,0,0,0,0,32806,0,0,0,0,0,0,0,0,0,0 -,0,0,0,0,0,0,0,0,0,49895,0,0,0,0,15786,4263,0,0,0,0,4746,3814,0,0,0,0,0,0,17192, -453,17323,0,20328,4036,0,0,0,15844,0,0,0,0,27561,31940,32296,0,0,0,0,0,0,0,11499 -,11782,0,0,0,0,9738,50471,0,0,0,0,0,35430,0,0,0,0,0,29734,0,0,0,36551,0,0,0,0, -9257,5606,0,13829,0,7015,0,0,0,0,0,25127,0,0,19051,0,0,0,0,0,0,0,0,0,0,0,0,0, -2572,0,0,0,0,0,0,29797,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,42342,0,0,0,0,9293, -0,17896,56038,4077,0,0,0,29899,37351,0,30823,0,8326,0,0,0,18342,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,18569,54054,0,0,0,0,0,0,0,0,0,37254,0,0,31433, -61510,0,2022,0,0,0,0,0,25381,0,0,0,0,0,0,0,0,0,0,0,0,0,2149,25289,0,0,0,0,0,0,0, -0,0,0,12516,14185,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8676,0,0,0,0,0 -,0,0,0,0,0,0,36486,0,0,0,0,10889,9607,0,28711,0,0,0,0,0,0,0,0,0,0,28490,0,0,0,0, -26181,10283,1701,0,0,0,0,0,0,0,0,0,14980,0,7783,0,27846,0,0,0,56486,3892,0,0,0, -5770,16583,0,26309,13422,20292,0,0,0,0,0,0,0,0,0,28742,0,0,0,0,14536,1158,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,25801,0,0,0,0,0,0,0,0,0,0,0,0,42438,0,3332,0,0 -,0,0,0,0,0,0,0,8327,0,0,0,0,0,0,0,0,0,0,0,0,17353,1447,0,0,8427,48518,1359,0,0,0 -,0,0,14986,0,32168,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,9230,2791,0,0,0,0,0,0,0,0, -16073,31623,4269,0,0,0,0,0,0,4519,0,0,27912,58950,0,0,0,0,0,0,0,0,8361,19812,0,0 -,0,0,6056,7877,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,21701,0,0,0,0,0,0,0,0,0,0,0 -,0,9128,1125,0,16548,0,0,0,0,0,0,0,0,0,0,17292,6854,21352,0,2380,0,0,4007,0,0,0, -0,0,24357,4202,0,0,0,0,0,0,0,0,0,0,0,0,0,10664,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 -,0,0,0,42823,3022,0,0,0,0,0,0,0,0,0,0,0,0,14373,0,20677,3304,2759,20522,64903,0, -0,0,38,0,0,0,0,0,0,0,0,0,0,0,27814,2802,8870,3758,1255,0,0,0,0,0,0,0,0,30027, -9510,0,0,0,0,17864,14855,0,0,0,0,0,0,0,0,0,0,23404,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -51462,0,0,0,0,0,0,0,45734,0,0,23467,32327,0,0,10826,52999,0,0,0,33222,31336, -64326,0,0,0,0,0,0,0,32166,0,0,3891,0,0,0,7017,645,0,0,0,0,0,0,27915,46087,0,0,0, -21863,0,34246,0,0,16715,0,0,0,0,14052,21416,0,0,0,0,0,0,0,0,39846,0,0,0,0,0, -38982,0,0,17512,7460,0,0,0,0,0,0,0,0,0,15428,0,0,0,0,0,0,0,28356,0,0,0,0,0,0,0,0 -,0,0,0,0,0,0,0,0,0,0,0,25445,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,11879,0,0,0,0,0,0 -,0,0,0,0,0,0,0,19911,0,20007,0,0,0,10855,943,0,0,10821,0,0,0,0,4170,0,0,0,0,0,0, -0,0,0,9836,0,0,0,0,0,0,0,0,0,0,65415,0,0,0,0,0,0,0,0,9865,24646,0,0,0,0,0,40519, -0,0,0,0,0,0,0,0,0,12804,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,22091,23655,0,0,0,0,0,0, -0,31686,0,0,0,58599,0,0,0,0,0,0,0,0,0,0,0,0,0,19620,0,0,0,0,0,0,0,0,0,0,0,0,0, -24421,0,28100,0,0,0,31268,0,3204,0,0,0,0,0,0,0,0,0,14822,0,0,0,0,19947,10182,0,0 -,9480,14821,4398,0,0,14532,0,0,0,48871,1873,0,0,0,0,0,0,0,589,1541,0,0,0,0,0, -23333,0,0,0,14149,0,0,0,0,1296,14374,0,27300,0,0,0,0,0,0,7276,0,0,0,0,0,0,47718, -0,0,0,0,0,0,0,0,0,0,5164,1765,0,14405,0,37574,1994,0,6636,0,0,0,0,0,0,0,0,27815, -0,0,0,0,2568,6820,0,0,0,0,0,0,0,0,0,0,11336,26247,0,0,23912,0,0,0,30536,0,0, -34342,0,17799,0,0,0,22149,0,6118,0,25732,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 -,0,0,0,0,26600,5190,0,0,1142,0,0,0,0,0,0,0,0,39527,0,0,0,0,0,39494,0,0,0,0,0,0,0 -,0,0,0,3085,0,0,0,0,0,0,0,4786,0,0,0,28873,6532,0,0,26664,0,9193,11719,0,0,0,0,0 -,0,31752,64646,0,0,0,0,0,0,0,0,0,0,0,11397,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,25094,0 -,0,18153,20167,0,0,0,17254,0,0,878,0,0,0,0,0,0,0,0,0,0,24166,0,0,0,0,0,0,0,0,0,0 -,0,0,26059,0,0,0,0,0,0,0,0,0,0,0,0,0,31592,0,0,8167,24362,6212,0,34758,0,0,0,0,0 -,0,32520,0,0,44679,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,17989,8681,29222,0,0,0, -0,0,0,0,0,10251,4902,1452,15207,0,0,0,0,0,0,0,22822,0,10469,0,0,0,0,0,0,19337, -17670,107,11494,0,0,0,0,27305,2565,0,0,0,0,0,0,0,64518,200,28389,0,0,0,0,31208,0 -,30762,0,0,0,0,0,29321,60518,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3209,3237, -12490,22663,0,0,0,18789,31464,16391,0,0,0,0,0,0,0,0,0,0,0,20646,0,0,0,27238,0,0, -0,0,0,15940,4488,6951,0,0,0,46342,0,0,0,0,0,0,0,0,0,28965,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,20584,3367,0,25350,0,0,0,0,0,0,0,0,0,0,0,0,1814,0,0,0,0,0,0,0,0,0,0,17125, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,55943,0,0,0,0,0,24133,0,0,0,0,0,0,0,0,0,0,0,0,2929 -,0,0,50086,0,2918,25356,30052,115,11846,0,0,0,0,3056,0,0,0,0,17639,239,19815,0,0 -,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36806,0,0,0,0,0,0,0,0,0,0,0,0,0,21479,0,0,0,0,0, -28420,11786,4772,0,0,3368,36295,0,31463,0,0,14665,996,0,20582,0,0,0,9988,0,23685 -,0,0,0,52551,0,0,0,0,0,0,0,7556,0,0,0,0,0,0,0,1895,2186,0,0,0,0,0,27755,25447,0, -0,0,0,31052,63270,0,0,0,0,0,0,0,36742,0,24804,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,31048,0,0,0,0,0,0,0,0,0,21290,2276,0,0,0,0,26475,0,0,0,0,0,0,0,0,0 -,0,15332,0,0,0,0,0,0,0,0,3176,19431,0,0,0,0,0,0,0,62726,0,0,0,25380,0,0,27883, -1316,0,0,7724,3015,0,0,0,0,6697,0,0,47910,0,0,0,0,0,0,0,0,0,3141,0,0,0,14820,0,0 -,0,0,9326,0,0,0,0,0,0,0,0,0,0,31493,0,0,0,0,0,6566,0,0,0,0,0,0,6569,1348,0,25638 -,0,0,0,0,0,20324,0,0,17067,0,0,0,0,0,0,0,0,0,0,0,0,0,0,11876,0,41030,0,0,0,26405 -,0,0,0,0,0,0,0,0,0,11431,28137,14950,0,10151,0,0,0,0,0,0,0,29574,0,0,0,0,27176, -57446,0,0,0,0,28650,57574,1387,0,0,0,0,0,0,0,0,0,0,58247,0,0,0,0,0,0,0,16805,0,0 -,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3526,0,15781,0,5572,13352,0,0,0,0,0,18665 -,23463,0,0,0,0,0,0,15405,6885,0,0,0,0,15272,0,0,0,0,0,0,0,0,9861,0,0,0,0,0,0,0,0 -,9512,4037,0,0,11563,49639,0,0,0,0,0,0,27880,57830,0,0,0,0,0,41831,0,21924,0,0,0 -,0,0,0,0,25509,0,27462,0,18085,0,0,0,0,0,0,0,0,0,0,0,0,13898,8068,26441,0,0,0,0, -0,0,25316,0,0,0,0,16298,7397,5706,19239,0,0,0,0,0,0,0,0,1392,50919,0,0,0,0,0, -53863,0,0,0,0,1451,0,0,0,0,0,0,0,0,0,0,35847,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 -,17801,15813,0,12740,0,0,0,32967,0,0,0,0,0,0,5389,0,0,0,0,0,0,0,0,0,0,31143,0, -20548,0,0,0,0,0,0,0,0,0,51686,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -12109,19015,0,34983,0,21732,3600,0,0,0,0,47750,17288,43975,22857,47559,0,0,0,0, -26408,48358,0,0,0,0,0,0,0,0,0,0,0,0,0,30470,0,0,23560,4581,0,22404,0,49286,0,0,0 -,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,49831,0,0,0,27525,31691,7,0,0,25835,0,0,0,0,0, -4201,16485,0,20676,0,0,0,0,3753,23303,16264,3878,0,0,0,0,0,0,11434,0,0,0,0,0,0, -7589,0,0,0,0,0,0,0,0,0,57095,0,0,0,0,0,0,0,0,0,0,0,22820,11146,49158,0,23623,0,0 -,0,0,0,0,0,13893,0,0,0,0,0,0,11722,60071,1258,0,0,0,0,0,0,18564,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,27945,0,0,0,0,5479,0,20006,17608,3431,10988,30180,0,0,0,0,0,0,0, -24581,14,0,0,0,0,0,0,25572,0,0,0,28612,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,53543,0 -,0,0,0,0,0,0,0,0,0,0,33670,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8710,0,14116,0,0,116, -292,0,0,0,37831,0,43078,0,0,0,0,0,0,0,0,21832,0,0,32134,783,0,0,30982,0,0,0,68,0 -,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5932,0,0,0,18505, -15175,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3630,16965,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 -,0,0,0,17797,0,0,0,0,0,0,520,42150,0,0,3122,0,0,0,22506,0,0,0,0,0,0,0,0,28550,0, -0,0,50278,0,0,13641,5958,0,35238,0,0,0,0,0,0,0,0,29993,18724,0,0,0,0,0,0,0,0,0,0 -,0,0,0,0,0,0,20619,9319,0,0,0,0,23977,0,5193,0,0,12196,0,0,0,0,0,0,0,0,0,0,0,0,0 -,0,0,0,0,24390,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20105,677,0,0,0,0 -,0,0,0,0,29419,0,0,0,0,0,0,0,0,0,20266,0,0,0,0,10631,0,0,0,0,0,0,0,0,0,47655,0,0 -,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,26628,12744,0,20648,0,0,0,432,0,0 -,0,0,0,0,0,0,0,0,646,0,25604,0,0,0,0,0,0,0,0,0,0,0,0,0,63782,0,0,0,0,24616,0,0,0 -,21291,0,0,0,0,0,0,0,0,0,0,45638,0,0,0,0,1931,0,0,0,20521,59975,0,20614,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,56231,0,0,0,0,0,29991,0,52871,0,20934,0,0,0,0,0,0,0,16871, -0,0,0,0,0,0,0,0,0,0,0,0,0,7237,0,0,0,0,0,47558,0,0,0,0,0,0,0,0,0,0,0,10406,0,0,0 -,0,0,0,0,43046,0,0,2930,0,12936,0,0,0,0,0,0,0,0,0,0,0,0,31141,0,0,0,0,0,0,0, -37639,0,17572,0,0,0,0,0,0,0,0,0,0,31240,0,0,0,0,0,688,0,0,0,0,0,1648,0,0,0,0, -10055,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,146,0,0,0,0,0,0,0,0,0,6345,199,0,34982,0,0 -,0,0,0,0,0,0,0,0,0,0,0,56839,0,0,0,0,0,48902,0,13412,0,0,0,0,0,0,0,0,2441,4420,0 -,0,0,0,20428,933,0,0,0,0,0,0,0,45383,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 -,0,0,0,0,0,54726,0,0,0,0,0,0,0,0,0,0,0,0,17036,741,0,0,0,0,0,0,0,27589,0,0,30282 -,18950,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2248,0,0,0,0,0,0,0,0,0,25993,0,0,0, -2443,0,0,31622,0,14150,0,0,0,28679,0,0,0,0,0,0,15464,0,0,0,0,54694,0,0,0,0,0,0, -3827,0,0,0,3756,0,9897,0,0,0,0,0,19082,31239,0,0,0,0,0,0,0,0,0,0,0,24580,0,0,0,0 -,0,0,0,0,0,16580,0,0,0,0,0,0,0,0,0,0,0,0,0,0,27625,0,0,0,784,4647,32652,0,0, -63494,0,0,0,0,0,0,0,21062,0,0,0,0,0,0,0,0,0,0,3404,58470,0,32325,0,0,0,0,0,0,0,0 -,0,0,0,0,0,0,0,0,18634,2789,0,0,0,0,0,0,0,8548,0,0,0,22501,0,0,0,0,0,0,0,0,0,0,0 -,0,0,0,15881,0,0,0,0,35879,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7978,17956,0,0,0, -0,0,0,0,24324,0,0,4937,0,0,0,8168,0,13420,10340,0,0,0,0,0,11780,0,0,0,0,0,0,0,0, -0,0,16712,0,0,0,0,0,0,0,17640,17991,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,2953,0,0,0,0,0,0,0,9100,16806,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,30667,0,0, -19013,0,0,0,0,0,0,205,15334,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1969,0,0,0,0,0,0,0,26248 -,52518,0,49798,0,0,0,0,0,0,0,9668,0,0,0,0,0,4742,0,0,21641,0,0,0,0,0,0,53574,0,0 -,0,0,0,0,5707,0,0,0,0,0,0,0,3018,12454,0,0,0,0,2920,262,0,0,0,0,0,0,0,0,0,0,3593 -,0,0,0,0,0,0,0,0,0,0,23910,0,0,0,0,0,0,0,55879,0,0,0,0,0,775,0,43270,5066,48967, -0,0,22986,4165,8971,44838,0,0,0,0,0,62279,272,0,0,0,0,51430,0,0,0,0,0,0,28234,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,13349,0,0,0,51111,20265,13861,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,585,7494,0,0,0,0,0,0,0,0,21768,62407,0,0,0,0,7979,166,0, -0,0,0,0,0,0,0,0,38918,0,56742,0,0,0,0,0,0,0,0,0,0,0,0,0,0,16296,5767,0,0,0,0,0,0 -,0,32068,0,0,0,0,0,0,0,0,0,0,0,0,0,29796,0,0,0,0,0,0,0,0,23916,30183,0,58791,0,0 -,0,0,0,0,0,20518,0,0,0,0,8969,0,0,0,183,0,0,0,0,0,2314,17445,0,0,0,0,0,0,0,0,0, -23748,0,0,8139,4839,27914,0,0,0,0,0,0,0,0,0,0,0,0,29478,0,0,16552,26663,0,53767, -0,0,13960,8039,18696,0,0,0,0,0,0,0,0,0,0,0,782,16005,0,0,0,0,0,0,0,0,6258,56806, -16456,12455,0,0,0,0,0,0,0,23780,0,0,0,0,0,0,9355,0,0,0,7273,41063,24780,57766,0, -0,0,0,0,0,0,0,0,0,3820,2597,0,0,0,0,0,0,0,0,0,0,0,0,0,0,29225,61126,0,0,0,58439, -15691,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,37190,22408,967,0,0,0, -23078,26858,0,0,0,19753,0,0,0,0,0,0,0,0,0,5416,13702,0,0,0,0,0,52742,20394,38567 -,0,0,0,51079,0,0,136,8516,0,0,0,0,0,0,0,0,0,0,0,27588,0,0,0,0,0,0,0,0,0,0,531,0, -0,0,0,0,0,0,0,0,8936,5031,12520,19334,0,0,22827,30247,28074,31140,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,27497,18148,20104,59079,0,0,0,0,0,0,0,0,0,24389,0,0,6125,0,0,0,0, -9541,0,0,24553,29095,0,0,0,0,0,0,0,25444,0,0,9643,0,0,63047,0,0,0,0,0,0,0,0,0, -39558,0,0,0,0,0,0,20620,11815,499,0,5128,2278,0,0,0,0,0,46310,0,0,0,0,0,0,0,0, -23530,40166,2440,0,0,0,0,0,0,0,0,0,0,15174,0,0,0,0,0,0,0,0,0,0,26922,0,0,0,0,0,0 -,0,0,0,0,26758,0,0,0,0,0,51911,0,0,23532,0,0,0,0,51238,25737,44486,12622,0,0,0,0 -,0,0,3078,0,9253,0,0,1128,22023,0,0,0,21350,0,16420,0,0,0,0,0,0,0,65094,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,22532,0,48774,0,34503,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,9797,0,0,0,0,0,0,0,13797,0,38279,0,0,1738,0,489,46343,0,45382,0,0,0,0,0,0, -0,0,0,29030,0,0,0,0,0,0,6220,56550,0,0,0,0,0,26885,0,28806,0,0,0,0,0,0,0,0,0,0,0 -,45958,0,0,0,0,20553,49927,0,0,0,0,0,0,3019,12358,0,0,0,0,0,0,0,0,0,0,26571, -13319,0,0,653,23399,0,0,0,0,0,0,0,0,22316,0,0,21188,0,0,0,0,0,0,0,0,0,27556,0,0, -0,0,0,0,0,27878,21483,27653,0,29701,237,0,10632,0,0,0,0,33766,0,0,0,0,0,0,31563, -0,0,0,0,0,1416,2439,0,0,0,0,0,0,0,0,0,0,9611,0,0,0,0,0,0,0,5611,16581,26601, -35462,0,0,0,26756,0,59271,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,26984,57734,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,7882,0,0,0,19528,6469,0,0,1161,0,0,0,7688,20935,425,0, -0,0,0,0,0,0,0,12519,0,12902,0,0,0,0,0,0,0,0,0,0,2411,0,11725,26086,0,0,20201,0,0 -,0,0,0,0,0,0,11045,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,30471,0,0,0,0,0,0,0,0,0,0,0, -21541,1141,21190,0,9188,0,0,0,0,0,0,0,0,0,0,0,0,0,0,184,1093,0,0,0,0,0,0,0,0, -4842,0,13672,0,0,12230,0,0,0,10532,0,0,8937,0,0,0,0,0,0,0,0,0,0,28996,0,0,11720, -26982,0,46182,0,43911,31754,0,1160,3940,0,20772,0,0,0,0,0,24549,0,32582,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,31845,0,0,0,0,0,0,0,2310,11788,0,0,43047,0,0,0,18853,0 -,0,0,0,0,0,0,0,0,63622,0,0,7048,17318,0,0,0,21957,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,1039,6279,0,0,0,0,0,0,0,0,0,0,0,0,0,12197,0,0,0,0,0,0,0,0,0, -46470,0,0,24,19719,0,0,0,0,0,0,0,0,0,39335,0,0,0,0,0,0,0,0,0,0,21353,3846,0,0,0, -0,0,0,0,36679,0,0,0,0,0,0,0,0,0,0,0,11268,0,0,0,0,0,9382,0,0,0,0,0,0,0,0,0,0,0,0 -,0,29926,0,33606,0,4708,2828,0,0,29543,0,0,0,0,0,29893,0,0,0,0,0,0,0,0,3663,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,10920,7111,0,0,0,0,0,0,0,0,0,0 -,9384,0,0,0,0,0,0,0,0,0,0,0,0,20388,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,37094,0,0,0, -27110,0,0,0,0,0,0,21865,0,27753,30214,0,0,0,0,0,57895,0,0,0,0,0,0,0,0,0,0,12648, -5446,0,0,0,0,0,0,0,0,0,0,19784,17124,0,52007,0,0,0,0,0,0,0,0,758,0,0,0,0,0,0,0,0 -,0,0,0,0,0,0,0,0,0,0,24900,0,0,0,0,0,1476,0,65031,0,0,1205,46663,0,30023,11625, -1094,0,0,0,0,0,0,0,0,0,0,0,0,0,0,10058,0,0,0,0,0,0,28455,0,0,0,0,0,0,0,0,0,0,0, -14788,0,0,0,0,16808,0,0,742,0,0,0,0,0,0,0,0,0,0,0,21636,0,0,0,0,0,0,0,0,0,0,0,0, -15944,23207,0,0,0,0,247,0,0,0,0,24743,0,0,0,5252,0,0,0,0,0,0,0,0,29961,18660, -21099,46791,0,7045,0,0,0,0,25707,0,0,17412,3828,0,0,0,0,0,0,0,0,0,0,0,5803,5637, -0,38151,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,60103,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,853,0,0,0,0,0,0,30215,0,0,0,0,0,0,0,8741,0,0,0,0,0,27366,0,0,0,0,171, -4070,0,0,0,0,0,0,0,0,24073,7366,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2184,5189,0, -20932,1545,4996,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7684,0,0,0,0,0 -,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6313,0,0,0,0,0,0,0,30826,0,0,0,0,0,0, -0,0,0,0,27463,0,0,0,0,0,0,0,0,0,0,21640,63303,0,0,3275,31111,0,0,0,0,0,0,0,11556 -,0,14756,0,0,0,15108,0,0,0,0,0,0,0,0,0,0,0,0,0,0,23914,28966,0,0,0,4965,0,0,0,0, -0,0,0,0,0,0,10216,5223,0,0,0,0,0,0,0,0,0,27142,0,0,1173,20198,0,0,0,0,0,56614,0, -0,0,0,0,4612,0,0,0,0,0,0,0,0,0,0,11822,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,17769,7910, -0,0,31880,0,0,6055,0,0,0,0,0,0,0,0,0,0,8970,0,0,0,0,0,0,0,0,0,0,0,16840,23879,0, -0,11051,0,0,0,32552,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20842,13701,0,0,0,37191,7373, -10471,17482,25348,0,0,0,38502,0,0,0,0,0,0,0,0,0,21509,6058,0,0,0,0,0,0,3173,0,0, -0,9543,0,0,0,0,0,0,17768,12708,0,0,0,0,0,37030,0,0,0,0,0,0,0,0,0,0,12748,48743,0 -,11718,0,0,25194,0,0,0,9033,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5028,0,30118,0,0,0,0,0, -42759,0,0,3720,0,0,0,0,0,0,25190,0,0,0,0,0,0,0,0,0,0,5450,5125,0,58086,0,0,0,0,0 -,27716,0,0,0,0,0,0,0,0,0,22052,0,0,0,0,26249,0,15947,3460,0,0,0,35814,0,0,0,7813 -,19500,32167,0,18597,0,0,0,0,0,28644,0,0,0,60743,0,0,0,0,0,29636,0,0,0,0,0,0,0,0 -,0,0,0,0,0,17220,15885,9414,9642,0,0,0,593,0,0,24228,0,0,0,0,0,40422,0,26244,0, -23109,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,64902,0,0,0,0,3979,60007,0,0,0,28199 -,0,0,0,43142,0,0,0,0,0,0,0,29158,0,30532,0,0,0,0,13256,0,0,0,0,16549,0,0,0,0,0, -26116,0,0,0,0,0,0,0,0,22825,0,0,0,0,0,0,0,1065,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 -,0,0,0,0,18985,4805,0,0,0,0,0,17702,0,0,0,0,0,0,0,0,0,0,3468,0,0,0,0,13447,0,0,0 -,0,0,0,0,0,0,0,0,56871,0,0,1776,15780,0,0,2603,0,10280,31366,0,0,0,0,0,0,0,0,0,0 -,0,0,0,0,11592,3591,0,2372,0,0,0,0,0,0,0,20004,0,0,0,0,0,0,12072,518,0,0,1960, -8999,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7178,32999,0,0,0,0,0,0,1641,0,0,0,0,0,0,0,6764, -9893,490,4005,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,25258,5541,0,14053,306,20743,0,0, -9422,0,0,0,0,0,0,0,11977,260,0,35175,0,0,0,0,0,0,0,18405,0,0,0,16582,0,0,0,22470 -,0,0,0,0,0,0,2792,0,0,0,14026,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,14858,3909,0,0,0 -,57671,0,0,0,0,0,0,15979,0,0,0,2794,15239,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,26884, -9070,0,0,0,0,51846,0,0,0,0,0,0,0,0,0,0,0,0,0,0,19499,37127,0,0,0,0,0,0,0,0,0,0,0 -,0,0,0,0,0,0,0,0,0,0,0,0,19205,10350,11910,0,0,0,0,15083,23108,0,0,0,0,0,0,0,0,0 -,0,0,0,0,0,0,0,169,0,0,0,0,0,0,0,0,0,0,0,15274,41735,0,56774,0,0,2825,0,14025, -389,0,0,0,0,0,0,0,0,21482,31910,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20456,710,0,0,25032, -21797,0,0,0,0,0,0,0,0,0,0,32427,21252,0,30150,0,43174,0,0,0,0,0,0,0,0,0,0,0,0, -11403,0,0,1029,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6892,9252,0,63206, -3496,14406,0,0,0,0,0,0,0,0,0,0,22568,0,0,21253,0,0,0,0,0,0,0,39623,0,0,10189,0,0 -,0,0,0,0,0,0,0,0,0,0,0,30729,59910,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3305,0,0,0,0,0,0, -0,0,0,7660,24871,0,838,0,0,0,0,0,0,0,0,0,0,0,0,12013,13252,0,551,0,0,0,43207,0, -30567,0,0,0,0,0,0,0,0,28394,30724,0,0,0,0,0,0,0,0,0,0,22665,22725,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,29414,0,0,0,0,16074,8966,245,1445,0,0,0,0,24872,0,0,0,0, -13124,0,35527,0,0,0,0,0,0,13259,10917,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -25191,0,0,0,13956,0,0,0,0,0,0,0,54631,19625,12070,3083,0,0,0,0,14436,0,0,0,0,0,0 -,0,0,0,0,0,0,0,21766,0,15463,29322,0,0,0,0,0,0,29990,0,0,0,0,0,0,0,0,0,0,0,0,0,0 -,0,0,0,23653,0,0,0,0,0,0,0,0,2643,0,0,21223,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,4114,0,0,0,0,0,0,0,0,34790,0,0,0,0,0,0,0,16103,0,0,0,0,0,0,297,3620,3338, -10372,0,14727,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,29924,22473,13895, -15529,32455,30378,13540,0,28807,0,0,0,0,0,0,0,64582,18380,0,0,0,0,0,0,0,0,0,0,0, -0,38598,0,0,0,0,0,0,0,0,1236,0,0,0,0,0,0,0,0,0,0,0,0,0,0,32710,0,0,0,0,4590,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,64935,0,0,0,0,0,0,0,0,0,0,0,0,16744,0,0, -0,0,0,0,20005,0,0,13608,1191,0,0,0,62183,0,0,0,0,0,24484,0,0,0,0,0,0,0,0,0,0, -17643,0,0,0,0,0,0,0,0,0,0,0,0,5380,0,0,32328,0,0,63814,0,0,0,2919,0,0,0,0,17034, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,60295,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,7690,486,0,0,0,39270,0,49094,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12555,0,0,0,0,0,0,0,0 -,0,0,0,0,20967,17993,12647,0,0,0,16036,32616,0,0,0,0,16294,8555,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,35174,0,0,0,0,0,0,30346,0,0,0,0,0,0,0, -14797,3652,0,0,8268,12934,0,54950,0,0,0,0,2632,33959,0,23175,0,0,0,0,0,36262,0,0 -,0,0,0,0,32684,26918,0,32676,0,0,0,0,0,0,0,0,0,0,15625,11943,1206,0,0,0,0,18052, -0,0,0,0,0,16422,0,0,0,26404,0,0,28777,0,0,24902,0,0,408,45351,0,35719,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,3658,17446,0,165,0,0,0,0,0,0,0,6151,0,0,24424,0,0,0,0,0,0,0, -24170,24293,0,0,0,0,0,0,0,0,0,11847,0,39591,0,0,0,0,0,0,9549,2788,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1010,0,0,0,0,0,0,26055,31724,0,24233, -1828,0,0,0,0,0,0,0,0,0,17284,0,0,0,0,19464,0,0,0,0,0,0,0,0,32452,0,0,0,28871,0,0 -,0,0,17704,53383,0,0,0,0,0,0,0,0,0,17892,1938,0,0,0,0,0,16362,0,0,21605,0,0,5003 -,0,0,0,0,0,0,22693,0,22342,0,0,0,55846,0,0,0,0,0,0,0,0,0,22853,0,0,0,0,0,0,0,0, -6600,263,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,24836,0,0,0,0,0,0,0,0,0, -40711,0,0,0,0,0,33894,0,0,0,0,0,0,13000,0,0,0,0,0,0,0,0,0,0,30308,0,0,0,0,0,0, -5386,0,0,0,0,0,0,27844,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,17740,0,0,0,0 -,25093,29064,0,0,0,0,0,0,0,12680,11462,0,0,0,0,0,0,0,0,84,7303,0,0,0,0,0,0,0,0,0 -,0,0,27044,457,0,22924,58246,19016,0,2606,45703,0,5157,0,25028,0,0,0,0,0,0,0,0,0 -,0,0,0,0,0,0,0,0,0,0,0,2065,0,0,0,0,0,31946,0,0,0,0,0,0,0,0,0,0,0,0,33382,0, -47878,0,0,0,0,0,0,0,0,25004,0,0,0,0,0,0,0,26153,35654,0,58055,30668,0,0,0,0, -25988,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4456,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 -,0,0,7560,20583,0,0,0,0,0,0,0,0,0,37510,0,0,0,0,0,0,0,0,0,42822,0,0,0,0,0,0,0,0, -0,0,0,1733,0,0,0,8196,0,0,11241,0,30572,60326,0,15013,0,0,0,40646,0,23812,0, -10022,0,0,0,0,0,0,0,0,12874,31015,0,0,0,0,0,0,1608,0,0,0,0,18308,0,0,0,0,27114,0 -,0,0,0,0,0,0,7944,1382,0,11813,0,0,0,0,0,0,0,0,0,0,0,0,0,24517,0,11621,0,0,0,0,0 -,0,0,0,0,0,0,21702,0,0,13100,8262,2644,7973,0,0,0,0,0,0,0,0,0,0,0,0,1033,12581,0 -,25221,0,0,0,40998,16301,62983,0,0,0,0,1263,9318,0,0,0,18854,0,0,1741,33895,0,0, -0,0,0,0,26377,0,0,0,0,0,0,0,0,0,0,32165,0,51143,0,0,0,0,0,29412,0,0,0,0,0,0,0,0, -1674,4230,0,0,0,0,0,10502,0,0,0,0,5545,0,0,0,0,0,2099,45158,0,0,0,0,0,0,0,0,0,0, -14157,0,26955,0,0,0,0,0,0,0,0,0,17096,0,0,0,0,0,0,0,0,0,0,0,0,0,27050,6726,0,0,0 -,0,0,0,0,0,28554,0,0,7142,0,0,0,0,16936,0,0,0,25833,0,4399,6980,0,46214,0,0,0,0, -0,10630,21164,0,0,0,0,0,0,0,2446,48551,0,0,0,0,0,0,0,0,0,0,0,13381,0,0,0,0,0,0,0 -,0,15400,12135,0,0,0,0,0,4774,586,0,0,0,0,0,0,0,0,23751,9736,4548,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,25577,29607,6250,1637,0,0,0,0, -22024,0,0,0,0,22308,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,37414,24044,0,0,0,14474,29735, -0,7077,0,45990,0,0,0,0,30568,40039,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -6150,0,4228,0,0,0,0,0,27687,0,0,0,0,0,0,0,24548,21513,1350,0,0,0,33607,0,0,0,0,0 -,0,0,0,11784,1414,0,0,0,0,0,0,0,18244,940,0,0,0,0,0,0,7270,0,0,0,0,0,0,0,0,0,0,0 -,0,0,0,0,16709,0,0,0,0,0,0,0,48935,0,0,0,0,0,0,23660,0,0,0,0,0,0,0,0,0,0,0,0,0,0 -,53350,0,0,0,0,0,0,4236,16358,0,4422,6665,32644,0,0,744,18084,0,11014,0,0,0,0,0, -29508,0,0,0,0,0,0,0,7686,0,0,13289,5478,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,12872,0,0,24134,1005,22916,0,31429,23400,0,0,0,0,0,0,0,28424,0,0,0, -25706,27109,0,0,26345,0,0,0,0,0,0,25126,0,0,88,0,0,0,0,0,0,0,17032,0,0,21799,0,0 -,10060,0,12296,21892,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20777,14311,0,58182, -32232,0,10282,0,2121,11527,0,0,0,12325,0,0,0,0,0,0,0,28804,2344,8133,0,0,0,0, -21864,62695,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2771,0,0, -23204,0,0,0,0,0,6278,0,0,0,0,0,26597,0,0,0,0,23144,0,0,0,0,0,31816,20070,0,0,0,0 -,0,0,0,0,0,0,24456,2118,0,0,0,0,6570,1156,0,0,0,0,0,0,0,30406,0,0,0,28388,3572,0 -,0,26599,12426,5286,0,0,0,0,0,4967,0,0,0,0,0,0,0,0,0,0,0,0,0,0,24970,24167,0,0,0 -,0,28745,4678,0,0,0,0,0,0,0,1444,236,0,0,0,0,0,0,0,0,19428,0,0,0,0,0,0,2092,0,0, -0,0,0,0,0,0,0,2827,0,0,0,0,0,19881,19204,0,11749,0,0,0,0,0,0,0,17958,0,17894,0, -18726,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,9190,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 -,0,0,0,0,0,0,0,21510,5033,0,0,0,0,22855,0,0,0,0,0,14598,0,29605,0,0,0,0,0,0,0,0, -617,0,0,0,0,47142,0,0,0,0,0,0,0,0,0,0,3627,0,0,0,0,0,0,0,0,0,0,0,0,0,2225,14823, -0,0,2637,6182,78,15078,0,0,0,0,20264,0,0,0,0,0,0,36743,4140,44551,17352,25703,0, -0,0,0,0,0,0,0,0,0,0,0,14024,0,0,0,0,0,0,28004,0,0,0,0,0,7588,0,0,0,0,0,0,0,2087, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,18028,0,0,0,300,14212,0,0,1386,40327,0,0,0,0 -,0,0,31082,0,0,22374,0,0,0,0,0,35718,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -26532,7756,0,0,18982,0,0,0,0,0,0,0,0,6440,1159,7180,0,0,0,0,0,0,45766,0,57798,0, -16740,0,0,6802,60454,0,0,0,26470,0,0,0,0,0,65382,4362,7750,0,0,0,0,0,0,9096,4743 -,334,0,0,0,0,0,0,39974,0,0,0,25828,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3027,0,0, -0,15816,0,0,0,0,0,0,0,0,48327,0,0,0,0,0,0,0,0,0,0,16168,41799,0,0,24458,8581,0,0 -,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12292,0,0,0,0,0,0,0,0,0,0 -,0,0,0,0,0,0,0,54503,0,0,0,0,5097,30852,18664,0,0,0,0,0,0,16484,0,0,27337,0,0,0, -0,0,0,0,0,0,0,0,0,35942,0,0,0,0,0,0,0,4356,0,0,0,0,0,57030,0,0,1417,41191,0,0,0, -0,0,23429,0,0,0,0,10024,21735,0,0,10126,0,0,0,0,19046,0,0,0,0,0,0,24105,4710,0,0 -,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4394,0,0,0,0,13253,0,56391,0,0,0,0,0,0,0,0,0,0, -0,19174,0,0,0,0,0,0,0,0,0,55974,0,0,0,52070,0,15620,0,0,0,0,0,2660,0,0,0,0,21644 -,0,0,52455,0,0,0,0,0,0,0,0,0,8902,0,0,0,0,0,0,3116,0,464,34726,0,0,0,0,0,0,25003 -,12423,0,27172,1896,7335,0,0,0,0,0,35686,0,0,0,0,3472,0,0,0,0,22406,0,0,0,0,0,0, -0,0,0,45254,0,0,0,0,0,0,0,0,0,0,0,0,0,21124,23594,33127,0,0,0,0,0,0,16684,22087, -0,0,0,0,0,0,0,0,0,0,0,0,8714,0,0,0,0,0,0,0,0,0,0,55814,0,0,0,0,0,0,4109,23460,0, -0,8874,0,0,0,0,0,0,0,0,0,147,0,0,0,0,0,0,0,0,0,0,0,0,0,29960,63398,1302,0,0,0,0, -0,0,0,0,24806,0,0,0,0,0,0,0,0,0,9799,0,0,0,0,0,0,0,31333,0,0,0,0,0,19557,0,0,0,0 -,0,5701,0,0,0,63014,0,0,0,0,0,0,0,21254,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12484,0,0, -0,48326,0,0,0,0,0,0,0,0,0,0,0,15783,0,0,1202,0,0,0,0,23174,0,0,0,0,0,0,0,0,0,0,0 -,0,0,0,0,0,0,0,0,0,0,0,3086,49191,0,0,5387,15141,0,0,0,3365,0,0,0,0,20076,14021, -0,0,0,0,0,0,0,0,0,0,376,40198,0,0,0,52039,0,24932,0,0,0,0,808,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,9860,0,0,0,0,0,23719,0,21476,0,0,0,0,20776,4807,0,0,3177,16678,0,0,110 -,10853,0,0,0,17382,0,0,0,0,0,0,0,0,0,43462,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 -,0,0,0,7500,4966,0,0,0,0,0,0,0,52102,0,24516,0,0,0,0,0,0,0,0,0,0,0,0,0,26535,0,0 -,0,46247,0,0,0,15557,0,0,0,0,76,52327,0,0,0,0,17866,0,0,0,0,0,0,0,0,0,0,46758,0, -0,0,0,0,19173,0,0,0,0,0,0,0,0,0,44038,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2985,0 -,0,0,0,0,0,14310,0,0,2125,45831,0,0,0,0,0,0,9838,0,13227,19492,0,0,0,29764,0,0,0 -,0,686,30053,0,0,0,0,0,30789,139,20837,0,0,0,0,502,18533,0,0,0,0,0,19111,0,0,0,0 -,0,31396,0,0,0,17444,0,0,0,0,0,0,0,49862,0,0,0,0,0,0,0,0,0,0,0,0,0,0,25610,550,0 -,0,561,0,29034,0,0,0,3528,0,0,0,1715,14661,18,63463,0,0,0,0,0,0,0,0,0,0,14186,0, -0,0,0,0,0,0,0,0,0,0,29578,59014,0,39430,0,0,0,0,2250,16612,0,31780,0,0,0,0,0,0, -462,16967,0,29029,0,0,0,0,0,23462,0,0,0,0,0,0,0,0,1768,0,6025,16998,1804,0,0, -54182,0,0,0,0,0,0,0,0,14124,0,6154,29702,0,0,0,0,0,7716,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,48807,0,8292,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,16389,5933,0, -14857,51303,0,0,0,0,0,0,0,0,0,0,0,35623,9097,23047,0,0,23112,0,0,0,0,0,438,0,0,0 -,0,0,0,0,151,9254,1390,0,0,0,0,0,0,54215,0,0,0,0,6187,0,0,0,0,13095,0,0,0,0,0,0, -0,0,0,0,0,0,9866,0,0,59622,0,0,0,0,0,0,0,0,0,25286,0,0,23848,32069,0,0,0,0,0,0,0 -,0,0,9255,2187,15270,437,0,0,0,0,0,0,0,0,0,0,19493,0,0,0,0,0,0,0,0,0,0,0,11748,0 -,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,16902,0,0,0,0,0,0,0,0,0,22212,1865,17543,0, -0,0,0,0,0,21996,0,0,0,0,55975,0,0,0,0,0,0,0,0,32138,21156,0,0,0,0,0,0,14249,0,0, -0,2388,0,0,0,0,6823,0,0,0,0,0,0,0,0,0,0,0,0,0,26694,0,0,6059,53511,0,0,0,0,0,0,0 -,49542,6159,0,0,0,0,0,0,0,0,0,0,0,0,0,1036,24036,0,2501,0,0,0,0,0,0,17419,51271, -3377,15142,0,0,0,0,0,0,5007,62374,0,56935,0,0,0,0,0,0,0,0,0,0,0,24422,0,0,0,0,0, -0,0,0,942,0,0,0,0,0,0,0,0,0,0,28263,0,0,0,0,0,0,0,15622,0,19749,0,0,1611,0,22219 -,48583,25129,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,17476,0,0,0,0,0,0,0,0,0,0, -721,0,0,0,0,32518,0,0,0,18469,0,0,0,0,0,0,5896,29927,3657,23046,0,0,3214,0,0,0,0 -,0,0,0,0,0,112,0,0,0,0,0,3048,455,0,31012,0,0,0,0,0,0,0,23270,0,32677,0,0,0,0,0, -38086,0,0,0,0,0,0,0,0,0,0,0,0,0,4900,0,0,0,0,0,0,0,0,0,25541,0,18788,0,0,22248, -1351,0,61734,4524,30629,0,14887,242,29063,0,0,14408,4741,0,0,0,37318,0,0,0,0,0,0 -,0,0,0,0,0,0,8106,0,32107,0,0,0,0,0,0,0,0,0,0,0,1481,0,0,28132,0,25798,0,59783,0 -,0,0,0,0,59078,0,0,0,23366,0,0,0,0,0,0,0,30887,0,0,0,0,16200,0,0,0,335,0,0,0,714 -,0,0,0,0,0,0,0,0,0,0,0,0,0,30730,9478,0,0,0,0,0,0,0,0,0,0,0,18790,0,0,0,0,663,0, -0,0,1034,31431,0,0,0,0,0,0,0,0,0,0,30120,0,0,0,0,13925,0,0,0,0,0,0,2280,13414,0, -0,0,0,0,0,22028,23687,3017,11047,0,0,21738,18630,0,0,0,0,0,0,0,30246,0,0,0,0,0,0 -,0,0,0,0,0,0,17257,0,21896,63783,0,0,0,21094,0,18662,0,25700,0,22533,0,0,0,0,0, -6341,5800,11111,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15399, -12970,6501,0,0,3179,26438,0,0,0,0,0,0,0,15750,0,13062,0,0,0,0,0,0,0,0,0,0,142,0, -0,0,0,21284,11177,4391,0,0,0,0,19595,40647,0,0,0,0,0,11877,0,0,0,26439,0,0,0,0, -695,49126,27467,11972,0,0,0,0,0,0,9961,0,0,0,31722,62982,0,0,0,0,15817,52710,0,0 -,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,24614,0,0,0,0,0,20550,0,0,5034,3942,0,0,0, -45927,0,0,0,0,0,0,0,0,0,0,2548,0,0,0,0,0,0,45606,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 -,0,0,0,0,0,0,3405,12582,15563,54087,0,0,0,0,0,0,0,0,0,0,0,0,24202,5893,0,0,0, -44230,0,0,0,5605,0,47782,0,32230,0,0,0,0,0,0,0,0,0,0,0,7014,0,0,0,0,16488,3175,0 -,27237,0,0,0,0,0,40902,0,0,0,0,0,0,0,32004,31434,0,24392,0,0,0,0,0,0,0,0,0,0,0,0 -,0,0,0,0,0,29130,58214,0,0,0,0,0,0,29002,0,0,0,0,0,0,0,0,0,0,55366,0,0,0,0,0,0,0 -,0,0,0,0,37926,0,0,0,0,0,0,0,0,1290,0,0,0,4713,0,0,0,0,0,0,0,0,0,0,0,0,0,20812,0 -,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1803,966,0,17700,0,0,654,19109,0,51655,0,0,0,0,0, -10470,1584,0,0,0,0,0,0,0,2506,0,0,25159,4303,0,0,0,395,15879,0,0,0,0,0,0,0,0,0,0 -,1352,6535,0,19652,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4722,7909,0,0,0,0 -,30152,0,0,64742,0,0,0,0,0,0,2153,9125,0,0,279,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 -,0,0,0,41894,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 -,0,0,0,0,1328,17030,0,0,0,0,0,0,0,54151,0,0,0,0,1775,54535,0,0,0,0,31624,0,0,0, -7150,0,0,0,0,0,0,0,1840,35943,0,0,0,0,0,56455,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -64486,0,0,0,51174,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4134 -,0,0,0,0,0,0,0,0,0,0,0,17092,0,0,0,0,0,0,0,0,0,0,0,0,12,16134,19883,39943,10281, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,44711,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -14125,2407,0,0,0,0,0,0,0,0,0,0,26921,0,0,0,0,0,22188,0,20810,10053,0,0,0,0,0,0,0 -,0,0,0,0,0,0,0,0,0,0,0,0,0,0,29220,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28170,0,15208,0,0 -,32517,5736,19271,3562,10534,0,0,0,59655,0,0,0,0,27084,60422,0,0,24969,0,0,0, -2636,0,0,0,0,26277,0,0,0,0,0,0,0,0,0,0,0,30596,3594,0,0,0,8362,14565,0,0,0,0,0,0 -,10793,12326,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5906,59686,0,0,23081,517,0,15556,0,0,0, -8486,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,19877 -,0,0,0,0,0,0,0,0,7497,0,0,26085,0,0,23784,63591,6568,6310,0,0,0,0,0,0,0,0,0, -10054,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7018,14470,18858,0,5641,10660,0,0,0,0,0,0,0, -35526,1515,0,0,0,0,0,0,0,0,0,0,0,27656,0,0,9606,0,39590,0,0,0,0,0,0,0,0,0,0,0, -53926,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,232,4327,12649,0,0,0,0,0,0,0,0,0,0,0,0,0,0 -,0,0,0,0,0,0,0,0,0,0,0,0,20199,0,0,0,0,0,0,26730,0,0,0,19400,14695,0,31334,0,0,0 -,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,19589,0,0,0,0,0,0,0,0,5064,11908,0,27333,0, -0,0,0,0,0,0,47751,0,0,0,26662,0,0,0,0,0,0,0,55655,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,6245,0,0,0,0,0,0,0,0,23368,63911,0,0,0,0,0,0,0,0,1974,0,0,0,0,0,0,0, -8520,24037,0,0,0,0,0,0,0,26279,0,0,0,22886,0,0,0,27782,0,30694,0,0,0,0,0,0,0,0,0 -,0,0,33703,0,0,0,30405,0,34598,0,51047,0,0,0,0,1908,0,0,0,0,0,0,0,0,0,0,1511, -21897,0,0,0,0,0,0,51398,0,24870,0,32647,0,0,0,35015,0,0,0,0,0,0,0,11204,0,0,0,0, -0,0,7758,57991,0,0,0,30949,0,0,22,15140,9162,0,0,0,0,0,0,25540,20136,7108,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,16427,10789,9805,0,0,0,0,0,0,0,0,0,4680,0,0,52679, -0,0,0,0,0,14884,0,0,0,16804,0,0,0,0,0,0,9578,5287,0,0,0,0,0,0,0,34054,0,0,0,0,0, -19076,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7627,55719,0,39463,14446,58374,0,0,0,0,23465, -15845,0,0,0,0,0,38534,0,0,0,17893,10922,0,7176,678,0,0,0,0,0,0,0,0,3113,46279,0, -0,0,0,0,0,0,23334,0,0,18088,23268,0,62342,0,0,0,16613,0,0,0,0,0,0,0,0,0,38182,0, -0,0,0,0,0,25292,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,10344,71,6446,0,0,1893,0,0, -1106,0,28680,30756,0,41126,0,0,1492,0,15341,0,0,0,0,17575,0,21220,0,0,0,0,0, -25060,2088,21828,0,0,0,0,0,358,0,0,0,0,0,16708,0,0,0,1668,0,0,0,0,0,12260,0,0,0, -0,0,0,0,0,4078,0,0,0,0,0,12713,6215,0,0,20329,0,0,0,0,0,0,0,0,0,0,31204,0,0,0,0, -0,0,0,0,0,0,3732,0,1646,0,0,27460,0,34406,17128,14341,0,0,0,0,0,19527,0,0,0,0,0, -0,0,0,0,0,6120,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8551,21546,10212,3020, -2951,0,17638,0,0,6985,44999,2218,8197,0,0,30472,63366,0,26660,0,0,0,0,0,0,0,0,0, -0,0,0,1265,0,0,0,0,0,0,0,2610,0,0,0,11278,20295,0,0,0,0,0,19780,0,0,0,0,0,0,2353 -,10852,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5421,24292,0,0,0,0,0,0,0,0,0,0,0,0,0,34407,0, -0,0,0,0,0,15432,20774,0,0,0,0,0,0,0,0,12360,10757,0,0,0,33126,0,0,0,0,0,0,0,0,0, -0,0,29573,0,2343,0,0,0,0,0,63079,0,0,0,0,0,0,0,0,0,43015,0,16038,0,0,0,0,0,0,0,0 -,1480,25573,0,0,0,0,0,0,0,8839,0,0,0,0,0,0,0,24645,0,0,0,0,0,0,0,0,0,0,0,0,0, -5063,0,0,0,0,0,45830,0,0,0,0,0,0,0,0,0,0,823,0,0,64039,0,0,0,0,0,0,0,0,0,0,0,0,0 -,15300,0,0,0,0,0,0,2924,46759,6760,19268,0,0,0,0,0,0,0,0,0,34182,0,0,3977,18149, -0,0,0,32199,0,0,0,0,0,0,0,0,0,23524,25994,0,0,10343,0,0,0,9733,0,0,0,0,0,0,0,0,0 -,4740,0,0,0,0,0,0,0,0,0,16741,0,0,4626,23367,0,0,31400,0,0,3557,0,0,4234,0,0,0,0 -,0,0,28486,0,0,0,0,0,14213,0,57191,0,0,0,0,0,0,0,0,0,0,240,0,0,0,0,65318,29832,0 -,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,29989,0,31846,0,0,8170,0,0,4421,27626,30884,0 -,0,20204,0,0,0,0,44614,534,20868,0,0,0,0,0,0,0,0,0,0,0,0,0,28710,0,10277,0,0,0,0 -,0,29511,0,19813,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,27020,0,0,0,0,0,0,53094 -,0,35207,0,0,0,37542,0,61766,8584,8037,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12488 -,22757,0,0,0,0,0,0,0,0,0,0,0,0,0,23814,0,0,0,0,0,0,0,0,0,19973,0,0,0,63943,0,0,0 -,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36006,0,0,0,19012,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 -,0,0,0,0,8580,0,0,0,0,0,0,0,18021,0,0,0,0,0,0,0,0,80,1254,0,0,0,42630,0,0,0,0,0, -0,0,16262,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2124,25479,0,0,0,0,16873,0,0,0,0,3142, -0,0,18443,0,0,0,0,0,3917,0,8841,1190,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 -,0,20645,0,0,0,0,0,0,0,0,0,0,0,9284,0,0,24394,41351,0,0,0,42087,0,62566,0,0,0,0, -0,0,0,0,0,0,6728,4199,0,0,0,0,25515,0,1231,0,374,15623,0,29956,0,14118,0,0,0,0,0 -,19047,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,31718,0,0,0,0,0,0,0,0,0,0,0,20900,0,16743,0 -,0,0,28902,0,0,0,0,0,0,0,0,0,0,0,0,2578,0,0,0,0,0,0,0,0,0,13838,0,0,10052,0,0,0, -0,7432,43783,17097,0,0,0,0,0,873,0,0,0,398,0,0,0,0,0,0,0,0,0,8459,23559,0,53030, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,35750,0,4071,0,0,0,38662,0,41414,0,0,0,0,11656,0,0 -,0,0,0,4011,42695,0,0,0,0,0,0,0,0,0,0,0,0,0,0,25353,0,0,0,0,0,0,0,27177,22372,0, -0,0,0,0,30980,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,46278,3976,12711 -,0,0,0,0,0,0,0,0,0,0,0,20517,0,0,0,0,0,0,0,0,0,0,0,0,4072,11078,0,0,16553,2405,0 -,0,0,0,0,0,0,0,2670,0,0,0,0,0,0,32998,0,0,0,0,0,0,0,47046,0,30533,0,0,11050,9734 -,13129,0,0,0,0,23494,0,0,0,0,0,58310,0,0,0,57543,0,0,0,0,0,0,0,0,0,0,0,0,0,454,0 -,0,0,0,0,0,5163,59687,2220,0,0,0,0,0,0,29510,0,0,0,0,0,0,0,0,0,0,0,17316,0,20069 -,0,0,0,0,0,0,0,0,0,5319,0,0,0,0,0,0,0,0,0,27174,0,0,0,0,0,0,0,22949,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,19208,0,0,0,0,0,0,20933,0,0,6026,8742,0,0,0,17380,0,13127,2797,0 -,0,30116,0,0,5963,8004,0,57126,0,0,0,0,0,42854,14792,30759,0,24964,0,0,0,0,0,0,0 -,0,0,0,0,0,0,0,0,0,0,16933,0,0,0,0,0,0,15176,40839,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -788,30341,0,0,0,0,21036,24102,0,0,0,0,30123,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -22597,31531,26789,0,59559,0,0,0,0,0,0,0,0,0,0,0,0,0,0,9352,29863,0,0,0,0,0,0,0,0 -,0,24551,0,0,0,0,0,0,0,20516,0,0,0,39462,3665,0,28265,0,8778,64262,0,57414,9132, -0,0,18276,0,0,0,0,0,0,0,0,0,0,26344,30725,524,19751,0,13796,0,0,0,0,0,0,0,0,0,0, -18155,0,12841,0,74,24998,13579,1061,0,64199,0,0,8776,0,0,60231,0,25412,0,0,0, -59143,0,0,0,0,0,0,14344,1510,0,0,0,38374,0,0,0,0,0,0,0,0,13353,0,0,0,0,0,0,0,0,0 -,0,9446,0,0,0,0,0,0,0,32613,0,0,0,0,0,0,0,0,0,0,0,0,0,19844,0,0,0,0,14859,0,0,0, -0,6662,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,14154,0,29770,0,0,0,0,0, -16520,2182,0,0,0,0,0,36102,3340,0,0,0,0,0,0,0,0,25189,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,15720,0,0,0,0,0,0,22758,0,0,304,0,3243,14117,0,0,0,0,0,0,0,0,0,0,5130, -12679,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,21733,10441,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,36103,0,0,0,0,0,23590,0,57479,0,0,0,0,0,0,0,0,0,0,0,0,10824, -18372,0,0,0,0,0,35078,15722,12967,0,0,0,0,0,34599,0,0,0,0,0,0,0,0,0,0,0,0,0, -53639,0,38630,0,0,0,0,0,0,31017,11333,0,0,0,0,19144,0,9513,0,0,0,0,0,0,0,0,56711 -,24042,0,1197,0,0,58502,0,0,0,0,0,0,0,0,0,8230,6121,18628,0,0,0,0,0,0,25290,0,0, -0,0,0,1514,0,0,0,0,0,0,0,14378,9798,32363,0,0,0,0,0,9577,0,0,0,0,0,0,26788,0,0,0 -,0,0,0,330,10533,0,0,0,0,0,42246,0,0,0,0,0,0,5074,21028,0,38119,0,0,0,0,0,0,248, -0,31176,62054,0,53287,0,0,0,0,271,0,0,0,0,0,0,0,0,0,0,0,0,0,9224,2117,0,0,0,0, -15818,5607,0,52582,0,0,0,0,0,0,0,0,18248,24005,23018,0,0,0,0,0,0,0,0,0,0,0,0,0, -427,0,0,39910,0,0,7080,11399,0,0,0,0,0,0,0,0,0,0,22220,57894,0,0,0,0,0,0,0,13156 -,0,1413,1007,0,0,0,0,21415,0,21543,0,0,0,0,0,0,0,0,0,41702,22538,9573,0,0,0,8806 -,0,0,6920,56359,0,0,0,0,0,0,0,0,0,0,0,42215,0,0,13708,0,0,0,0,0,0,0,0,0,0,16453, -0,0,0,0,0,0,1582,1764,3282,0,0,0,0,0,0,0,0,0,0,0,0,0,0,11653,0,0,0,0,12139,0, -29482,31076,1673,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,40262,0,0,0,33862,0 -,0,0,0,0,20996,0,0,0,0,0,4615,0,0,0,0,0,0,0,0,0,0,0,43943,333,19367,0,0,0,0,0,0, -0,26821,0,32389,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4936,11687,0,0,0,0,0,0,0,0,0,10885,0 -,0,0,0,0,25926,0,0,0,0,0,0,15851,0,0,0,0,0,0,0,0,0,8360,0,17130,7942,0,11460,0,0 -,0,0,0,0,0,0,0,0,0,0,0,0,0,18150,14248,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -22310,0,0,0,42758,0,0,0,0,0,0,0,0,29354,5574,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 -,0,0,0,0,0,0,0,0,0,0,0,31109,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,11236,0,0,0,0,0,0,0,0 -,0,0,0,0,0,9156,0,0,1801,14023,0,0,0,0,0,62406,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -23620,0,0,0,0,0,0,0,0,0,0,31018,65510,0,0,0,0,0,0,0,26182,0,0,0,0,0,0,0,27717,0, -0,0,0,0,0,0,46950,0,0,0,0,0,0,0,0,0,0,0,0,0,31108,0,11366,0,0,0,3717,0,0,0,0,0,0 -,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8552,6054,3339,0,0,0,0,51622,0, -0,0,0,0,0,0,3718,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28358,0,2756,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,1462,0,0,27622,0,0,0,0,0,0,0,62502,14410,56743,0,0,0,0,0,0,0,0,0 -,0,0,0,0,0,0,0,0,0,0,0,0,0,12206,0,0,0,0,0,0,0,0,0,0,0,0,36550,0,38054,0,0,0, -21221,0,0,0,0,0,0,0,27077,0,0,16906,0,12587,12101,0,0,0,0,0,0,10414,28775,21769, -60167,0,56646,0,0,0,0,0,20740,0,0,0,0,0,0,5931,5351,0,65478,0,0,0,0,0,0,7977, -52647,0,4868,0,0,0,55463,0,0,0,0,0,32197,0,0,0,0,0,13445,0,0,0,26631,0,0,0,0,0, -11237,0,0,0,0,209,1285,0,0,1928,0,0,0,0,43334,23849,23172,0,0,0,0,0,0,0,0,24712, -62439,8811,3463,20457,0,0,0,0,0,0,0,0,0,16008,56263,0,0,0,0,0,0,0,0,0,0,0,60358, -22761,6565,0,0,30888,27686,0,0,0,17093,0,0,0,0,22121,0,0,0,7593,14182,0,28103,0, -0,0,0,0,45126,0,0,0,0,0,0,0,0,0,0,0,0,0,31844,0,0,0,0,0,0,0,0,0,0,0,0,0,18500,0, -0,0,0,28202,0,0,0,0,0,0,0,0,26308,0,29541,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -29572,0,0,0,21285,0,0,0,0,0,60839,0,0,0,0,0,30407,15949,2981,0,0,0,46439,0,0,0,0 -,0,23911,26505,25222,12811,5895,0,6343,0,0,0,0,0,0,0,0,0,0,0,31815,0,0,0,0,0,0,0 -,0,19688,10245,0,0,0,31301,26985,28964,0,0,0,0,0,0,0,0,27208,31172,0,0,0,0,216,0 -,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,16292,0,0,0,0,0,8743,0,0,0,0,0,0,0,0, -0,0,0,0,0,6438,0,0,0,33319,0,0,0,33286,0,0,0,0,0,0,0,0,0,22181,7499,24774,0, -10756,0,44775,724,0,25768,25669,24873,5349,25257,0,0,54566,0,0,0,0,0,0,0,0,0,0,0 -,327,439,357,0,0,6536,8452,0,0,1802,0,0,61350,0,15045,0,0,0,0,0,0,0,0,0,0,0, -38343,0,0,0,0,0,0,0,0,0,0,32491,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -22885,0,0,32073,0,0,0,9546,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,27748,0,0,23176,0,0,0 -,0,0,0,0,0,0,0,0,0,24583,0,0,0,0,0,34118,0,0,0,0,2158,0,5586,30340,0,0,0,0,0,0,0 -,0,0,0,0,0,0,24452,0,0,0,0,2409,4390,0,24196,0,0,0,0,0,0,32264,26948,20587,0,0,0 -,2155,0,0,0,0,0,0,0,0,0,0,0,4328,26276,0,0,0,0,0,0,0,0,23564,0,12458,11367,0,0, -25162,0,0,0,0,0,0,65414,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,32966,0,0,0, -34662,0,0,0,0,0,39238,0,0,0,0,11400,10214,266,12452,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,15173,0,0,0,13668,0,13222,0,23364,0,0,0,0,0,11941,0,0,0,0,0,0,0,0,0, -25575,0,0,0,57383,0,0,0,10308,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,2865,9287,75,0,0,0,0,0,0,0,0,0,0,21508,22380,59526,0,0,0,23589,0,0,0,51590 -,0,0,0,0,0,0,0,0,0,0,0,4645,3980,28295,0,0,0,0,0,12388,0,0,0,0,0,0,0,0,0,0,0, -21734,0,17607,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,41767,0,0,0,0,0,0,0,18436,0,0,0,0,0, -0,0,21958,0,19430,0,0,1204,0,0,0,0,0,0,0,0,0,3240,55239,0,0,0,0,0,30660,0,0,0, -28901,0,0,0,0,4716,0,0,0,0,0,0,0,0,0,0,0,11754,0,0,0,0,22086,0,22564,8749,0,0, -28391,0,0,0,0,0,0,0,0,0,0,0,2886,0,0,0,0,0,0,0,29062,0,0,0,0,0,0,0,40358,0,0, -15916,39526,0,13735,0,0,0,0,28938,0,407,4006,0,0,0,26916,0,0,0,0,0,27526,30280,0 -,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,24586,0,24649,5126, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8684,0,0,0,0,0,0,0,23019,0,22377,18599,0 -,0,0,0,0,0,0,0,0,0,27593,9735,0,20196,0,0,0,0,28168,48423,0,0,0,0,0,31399,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,13892,0,0,0,0,0,17606,0,0,15242,29767,26378,17701,0,0, -14472,0,4840,0,0,0,0,0,0,24708,0,9349,4330,0,0,0,0,0,0,0,16137,0,0,34854,0,0,0,0 -,0,0,0,0,0,0,0,25063,0,0,0,0,0,0,6603,12583,0,0,0,0,0,0,0,0,7433,29188,0,0,0,0,0 -,31270,0,0,22920,3143,0,0,0,0,0,23461,0,0,0,0,0,0,0,0,618,0,0,0,0,21381,0,11524, -0,0,0,0,0,0,21004,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,312,23239,0,0,0,0,0,0,0,0,0,0,0, -0,2313,0,0,40614,0,0,14825,0,0,0,0,0,0,46535,0,41190,7853,0,31656,0,0,0,0,0,0,0, -0,0,3433,5255,0,0,0,0,0,0,0,33958,0,0,0,0,72,15493,0,0,0,0,0,0,0,36070,0,0,0,0,0 -,0,0,14724,0,0,0,0,0,29828,0,0,0,0,0,0,0,18822,20008,0,0,0,0,2438,2952,0,0,0,0,0 -,0,0,0,0,0,0,0,0,3342,0,0,0,0,0,0,0,0,0,0,0,0,0,0,24420,0,19908,0,0,0,8101,0, -17479,0,0,3530,0,8202,29319,0,0,1132,6789,0,0,23881,0,0,0,4810,0,0,46918,0,0,0, -41574,0,0,0,0,0,0,0,0,0,48582,0,0,0,0,0,0,0,0,0,0,0,0,0,39334,0,0,0,26117,0,0,0, -0,0,0,5100,0,0,0,0,0,23496,27813,4045,54918,0,0,0,0,0,0,6473,7428,0,0,0,0,6792,0 -,0,0,0,0,3560,32103,0,0,0,0,0,0,0,0,0,0,0,54790,0,0,6926,0,0,0,0,16518,0,0,0,0,0 -,20806,0,0,0,0,1841,3174,0,0,0,0,9612,18374,0,0,0,0,32744,0,0,9671,0,59879,0, -23300,8073,0,0,14758,0,0,0,10342,0,0,0,0,0,0,24808,14759,0,0,0,0,0,0,5515,0,0, -14852,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2354,23271,0,32740,0,0,0,0,0,0,0,0 -,0,0,18472,0,0,0,0,0,0,0,0,33190,0,0,0,0,0,0,0,0,8972,21669,0,0,0,0,0,0,0,0,0,0, -0,25574,0,0,0,0,5096,0,14283,55367,0,0,0,0,0,0,0,0,0,12644,0,0,0,0,4651,0,0,0,0, -0,0,0,661,0,0,13638,19466,0,0,0,0,0,31273,0,8010,0,0,0,0,0,3211,0,0,0,0,63430,0, -0,0,0,0,15237,0,0,0,0,0,0,19018,2437,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,14312,0 -,0,0,0,16836,0,0,471,35975,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 -,6023,0,0,0,0,0,0,0,0,11593,9639,0,0,0,55783,0,5700,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,27908,0,26598,0,0,6667,6470,0,0,0,0,0,0,0, -62534,0,0,0,0,16522,27911,0,0,10025,7172,0,0,779,0,360,17477,0,0,0,61991,7752, -7717,1494,0,0,0,26569,40742,0,0,0,0,0,0,0,26406,10474,32196,0,0,0,0,0,50567, -16521,11716,0,0,0,0,0,55558,0,0,0,0,0,0,0,0,0,0,0,61926,0,26436,0,0,0,0,4459, -10598,0,0,0,0,0,0,0,0,0,0,0,9223,0,29318,0,0,0,0,0,60423,0,0,0,0,0,0,0,47078,0, -50246,0,12612,0,0,0,0,0,0,0,61799,0,55015,0,21060,7309,0,0,0,0,0,11976,0,0,0,0, -23527,0,0,0,0,0,0,10347,15942,0,34023,0,0,0,0,4969,0,0,0,0,0,0,0,0,28997,0,0,0,0 -,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36454,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -3466,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,19716, -28872,0,0,0,0,0,22152,0,0,0,0,0,0,26342,0,0,0,9764,0,0,0,0,0,0,0,21798,0,0,0,0, -13,6853,32136,0,0,0,0,0,0,0,750,0,0,54502,0,0,0,0,0,0,0,0,0,46183,0,0,625,22854, -0,0,0,0,2061,23588,0,0,11049,56262,0,0,18538,1509,0,0,17258,4453,0,0,0,0,12429,0 -,0,0,0,8102,0,0,0,0,0,0,8074,0,23852,0,0,0,0,0,0,0,0,0,0,0,16136,3428,0,27876,0, -0,0,7332,0,0,0,0,0,28900,0,0,2284,0,0,17573,201,1508,0,0,0,0,0,0,0,0,0,31365, -27688,22565,0,0,0,5159,0,0,0,0,4584,42599,0,0,0,44422,1068,23173,0,0,0,613,0,0,0 -,12645,0,0,0,0,0,27076,6732,0,0,0,3913,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 -,0,0,0,0,0,0,0,0,0,0,0,22244,29992,15911,0,0,0,0,0,22982,0,0,0,0,0,0,0,50598,0,0 -,0,0,0,0,5161,1574,0,0,0,0,0,0,0,0,0,19108,0,0,0,35014,0,0,0,25956,29067,0,0,0,0 -,0,0,0,0,0,0,47079,0,0,0,0,0,0,0,0,0,0,1356,61927,0,0,0,64455,2122,64231,0,0, -18763,0,0,0,0,0,0,0,0,0,907,34471,0,0,0,39078,0,0,1995,0,0,0,0,0,0,0,0,0,0,56518 -,0,0,0,0,0,0,0,0,0,0,0,0,822,0,15978,44423,0,0,3112,325,0,0,0,0,0,15397,0,0,0,0, -0,0,0,0,0,0,1193,4294,4968,15559,0,46150,0,0,0,0,0,18917,0,0,0,0,0,0,9928,37543, -0,0,0,0,13097,36999,0,0,0,15430,0,0,8424,29639,0,0,0,0,0,0,0,0,0,0,0,0,0,25734,0 -,0,0,0,0,0,0,0,0,0,0,0,0,40487,0,13284,0,11141,0,0,0,32388,0,0,0,0,0,0,0,0,0,0,0 -,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5298,57702,0,0,0,0,0,0,0,13060,0,0,0,0,0,0, -8233,42278,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36422,0,0,0,7972,0,0,0, -18437,0,0,0,0,7406,0,0,0,9225,0,0,0,0,0,0,0,0,0,13865,47591,18220,53703,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2796,0,0,0,0,0,24940,17223,0,0,0 -,13221,0,0,0,0,0,0,0,0,0,0,15848,0,0,0,0,0,6122,1735,0,0,0,0,0,0,0,0,0,0,0,0,0,0 -,0,0,0,0,16968,18151,0,0,0,0,0,47494,0,0,0,0,0,0,26089,19494,0,0,0,0,0,15494,0,0 -,0,0,0,0,0,0,0,0,28809,0,0,0,0,42727,0,55174,0,0,0,0,0,0,0,0,0,0,0,20485,0,0,0,0 -,0,0,0,0,0,0,0,58598,0,0,0,0,0,0,0,0,0,0,0,0,0,15172,0,0,0,0,0,0,0,0,0,35302,0, -48135,20972,33094,0,0,0,0,0,9765,0,0,0,0,0,0,0,0,0,39559,0,0,13736,6950,0,0,0,0, -23658,8903,0,0,0,0,0,0,0,22662,0,0,0,0,0,58886,7468,0,0,0,0,0,0,0,0,64550,0,0,0, -0,0,47622,0,0,0,50886,0,0,0,0,0,57606,912,0,0,0,0,0,0,0,0,0,1449,0,1169,0,718, -46151,12104,0,0,0,0,0,0,48230,0,0,0,0,0,0,0,0,0,0,1259,0,0,33734,23208,62567,0, -65158,0,0,0,0,0,0,0,0,0,0,28684,59878,0,0,0,0,0,0,0,0,0,0,25769,0,0,0,0,65479,0, -0,0,0,555,22789,0,19748,1769,10246,8680,0,0,0,0,0,0,0,0,0,14250,0,5899,3303,0,0, -0,0,0,0,0,0,21097,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,21638,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,10795,0,0,0,16204,0,0,0,0,0,26986,2469,0,14660,0,0,0,0,0,45447, -12234,3494,4555,10566,0,0,0,0,0,0,0,0,0,0,0,0,2801,0,0,0,15755,0,0,0,0,0,0,0,0,0 -,0,0,0,0,0,0,0,0,0,39654,0,0,0,0,0,0,6763,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -33574,0,10279,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,63527,0,0,3912,0,0,7492,0,0,0,35142, -0,0,0,0,0,0,17576,8103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,16713,4198,0,0,4782,0,0,0 -,0,0,0,0,0,0,0,0,0,0,0,16228,0,0,0,0,25961,20166,0,0,0,10980,0,0,0,0,0,14340, -18922,14567,0,44199,0,0,0,0,0,0,0,18406,0,0,0,0,0,37606,0,0,0,0,0,0,0,0,0,20902, -0,0,0,56358,0,38342,0,0,0,0,9514,36071,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,21700,0,0, -5266,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1134,0,1453,0,0,0,0,0,3882,0,0,0, -0,0,0,0,0,4004,0,0,0,51910,0,0,0,0,0,23076,4648,0,0,0,31051,25351,0,0,0,22884,0, -0,0,0,0,63975,0,0,2376,16997,0,0,2096,0,0,0,3373,7046,0,0,0,0,0,0,0,30726,0,0,0, -0,20,0,13707,614,0,0,12840,3079,0,0,0,0,0,51046,3729,0,32680,0,0,0,0,0,24008, -62759,0,0,4745,0,0,0,0,0,0,0,0,0,0,0,0,0,2414,0,0,44262,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,24937,0,0,0,0,0,0,0,0,19140,0,13575,0,0,0,0,0,0,0,39110,0,0,0,28036,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,4261,0,0,0,0,5992,0,264,0,0,0,0,0,0,0,13739,0,21928,0, -0,0,0,0,0,0,0,0,0,0,4232,15110,0,0,0,0,0,0,0,0,0,30022,0,0,27977,0,0,0,0,0,24776 -,0,0,0,0,0,2962,0,0,0,0,0,0,26564,22441,0,0,0,0,0,13640,11205,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,19305,1894,0,0,0,0,0,0,0,0,0,0,9389,0,0,0,0,0,0,0,0,0,0,0,0,0,0,14119, -5224,135,0,0,0,0,0,0,0,0,0,25796,0,0,0,0,0,0,7470,0,0,0,0,63815,0,55654,0,0, -12584,0,1524,33223,0,0,0,9895,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,11624, -0,0,0,5614,0,0,0,0,0,0,0,21320,0,0,53607,0,51206,0,0,0,25863,0,0,0,0,0,0,0,0,0,0 -,0,8964,1740,0,0,0,0,0,0,0,0,13476,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7975,0, -0,3306,8134,0,8389,48,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,25766,0,0,0,0,0,0,0,0,0, -52166,0,0,0,0,0,0,0,0,0,0,0,0,0,21477,31112,31652,0,0,0,0,0,0,0,28452,0,0,0, -44231,0,0,0,0,0,0,0,24805,0,0,0,0,0,0,0,0,0,0,12428,6471,0,0,0,0,525,17926,0,0,0 -,26919,0,0,18120,0,0,0,30024,0,0,0,0,0,0,0,0,0,0,29189,0,0,0,43559,0,0,0,0,0,0, -19787,7557,0,59334,0,0,10184,6085,0,44039,0,0,0,0,0,0,0,11175,0,0,0,0,30440, -63110,0,0,0,0,0,0,11017,0,0,0,0,0,0,0,0,27204,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,29126,0,0,0,0,0,0,0,0,0,0,0,0,0,0,622,0,5226,2727,0,15588,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4650,0,2675,0,0,32420,0,0,0,61511,0,0, -5419,17829,2123,0,0,0,0,0,0,0,0,0,0,0,0,0,0,38183,2640,0,11274,14533,1842,0,0, -42663,12681,3430,0,11845,0,0,0,0,0,0,0,0,0,6533,0,0,0,0,0,54598,0,0,0,0,0,0,0,0, -0,0,0,0,12616,38535,0,0,0,0,0,32229,0,0,0,54279,0,48614,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,31401,0,0,0,0,34310,0,0,0,22788,0,52134,0,0,0,0,0,0,0,23302,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,40678,0,0,0,51463,535,0,0,0,0,15525,0,0,0,0,0,0,4904,869,0 -,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,63718,0,0,0,0,0,0,0,0,1678,0,692,0,0,0, -0,0,0,0,0,0,26216,0,0,0,0,0,29355,0,0,0,0,25095,0,0,0,0,4335,0,0,0,0,0,14538,0,0 -,0,0,0,0,0,0,0,27273,55014,0,0,0,0,0,27271,0,0,0,0,0,30468,0,0,0,0,18186,0,0,0,0 -,0,14345,0,0,0,2152,0,0,0,0,0,0,0,0,0,0,0,0,0,0,58438,21034,0,23339,21318,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,21412,0,0,0,0,0,0,0,12869,0,0,4875,0,0,0,0,29191,0,0,0,0 -,0,0,1640,10247,0,14244,0,0,0,0,9867,0,0,0,0,0,12363,0,0,7653,0,0,4168,2663,0, -4580,0,11143,0,0,0,0,0,0,0,30662,0,0,0,0,0,6724,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,13764,0,0,0,0,0,0,0,0,0,0,0,0,234,6821,0,0,0,0,0,0,0,0,0,0,0,0,0,0 -,0,0,0,0,0,0,0,0,0,25639,0,0,0,0,0,0,0,0,0,29958,0,3461,0,0,0,0,0,0,0,0,0,28324, -18795,7013,12746,11655,0,37287,0,0,10953,7718,9705,0,0,0,0,0,0,0,0,0,0,46534,0,0 -,0,0,0,0,0,0,0,0,8137,17988,0,25156,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,41415,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15784,6918,0,0,0,0,7019,10919,0,0,0, -0,0,0,0,0,0,0,4171,55495,4940,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,22440,19333,0,0, -28136,0,6249,21317,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,53414,0,0,0,57318,0,0,0 -,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,39303,0,0,0,0,0,19940,0,0,0,0,0,0,0,25543,0,0,0 -,0,0,0,0,0,0,0,0,0,2698,3911,0,0,0,26790,0,0,0,0,0,0,32424,0,0,18470,0,0,0,14726 -,29834,0,0,0,0,0,0,0,0,0,0,0,1000,4197,0,0,0,19366,0,0,0,39878,0,0,0,0,2185,8901 -,5288,9829,25000,0,0,0,0,0,0,1062,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,35622,0, -0,23048,62503,6506,0,0,0,0,0,0,0,13609,10438,0,0,0,0,0,0,0,0,0,0,7723,42119,0,0, -0,0,0,13317,0,0,0,41606,0,27111,0,0,21194,11461,0,0,0,0,26856,58342,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,20940,48710,0,0,0,0,0,0,5227,0,0,0,0,0,10061,31300,0,0,0,19236,0 -,0,0,0,0,30277,13896,0,0,0,12876,13159,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,428, -46951,13134,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15462,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,21668,0,0,0,0,0,0,0,0,0,0,0,0,2249,0,0,0,0,44967,0,0,0,0 -,0,0,3465,0,0,0,0,0,0,0,0,0,0,0,0,0,0,24868,0,0,0,0,0,23909,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,2190,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,16164,0, -10437,0,0,5263,20102,20938,0,0,0,1192,1030,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 -,0,21385,4870,0,0,0,0,0,0,0,0,0,0,0,18596,0,0,0,0,1422,4038,2858,0,0,0,0,0,0,0,0 -,48998,0,0,0,0,0,0,0,0,6508,37350,0,0,0,0,0,0,0,0,17001,39431,0,0,0,0,0,30182,0, -21445,7403,28164,0,51750,0,0,0,62631,0,0,0,0,0,0,0,31206,0,0,0,0,0,0,0,0,0,0,0, -7751,0,0,0,0,0,0,0,0,0,13477,0,0,456,26693,0,0,0,0,0,0,0,0,0,0,0,0,14890,0,0,0,0 -,0,26697,22022,13225,27364,0,0,0,18884,0,0,0,0,0,0,0,0,3659,0,0,0,0,0,0,0,0,0,0, -0,1448,5413,0,0,0,0,0,0,0,0,0,0,0,6340,0,0,18091,18725,0,0,0,0,0,0,0,0,0,0,0,0,0 -,22118,0,0,0,18981,0,0,0,0,0,0,0,0,0,29223,3724,0,0,0,0,43526,0,0,0,25668,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,21545,9862,0,22692,32201,60646,0,7300,0,0, -0,58887,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,19460,0,0,0,0,0,0,0,0,0,50342,0, -65255,4360,17286,0,0,0,0,0,0,0,28708,0,0,30025,60102,0,0,0,0,0,0,0,0,0,47014,0, -31973,0,9572,0,0,0,0,0,0,0,18501,0,0,0,0,0,14597,0,0,0,53735,5228,22183,0,0,0,0, -0,0,1554,24164,0,0,0,0,0,0,0,0,0,0,0,0,10827,0,0,0,0,34918,0,0,0,0,22252,0,0, -46855,0,0,0,0,0,31207,0,0,10733,0,0,63334,0,0,0,0,8616,50119,20169,12678,0,0,0,0 -,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,58087,20298,5,0,0,30920,0,0,0,0,0,0,0,296,13190,0 -,30663,0,0,18536,12228,0,6788,0,0,0,0,30890,21796,0,0,526,0,0,0,0,0,0,0,0,0,0,0, -0,20965,0,0,0,0,2161,0,0,0,0,0,0,24038,0,0,0,0,13544,7398,0,0,32522,9605,0,0,0,0 -,3208,7590,0,0,0,43846,0,0,0,38663,0,0,0,0,0,39014,4142,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,6373,0,0,13676,0,0,0,0,30374,21288,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 -,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,22791,0,0,0,0,0,37958,0,0,0,0,0,0,0,0,0,0,9452, -9990,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4841,0,0,0,0,18820,152,0,0,0,0,0,13260,3334,0,0 -,24234,8422,0,17957,0,0,0,10244,0,0,0,0,0,0,0,0,0,0,0,7204,0,0,0,0,1201,26151,0, -31173,0,0,0,0,0,0,0,0,0,0,0,0,0,64838,4203,7525,521,0,18888,37031,0,0,0,0,0,0,0, -0,7082,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4490,12487,0,0,0,0,0,0,0,36615,0,0, -0,14854,0,0,0,0,0,0,0,0,0,0,0,0,6539,13029,9704,38983,0,0,0,0,168,10405,0,0,0,0, -394,25607,0,57063,0,0,0,0,0,0,0,0,0,0,16141,19878,0,0,0,0,0,0,0,0,0,29446,0, -12036,0,0,0,0,0,6982,18572,0,24584,14535,0,0,0,0,0,0,0,0,0,0,16,0,21642,0,0,0,0, -0,0,5254,0,0,0,0,0,0,0,0,1622,0,0,0,0,0,0,0,0,0,0,0,0,0,3853,9126,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,7241,10982,0,0,0,0,0,0,0,0,0,0,0,0,0,0,950,0,0,57990,0,0,277,0 -,0,0,694,36007,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,42470,0,0,0,0,18409, -51142,0,0,0,0,0,0,0,0,0,28646,0,0,0,30693,0,0,0,0,0,56295,5544,0,0,0,0,8518,8366 -,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,45670,0,0, -9608,33062,0,0,0,0,0,0,0,0,0,0,0,18694,0,0,0,0,1672,23493,0,0,6955,7655,0,36134, -0,0,0,0,0,0,0,0,23432,647,0,0,0,0,0,0,0,0,0,0,0,13382,0,0,0,19621,0,0,0,0,0,0,0, -0,0,20228,0,0,2728,31495,0,0,0,0,29096,22213,235,35495,0,0,0,0,0,0,0,0,0,0,0,0,0 -,0,0,5348,0,0,0,0,8968,1989,0,0,1066,0,0,11492,5965,31367,0,0,0,0,0,0,0,0,0,0,0, -18727,0,0,0,6757,0,0,10765,4646,0,36166,0,27943,0,0,26888,8420,0,0,0,0,0,0,0,0,0 -,29316,0,0,0,0,0,0,0,0,0,0,4975,0,0,0,14762,3111,0,0,0,0,0,43399,0,0,0,0,0,0,0, -18980,0,0,0,0,0,44550,0,0,0,0,4051,0,0,0,0,37734,0,0,0,0,0,5188,0,0,0,0,0,24486, -0,5989,0,41159,0,0,0,0,0,0,0,0,0,20326,0,0,747,6884,0,0,0,41798,0,0,3117,22919,0 -,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,21032,0,0,0,0,0,0,0,0,9574,0,0,0,0,0,0, -4302,0,0,0,0,0,0,0,0,0,0,0,21068,34630,0,0,0,0,0,64071,0,0,0,0,0,0,26667,7943,0, -0,0,0,0,52934,0,0,17002,0,0,0,0,0,0,20294,0,0,0,0,0,0,0,0,0,27301,18347,7974,0,0 -,0,0,0,0,0,0,16874,0,0,0,0,45414,0,0,0,0,0,0,648,1575,0,0,0,31749,0,0,0,23301,0, -0,0,0,0,0,0,0,0,0,0,0,15912,50535,0,0,0,0,1993,8582,0,0,0,0,0,0,0,38438,0,0,0,0, -0,0,0,0,0,0,0,0,15850,6183,0,0,0,0,3402,0,0,27494,0,0,749,0,0,0,0,0,0,0,26025, -29606,0,0,7144,19622,30504,0,0,0,0,0,0,0,0,21316,0,0,0,0,0,0,0,0,0,21444,0,0, -1289,6919,0,0,0,0,0,0,8299,0,0,0,14090,35655,0,0,0,0,0,0,0,0,2377,15206,0,0,6028 -,4452,0,25508,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,50310,0,0,0,0,1269,0,0,0,0,0,0,0,0,0 -,0,0,0,51014,0,0,0,0,0,0,0,9286,0,7429,0,0,28393,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 -,0,0,0,16680,452,0,0,0,0,0,23718,0,0,0,31750,0,0,0,0,0,0,0,0,3568,0,0,13604,0,0, -0,0,0,25255,0,0,0,50982,0,56582,0,0,7467,0,0,0,0,30181,0,0,0,0,0,0,0,30564,7208, -7845,0,0,0,0,0,0,7726,0,0,0,0,62182,0,0,0,41094,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,22695,0,0,0,0,0,0,17736,0,0,0,0,0,0,0,0,50054,0,0,0,14180,0,0,0,0, -0,0,8974,0,0,0,0,0,0,0,0,23332,0,0,0,11140,0,0,0,0,0,0,0,24262,27145,9540,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,26537,45510,6062,3879,0,0,20233,25991,0,0,17803,0,0,0,0,0, -13962,5508,16971,27013,7437,31494,0,0,0,0,0,0,0,0,0,0,4714,0,0,0,0,0,0,0,0,17189 -,0,0,0,0,0,27492,0,0,26953,0,0,0,0,0,0,0,0,0,0,41319,0,0,0,0,0,0,0,0,0,0,0,47430 -,19596,12549,0,0,0,8390,1006,0,0,0,0,0,0,0,0,0,0,24100,17577,4,0,0,0,0,0,22277,0 -,0,0,0,0,0,0,26692,0,0,0,0,0,24676,0,0,0,0,0,0,0,0,0,0,0,0,0,29477,0,0,0,21573,0 -,0,0,0,0,0,0,0,0,0,9864,14214,0,0,0,0,0,0,25771,5766,0,0,8909,8679,0,0,6861, -16166,0,38887,0,0,0,0,0,0,12392,8678,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -52646,1354,2950,0,14692,0,0,10572,49830,0,0,0,0,0,0,0,0,3626,582,0,0,0,55750,0,0 -,0,30885,0,0,0,0,0,0,0,0,0,0,0,0,0,5830,0,0,2090,0,0,0,0,0,0,0,0,0,0,0,0,31142,0 -,0,0,0,0,10503,0,0,18825,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -57158,0,0,30792,63526,0,0,0,9863,16267,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 -,0,0,0,0,0,0,0,0,0,0,18824,0,0,0,0,0,0,19653,25388,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 -,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,9292,0,0,0,0,0,0,0,0,0,0,36358,0,0,0,0,0,0,0,0, -0,0,25480,23015,0,0,10440,6725,0,0,0,22436,24265,15109,0,0,0,62311,8906,34534,0, -0,0,0,0,0,15913,1319,0,0,20296,1477,30760,0,25928,16772,0,0,1069,0,0,0,0,0,0,0,0 -,0,0,0,0,17029,0,31909,0,0,0,0,0,0,0,0,0,0,0,41638,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 -,0,0,0,0,41542,0,21478,0,0,0,9796,0,0,0,0,0,0,0,0,0,0,22187,58343,0,0,0,24295,0, -0,0,0,0,61831,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2833,5829,0,0,0,62855,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,16676,0,0,0,0,0,0,13577,27431,0,0,0,0,21480,10501,0,16932, -0,0,0,0,0,22918,0,48294,2574,2150,0,0,0,0,1897,4518,0,0,0,0,0,0,25064,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,47942,0,0,0,0,10990,13767, -25705,37863,21672,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,43430,1712,0,0,0,0, -18886,0,0,0,0,0,0,0,0,0,0,0,0,0,10535,0,0,0,0,0,0,0,15012,0,0,0,0,0,0,0,0,0,0, -14734,0,0,55782,0,0,30824,10886,0,0,0,0,0,51302,0,0,8012,0,0,0,0,0,20680,6981,0, -57415,11,0,0,18277,0,14564,0,0,0,32390,0,0,0,0,0,0,0,0,0,0,0,0,19113,5158,0, -11172,0,16774,0,0,0,0,0,0,0,0,0,0,0,0,10315,13830,0,0,0,0,0,0,10410,7141,0,0,0,0 -,0,18116,0,0,0,44615,15403,13958,0,1540,14632,19525,24201,19781,0,0,0,24165,0, -38951,0,0,0,0,0,6308,0,0,0,0,0,0,0,0,0,0,0,0,0,0,17416,15749,3438,13255,0,0,0,0, -0,0,0,0,0,0,0,32228,0,0,0,0,176,0,0,50566,0,0,0,0,0,0,0,0,0,0,0,0,0,21540,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,58982,0,0,0,0,0,0,0,0,0,5284,0,0,0,0,0,0,25897,28326,0,0 -,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15945,0,0,0,9804,293,0,0,0,0,0,0,0,13988,23082,4677 -,0,0,0,0,0,0,0,0,0,0,0,5670,0,0,0,0,0,0,0,44070,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,6405,0,30692,0,0,0,61702,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 -,45926,0,15398,0,0,0,0,0,0,4554,2692,0,0,0,0,0,32485,0,0,0,10084,0,0,0,0,0,0, -24297,0,0,0,0,0,0,0,0,22790,0,0,0,55110,0,0,0,0,0,0,0,0,0,0,0,0,7112,0,31530, -45255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,40743,17226,22599,0, -0,0,0,0,0,0,0,3695,0,0,0,0,0,0,0,0,0,0,56999,0,0,0,0,0,13799,3114,21287,1353, -7591,0,0,0,8455,0,0,6824,0,0,0,0,0,0,0,14569,0,0,0,29000,0,0,0,0,0,0,0,0,0,0,0,0 -,0,0,0,19979,0,18376,0,0,0,0,0,0,0,0,0,0,0,0,11332,0,0,0,49863,0,0,0,0,0,0,0,0,0 -,0,0,0,0,0,2191,7527,23148,58022,0,0,0,30631,0,26565,0,0,0,0,0,0,0,0,0,0,0,0,754 -,0,0,15877,0,0,0,0,0,0,0,17510,7657,2821,0,0,0,0,0,0,0,0,0,41927,0,0,0,0,0,0,0,0 -,2569,34439,0,0,3790,0,0,0,15339,8775,0,0,0,0,0,0,0,0,0,0,0,15908,0,0,21419,8359 -,0,0,0,0,424,0,0,0,0,0,0,25318,8008,20551,0,0,0,45735,30058,30372,0,0,0,0,0,0,0, -0,0,0,0,0,0,26180,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,31432,10567,0,0,0,0, -17450,0,0,0,0,0,0,30310,0,38022,0,0,0,0,0,28932,0,0,0,0,0,43910,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,22180,12075,0,0,0,0,0,0,0,0,0,0,0,0,0,0,22247,0,0,22826, -12359,0,0,0,0,4105,50407,0,0,0,0,0,0,13581,28583,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 -,0,0,0,0,28936,0,0,0,0,0,17673,10310,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,905,57862, -1580,0,0,0,0,58630,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,13479,0,0, -14153,13286,0,0,9259,0,0,0,0,0,6606,3524,0,0,0,0,0,6567,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,631,49255,0,0,0,0,0,42886,0,38215,0,0,0,0,0,0,0,0,17580, -0,0,0,0,0,0,0,0,55046,0,0,0,0,0,0,0,0,0,10213,0,0,0,0,3604,37767,0,0,0,0,0,0,0,0 -,0,0,0,30950,0,0,0,0,0,0,0,0,0,62087,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,23528,0 -,0,0,0,0,0,0,0,0,28715,4229,0,0,0,0,0,0,0,0,0,0,1226,26820,0,0,0,12133,6984,261, -21130,32548,0,0,0,0,0,0,3565,12390,20713,28071,0,0,1706,25287,0,0,0,0,0,0,0,0, -14670,0,0,0,0,0,0,30534,0,0,0,12615,0,43750,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28228, -0,0,0,0,0,0,0,45095,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1224,3975,10954,6375,0,0,0,0 -,0,0,0,0,0,0,23180,20100,0,0,0,0,25736,8519,0,0,0,0,0,6663,0,2534,0,0,0,0,0,0,0, -0,23720,0,0,0,0,0,0,0,0,0,0,19398,0,47814,26281,49702,0,0,4332,12965,0,0,5704, -3206,0,0,0,0,0,0,0,0,0,0,0,0,0,15396,0,0,0,44102,0,0,0,0,0,0,0,0,0,0,0,0,0,25317 -,1064,39271,27433,0,14952,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,14308,0,0,0,0,0,0,2763 -,4100,0,0,0,0,0,0,18792,0,0,0,22154,32583,0,6244,0,0,0,0,0,0,0,49478,0,0,0,0,0,0 -,0,0,0,0,0,21894,0,0,11048,0,0,0,0,0,0,11685,0,53862,0,0,15114,0,13870,0,0,0,0,0 -,0,0,919,0,0,0,31916,0,22570,101,0,0,0,0,0,0,0,0,0,7333,0,0,0,0,3272,0,0,0,0, -27718,32712,0,0,0,0,0,0,0,0,0,1782,0,3688,0,0,0,0,29862,0,0,0,0,0,0,0,22469,0,0, -0,0,0,0,0,55302,850,15492,0,0,0,5927,19786,13350,0,25702,0,0,0,0,0,0,0,0,0,0,0, -40390,0,0,0,0,0,0,0,0,0,0,0,0,0,20260,0,0,0,0,0,0,0,0,0,0,0,0,0,15335,8394,0,0,0 -,0,0,0,26566,0,0,0,0,843,2245,0,0,0,0,0,0,0,0,6959,0,20488,1638,0,0,11533,50759, -0,0,0,0,0,20871,0,0,0,0,0,24519,0,0,0,0,9544,23591,0,0,0,0,0,0,0,0,0,0,20969, -7109,29001,0,0,32422,31720,64294,0,0,0,0,16106,0,0,0,6930,4933,0,0,0,22917,0, -27015,0,0,0,0,19880,8070,0,0,0,0,23945,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -3310,0,87,0,0,0,0,0,0,0,0,0,0,0,0,0,0,18439,0,0,0,20742,0,0,0,10597,0,0,0,0,0,0, -0,0,0,0,0,0,20236,0,0,0,16584,3429,0,0,0,0,0,0,0,0,27241,0,0,0,0,16132,0,0,0,0,0 -,0,0,0,0,0,0,0,244,28261,0,0,0,0,0,0,0,29509,0,0,0,0,0,0,0,0,2921,31781,0,0,0,0, -0,0,6408,4196,344,0,0,0,0,0,0,0,0,0,0,0,0,0,11689,45863,0,0,0,0,906,3301,0,0, -25544,32421,0,0,0,0,0,0,0,0,1260,61607,0,27302,0,0,8682,16614,0,0,0,0,10830,0,0, -9604,15049,13413,0,0,0,0,0,0,26761,0,0,0,0,0,0,61990,0,0,0,0,0,12580,0,0,11432,0 -,0,0,0,0,22507,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12389,0,0,0,0,0,0, -2408,22661,14507,43239,0,9700,0,0,24714,0,0,0,0,0,0,0,0,23972,0,0,0,0,0,0,0,0,0, -0,0,0,0,34086,0,0,22955,7238,0,0,0,0,0,28485,13806,20038,0,0,0,0,22602,0,0,0, -1645,22340,0,0,0,0,0,0,0,0,0,0,0,26502,0,0,554,0,0,0,0,61735,0,0,0,0,0,0,0,0,0,0 -,0,0,0,0,0,0,0,2694,0,0,0,0,0,0,0,0,0,0,0,0,0,0,883,27879,15948,0,3242,57382,0,0 -,0,0,0,0,13930,0,0,0,0,0,30922,0,4137,52615,0,0,0,0,0,0,0,0,0,0,0,0,0,31911, -16072,0,0,0,0,0,0,0,0,0,0,0,0,26340,0,61671,0,0,0,0,3145,56199,0,0,0,0,0,0,0,0,0 -,0,0,0,280,0,5131,33479,0,15751,0,0,0,0,0,0,4136,1446,0,0,0,0,0,0,11304,17863,0, -0,0,0,0,25125,0,0,0,36646,6057,0,0,0,855,11301,0,0,0,0,0,64774,0,0,0,19397,0,0,0 -,0,0,0,0,0,0,0,0,0,0,0,0,0,1040,27367,0,0,0,0,0,0,0,0,0,0,0,0,0,64358,0,0,178, -132,0,0,14763,24455,0,0,0,46374,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,46246,0,0,0,37382, -0,0,0,7462,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8166,0,0,6921,0,0,0,9163,0,0,0,119, -0,0,0,23146,17156,0,0,0,0,0,9127,0,0,0,17927,0,0,0,0,0,22084,0,0,0,0,0,39879,0,0 -,2035,0,1067,0,0,0,0,0,16652,59591,0,0,0,0,0,0,0,0,0,0,0,0,20171,0,0,0,0,17733,0 -,0,0,0,0,32037,0,0,0,0,0,14277,0,0,0,0,0,0,0,42022,0,0,26793,20358,0,0,0,0,0,0,0 -,0,0,0,0,0,0,0,0,0,8907,0,0,0,0,0,0,0,0,27780,0,0,0,0,32330,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,39399,0,9732,0,16199,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 -,0,0,0,0,854,0,2984,45063,25418,26980,22539,0,9133,3653,15528,28743,4649,0,616, -65127,0,0,0,61863,0,0,0,0,0,0,0,55303,0,0,0,0,0,0,0,0,23880,0,0,0,0,0,0,0,31848, -62854,0,0,0,0,0,0,0,0,0,0,0,49606,0,27974,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,32580,0,0,0,26052,4043,0,0,40454,0,0,26056,30565,0,0,0,0,0,0,0,31398,0,0,0,0 -,0,0,0,0,29288,1797,0,0,3220,0,0,0,0,0,0,0,0,0,20427,0,0,0,0,23621,0,0,0,0,0,0,0 -,0,0,24261,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,35591,0,0,6862,0,0,0,4265,0,6285, -5383,0,0,0,0,0,36870,0,39847,0,0,17224,5414,27882,58118,0,0,13224,4262,0,0,0, -31302,0,0,1388,2982,11881,0,0,0,0,0,0,16837,809,0,24140,10724,0,0,0,0,5835,0,0,0 -,0,0,0,0,0,0,0,0,1256,19237,0,0,0,0,0,0,0,5796,11848,0,0,52870,11464,0,0,0,0,0,0 -,0,0,0,5645,9158,0,25223,0,0,0,0,0,39142,24968,8135,32104,28678,0,0,0,46311,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,23820,0,0,0,0,0,4050,0,1323,25220,0,0,0,20133,0, -0,0,0,0,0,0,0,0,0,0,9381,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 -,0,0,0,0,0,0,0,13444,1198,60806,0,0,0,0,17356,50247,30632,0,0,0,0,0,0,0,11944, -999,0,0,0,0,4010,10404,0,0,0,0,0,0,10346,0,0,49510,0,0,0,0,0,0,0,0,0,0,0,0,0, -38919,0,0,0,0,0,0,6351,60966,20137,487,0,0,0,0,0,0,655,2406,17387,43303,0,0,0, -17063,0,0,213,0,0,0,0,0,0,17221,0,0,0,0,0,0,0,0,0,0,0,10820,0,0,0,0,369,6,0,0, -9098,21093,0,31653,0,0,0,0,0,0,0,0,0,27143,0,0,16234,0,0,0,0,0,0,0,0,6020,31723, -28293,0,0,0,0,1936,30695,0,0,0,0,0,52902,0,0,29512,10791,0,20420,0,0,16010,0,0,0 -,0,0,0,0,0,0,0,0,5324,0,0,0,0,0,0,0,0,0,0,0,0,13383,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,24328,0,0,0,0,0,0,40870,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,24648,0,0,0,0,0,0,0,7786,2852,0,0,0,0,0,0,0,0,0,44678,0,17925,0,0,105,53062, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,18762,0,0,40679,0,0,0,16165,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,20390,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,62310,1322, -14247,0,0,0,0,0,0,0,0,1832,6052,0,0,11882,0,0,0,0,17668,0,28262,0,29542,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28007,0,0,0,57223, -1585,0,0,0,0,0,0,0,0,0,0,0,21162,0,0,62247,0,0,0,0,0,25414,0,0,0,0,0,0,0,0,0,0,0 -,0,0,0,0,0,0,0,0,0,0,0,0,36326,0,0,0,23845,0,0,0,0,0,0,0,2693,0,0,0,0,0,0,0, -13125,0,31236,0,0,0,0,0,22502,0,0,0,0,0,0,5994,10309,0,0,0,7269,0,0,0,0,17929,0, -1011,44647,0,0,0,0,0,14919,0,0,0,0,20586,5350,0,0,0,45702,0,13189,0,0,0,0,0,0,0, -0,0,35782,17992,0,0,0,0,0,8203,0,0,0,0,0,0,56678,0,0,0,0,0,38087,4233,0,2127,0,0 -,0,0,0,0,0,0,0,0,10148,0,0,0,2021,0,0,0,0,0,0,0,47206,0,0,0,0,0,0,0,9220,0,0,0,0 -,19465,0,0,0,0,0,0,0,0,39206,0,38055,0,0,0,0,0,0,0,46982,0,0,0,0,0,22054,3850,0, -0,0,0,0,0,0,55,0,10542,0,0,0,0,7239,0,0,0,0,0,59367,0,0,14761,0,0,0,0,43079,0,0, -0,0,0,2726,0,0,9582,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,37478,0, -0,0,31364,0,0,0,0,0,0,0,0,20393,8933,0,0,0,0,0,9380,0,0,0,0,16905,549,0,0,0,0, -182,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1558,0,0,0,0,0,0,0,19242,0 -,0,0,0,0,0,24933,0,6276,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,42310,23595, -24068,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,13191,6158,2567,0,0,268,47047,0,0,0,0,0,0,0, -0,0,27940,0,0,0,0,0,26726,0,0,0,0,8200,1222,31562,0,0,0,0,0,0,0,0,0,2922,8231, -8904,29157,0,0,0,0,0,0,0,0,23976,4836,0,0,0,0,0,0,0,0,0,0,0,0,31658,0,0,31685,0, -0,2889,6213,0,0,0,0,0,13605,0,0,0,0,0,24772,0,0,0,0,0,0,0,0,0,0,20684,26468, -24075,0,0,0,21193,0,715,679,0,0,0,0,0,0,3050,7654,0,0,0,13798,0,0,0,0,15,27973,0 -,0,8491,2086,0,0,0,43206,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,60391,0,0,0,0,0,0 -,0,25892,0,22276,0,34374,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20165,0,0,25672,0 -,0,0,1811,24839,0,31044,0,0,25513,0,0,0,0,0,12810,0,0,62438,0,0,1325,0,364,3782, -0,0,0,0,0,0,0,0,8042,19687,0,0,0,33415,0,0,0,0,0,0,0,0,0,0,0,7205,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,11844,0,0,0,0,3341,1543,6698,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 -,0,0,0,0,0,0,0,0,0,0,0,0,29766,0,0,0,0,0,0,0,0,0,0,0,41158,0,24294,0,3844,12329, -0,0,0,13738,0,0,0,0,0,0,0,0,26245,0,0,0,0,0,0,6378,0,343,4838,0,0,0,24358,11688, -0,0,0,0,0,0,0,0,0,1489,34759,0,0,0,0,363,51974,1878,11013,0,0,32265,59782,0,0,0, -28421,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,22756,0,0,0,0,0,0,0,0,0,0,0,0,0,0,14089,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,29257,61222,0,30661,0,28327,0,0,0,0,0,0,0,0,0,0,0,0,0, -27108,8843,0,9673,2084,0,0,0,16327,0,48455,0,0,0,0,0,0,4876,9316,0,0,0,0,0,0,0,0 -,0,0,0,0,9035,18852,0,0,0,0,0,0,0,0,0,0,0,0,0,4164,0,0,14827,1349,0,0,0,0,0, -11909,0,0,0,0,0,0,0,0,0,21765,0,0,0,0,0,0,0,0,31272,63910,0,0,0,25924,0,0,0,0,0, -0,0,0,0,44487,0,0,0,20612,0,0,27754,31428,0,0,0,0,0,0,0,17287,0,3943,0,0,0,63302 -,0,0,0,0,25256,19942,0,55142,0,39046,0,0,0,0,0,0,0,15367,0,0,0,0,0,0,0,0,0,0,0, -28422,0,0,0,0,0,0,0,0,0,0,0,0,9576,63847,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 -,0,0,25226,5734,0,0,0,0,0,0,13801,4997,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 -,0,0,0,0,0,0,43942,1270,2566,6284,0,0,16230,0,0,0,20678,0,0,0,0,0,38855,0,0,0,0, -29643,0,0,0,41,3655,0,0,0,0,0,14276,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,15686,0,0,0,15718,0,50694,0,0,16232,8007,0,0,0,5060, -329,11591,51,0,0,0,0,0,0,0,0,0,13065,7302,27530,15366,0,24934,0,0,0,17828,0,0, -4552,6311,0,0,0,0,0,0,0,0,0,0,0,47686,368,12103,10122,33830,0,0,599,18534,9579, -49479,0,5668,0,0,0,0,0,0,0,0,0,13157,0,0,0,0,23274,14055,0,0,0,0,0,48903,0,0,0,0 -,0,0,1871,0,15434,0,0,0,16174,62470,0,0,0,0,0,0,0,0,0,0,0,7749,0,0,0,0,0,0,0, -30501,0,0,0,0,25675,0,0,0,0,0,0,0,0,0,0,9285,0,0,25323,1669,0,0,0,0,0,0,0,0,0,0, -0,3588,0,0,0,0,0,32902,0,0,4426,0,0,0,0,57959,0,0,0,0,0,0,29898,58278,0,0,0,0, -11880,1220,0,0,0,41479,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,23141,0,0,0,0,0,0,0,0,0,0,0 -,0,0,42566,0,0,0,0,0,0,0,40167,9484,3493,0,0,0,0,0,21126,0,0,0,0,8649,18918,0,0, -0,0,0,0,0,34886,2601,0,0,0,0,12518,0,0,0,0,7976,10311,0,0,0,0,0,0,0,45190,0,0,0, -0,0,0,0,0,0,0,16842,20229,0,0,0,0,0,0,7528,4614,0,0,0,0,0,30086,0,0,0,1671,0,0,0 -,0,0,0,0,0,0,0,0,0,0,0,9896,6277,0,0,0,0,0,61191,0,41287,0,21956,0,0,20010,0,0,0 -,0,0,0,0,0,0,0,0,13195,0,0,0,0,1381,0,0,0,0,365,30951,24268,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,7044,0,0,0,0,0,0,0,0,0,0,27944,359,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 -,0,0,28487,0,0,77,0,0,0,0,0,0,0,0,56775,12586,8421,0,0,0,0,0,0,26185,14599,0,0, -8040,5702,12585,3109,0,0,0,0,0,21574,5388,0,0,0,0,0,0,0,5106,52454,0,0,0,0,0,0,0 -,0,1907,29895,0,6116,0,0,0,0,11081,5285,0,28069,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4104 -,0,0,0,0,0,0,41511,0,0,0,0,0,0,5262,0,0,0,503,4231,7720,34343,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7304,10374,1718,0,0,29127,0,0,0,0,0,0,0,0,23497, -22567,6952,2340,0,0,0,0,0,0,0,0,20360,12453,0,45094,0,0,0,0,0,28582,0,0,0,0,680, -0,0,0,0,0,0,0,0,0,0,0,0,0,23084,0,0,0,30696,0,0,0,0,45862,0,0,0,0,0,0,0,0,0,0,0, -0,5580,6053,0,0,0,0,0,0,0,0,0,0,712,70,0,0,26091,11335,0,0,0,0,13612,0,13160, -1926,435,51559,0,0,0,0,0,0,0,0,0,0,0,0,0,47302,19083,0,0,12742,0,1607,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,6155,37095,0,0,0,0,0,18948,7146,0,0,0,0,0,0,0,7848, -2055,0,0,0,0,8910,0,19336,0,0,48070,8490,0,0,0,0,0,0,0,9932,56423,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,4133,0,0,0,0,0,0,0,0,0,43398,0,0,0,0,0,0,0,0,16173,0,0,0,0,0 -,0,0,32011,0,0,30918,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,26854,0,0,0,0,0,0,0,0,0,0,0,0 -,0,20389,0,0,0,0,0,0,0,0,0,0,0,0,0,0,18889,0,0,0,0,8965,0,0,0,44358,0,0,0,8997,0 -,34055,0,0,0,0,0,29350,0,0,501,17767,0,0,32457,60262,0,0,0,30886,0,0,3757,1063,0 -,0,0,25637,0,0,0,0,0,28068,0,26374,0,0,0,0,0,0,0,0,0,0,0,11684,0,0,0,0,0,0,24779 -,229,0,13766,0,0,7402,11525,0,0,0,0,0,0,0,0,26313,23686,0,0,29736,47527,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,27268,0,0,0,0,553,0,0,0,0,0,0,32038,0,0,0,0,1135, -26596,0,0,12300,14631,0,0,0,43238,0,871,0,0,31496,0,8457,17669,0,12836,0,0,0, -22726,0,38758,0,0,375,6564,0,0,0,0,0,0,0,0,0,0,0,0,170,18535,0,22948,0,0,32360,0 -,0,0,0,0,0,0,0,0,0,0,0,0,0,25764,0,0,0,0,0,0,0,0,0,0,0,15652,0,0,0,32774,0,0,0,0 -,0,0,0,0,0,28551,0,0,0,0,0,0,0,0,0,0,0,0,15145,0,0,0,21100,27654,0,0,0,0,0,0, -4874,26215,0,1639,0,0,0,0,0,0,0,0,0,0,4169,0,0,0,0,0,7336,0,0,0,0,21572,0,0,0,0, -0,0,0,0,0,24644,1675,2533,0,0,0,53318,0,13094,0,0,0,0,0,0,0,6246,0,22020,0,0,0,0 -,0,0,0,0,0,0,0,28453,5576,5124,0,0,0,0,0,0,0,0,0,0,0,0,0,27910,0,29382,18216, -8583,0,0,0,39174,0,43558,0,0,0,0,0,0,0,0,0,11973,0,0,0,0,0,23397,0,0,0,0,6091,0, -0,0,0,0,0,0,6474,16197,14217,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 -,0,0,0,26728,0,567,48839,0,0,0,0,0,15271,0,0,31818,43974,2450,0,0,0,0,0,0,0, -11368,9191,0,44454,0,0,0,0,0,0,14568,12293,0,0,0,8453,0,0,0,0,0,0,0,0,0,0,0,0, -32040,0,0,0,0,0,0,0,0,0,0,0,0,902,0,0,0,27236,5612,11495,0,0,0,0,0,0,0,0,9194, -23684,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,27430,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -26217,44870,0,0,0,0,0,0,5581,7173,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -52775,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20968,18340,0,0,0,0,0,0,0,0,4107,11239 -,0,0,0,0,0,0,0,0,0,0,0,29381,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,21990,0,0,0,0 -,0,0,0,0,0,48806,0,0,0,32292,0,0,0,0,0,0,0,10884,0,0,0,0,0,0,0,0,0,0,27562,0, -5643,0,0,0,0,0,0,0,0,0,3089,31525,0,19684,0,0,0,0,0,0,0,61415,0,0,0,0,0,36198,0, -0,0,0,0,0,0,7908,0,0,0,0,872,743,0,0,0,0,0,0,0,0,1229,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,32484,0,0,0,0,0,34822,0,0,0,0,0,50726,0,0,0,0,7274,0,0,0,15304, -11526,0,0,0,3047,0,0,0,0,0,0,22376,0,0,0,846,0,0,0,0,35815,0,0,0,23652,0,0,0,0,0 -,0,0,0,0,0,0,0,0,0,0,0,23721,2148,0,0,0,0,0,0,14856,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,1358,0,3082,0,0,0,848,10949,0,0,0,0,0,0,6504,0,0,14372,0,0,0,0,0,0 -,0,0,0,0,8201,9958,0,0,0,0,0,0,24266,0,0,0,0,0,0,0,0,26469,0,0,0,0,18604,2053,0, -33511,0,0,0,0,0,9222,0,0,0,0,0,44006,0,0,0,0,0,0,0,0,0,0,0,41895,0,0,0,0,0,0,0,0 -,12044,390,0,0,0,0,0,4935,0,48646,0,56102,3052,16070,0,0,0,0,0,0,0,8612,9320, -38311,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,500,0,0,0,0,42918,0, -32550,0,0,0,0,0,0,0,0,27434,57926,17064,0,0,46502,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,26760,6756,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,624,0,5000,0,0,0,0,32293,0, -0,0,0,0,0,0,0,0,0,0,0,0,26246,0,0,0,0,0,0,0,0,23,7301,0,0,0,36199,0,40838,0,0,0, -0,0,0,0,0,0,0,0,0,27178,57350,0,0,12457,9317,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 -,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,16810,0,0,0,14510,0,0,0,0,21319,0,0,0,13508,17, -11365,0,0,0,0,5291,0,8329,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,27685,0,0,0,0,0,0,0, -52006,0,0,0,7493,0,44263,0,0,0,0,0,0,0,0,9800,0,0,0,25676,61478,0,0,0,0,0,0,5773 -,0,0,0,0,41991,26057,0,0,0,0,0,0,0,0,0,0,22629,0,0,0,47783,362,1959,23468,0,0,0, -10921,0,0,0,3150,0,0,0,0,0,0,0,0,0,0,0,32456,0,0,0,0,0,0,0,4559,3270,0,0,983,0,0 -,26343,0,33446,0,0,0,61767,0,48390,0,0,0,0,0,0,0,2790,0,39782,7849,0,0,0,0,0,0,0 -,1544,2183,0,0,0,0,0,0,0,0,4040,2471,20009,30020,0,0,11242,0,0,0,5578,53382,0, -22631,0,0,0,0,0,0,0,0,0,0,0,12901,0,0,0,0,0,0,0,0,0,0,0,0,215,0,0,9030,0,0,0,0,0 -,0,265,1412,0,0,11626,3687,0,0,0,0,0,0,0,0,0,0,0,0,17449,24359,0,0,26729,40134,0 -,0,0,0,29768,61958,0,0,0,0,0,0,0,0,20908,0,0,0,0,0,11016,0,0,47462,21547,5926,0, -0,14728,2983,24104,15301,0,0,0,0,0,32645,0,0,0,0,0,0,0,3300,0,0,0,15972,0,0,0,0, -0,0,6634,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3076,0,30983,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,106,0,0,0,0,12775,0,0,0,0,7177,18022,0,0,0,0,0,22534,0,0,0,0,0,0,0,0,0,0,0, -49894,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,27560,0,0,0,0,30278,10668,23877,0, -0,0,0,0,0,0,29124,0,0,0,0,0,0,0,0,0,0,0,0,0,20870,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,44582,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,48454,0,0,0,0,6442,0,16330,22951,0,0 -,16904,0,0,0,0,644,0,0,0,40038,0,0,0,37222,0,0,0,9830,0,0,0,0,0,34919,0,0,0,0,0, -0,0,0,0,0,0,13733,0,0,0,28196,0,0,0,0,0,19876,0,0,0,0,0,0,0,23558,0,11142,0, -27781,0,0,0,0,13864,0,0,0,24682,47847,0,0,0,0,6890,0,0,0,0,0,3981,0,0,0,0,0,0,0, -0,0,0,0,1772,0,0,0,0,0,0,0,3603,1991,0,27396,8652,0,18312,0,0,0,0,30054,0,0,0,0, -0,0,0,11270,0,0,0,0,0,0,0,0,0,20708,0,0,0,0,338,0,0,0,0,0,0,0,7050,0,0,0,0,0,0,0 -,0,0,0,0,0,0,14862,0,0,3492,0,0,0,55878,0,0,0,16486,0,0,0,18119,0,0,0,0,0,0,2154 -,1284,0,0,23113,31751,0,0,29547,0,0,0,0,0,0,36647,0,0,0,0,0,0,0,0,0,0,0,18183,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,7913,0,0,0,0,20644,0,0,10508,0,0,0,0,0,0,0,0,0,0,0,0, -43622,0,0,0,0,0,40966,0,0,0,0,0,0,0,0,0,0,246,901,11529,5191,0,0,0,0,0,0,0,0,0,0 -,0,24454,0,0,26665,27590,0,27397,0,0,0,0,0,0,23562,2949,0,0,30344,62214,0,47334, -2026,18885,0,0,0,48678,0,0,0,22694,0,0,1972,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,15465,0,0,0,0,38822,0,0,0,0,945,32708,0,54791,0,14918,0,0,0,0,0,0, -0,0,0,0,0,0,0,23396,0,0,0,0,0,0,5486,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7722,0,0, -0,0,0,0,0,0,0,0,0,30856,64166,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,35206,0,0,0,30535,0, -0,0,0,0,0,0,0,0,62663,0,0,1096,17574,31820,0,0,14375,4402,27207,0,0,21448,4676,0 -,0,0,0,16585,5094,0,0,0,0,0,0,0,0,4845,0,0,32870,0,0,0,0,0,0,0,0,0,0,31466,0,0,0 -,0,31783,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4522,16039,0,0,0,0,0,0,0,0, -0,14469,0,0,0,0,0,0,0,0,0,0,7464,4773,0,0,0,0,0,0,0,0,18636,0,0,0,25640,0,0,0,0, -0,0,2244,0,0,11818,0,1168,0,0,0,0,0,0,0,6540,23079,13770,7719,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,58150,528, -34502,32682,0,0,12997,0,0,0,0,0,2214,0,0,0,0,0,58567,0,0,0,26375,0,0,0,0,0,0,0,0 -,0,26437,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,26121,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 -,0,32005,22952,59047,0,13543,0,0,0,0,0,0,0,0,16328,0,0,33542,0,0,0,19782,0,0,0, -16644,0,0,0,0,31688,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,10276,0,0,0, -0,0,0,0,36327,0,0,29480,0,0,0,777,12709,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,27398,0,0, -0,4455,9037,31397,0,9221,0,0,0,60487,20840,1796,0,0,0,0,0,0,0,0,8364,0,0,0,0,0,0 -,0,0,0,0,0,19752,44902,0,38566,0,0,18027,0,0,0,0,0,0,0,0,10662,0,0,0,0,0,11812,0 -,0,0,0,0,0,0,0,0,19910,0,0,0,45030,0,0,0,0,0,0,0,0,0,0,0,0,19978,5127,0,11620,0, +BROTLI_INTERNAL const uint16_t kStaticDictionaryHashWords[32768] = { +1002,0,0,0,0,0,0,0,0,683,0,0,0,0,0,0,0,1265,0,0,0,0,0,1431,0,0,0,0,0,0,40,0,0,0, +0,155,8,741,0,624,0,0,0,0,0,0,0,0,0,0,0,0,66,503,0,0,0,451,0,0,0,0,0,0,0,835,70, +0,0,539,0,0,0,0,0,0,0,0,0,113,0,0,0,0,718,0,0,0,0,0,0,520,0,1070,0,0,0,0,0,1515, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,78,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,610,0,0,750,0,0,0,307,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,964,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,999,0,0,0,0,0,0,0,0, +645,75,0,649,52,282,0,200,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1621,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,211,225,0,0,687,718,0,0,110,0,58,0,0,0,0,0,0,345,0,0,301,0,0, +0,203,0,0,1154,674,1949,0,0,0,0,0,0,0,0,0,259,0,0,0,0,0,0,0,1275,0,0,0,1231,254, +0,0,0,0,0,0,0,277,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,248,0,0,800,0,0,0,29, +116,100,490,0,0,0,0,0,1641,0,543,0,0,0,0,41,181,0,657,0,0,202,25,0,0,0,0,0,0,0, +0,0,0,423,0,0,0,113,0,0,0,927,963,0,976,0,206,0,0,0,0,0,0,0,0,0,2002,0,0,0,0,0, +0,0,0,0,0,0,696,0,1170,0,0,0,0,226,13,0,769,678,551,0,0,0,0,0,0,57,0,0,0,10,188, +0,0,0,624,0,0,0,0,0,0,0,0,0,1941,130,0,0,0,0,378,269,0,0,528,0,1146,0,0,0,1105, +0,1616,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,656,0,1940,0,0,0,0,0,173,0,0,0,0,0,0,0,0,0, +0,0,457,342,810,0,0,0,0,620,0,0,0,0,0,0,0,967,95,447,406,0,0,0,477,0,1268,944, +1941,0,0,0,629,0,0,0,0,0,375,0,0,0,1636,0,0,0,0,774,0,1,1034,0,0,0,0,0,824,0,0, +0,0,0,118,0,0,560,296,0,0,0,0,0,0,0,0,1009,894,0,0,0,0,0,0,0,0,0,0,0,0,0,1474, +366,0,0,0,0,0,0,0,0,0,79,1723,0,0,200,0,0,0,0,0,0,0,0,1759,372,0,16,0,943,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,258,0,0,900,1839,707,30,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,2004,0,0,10,115,0,50,0,0,0,0,0,0,0,0,0,0,520,1,0,738,98,482,0,0,0,0, +0,0,0,0,0,0,701,2,0,0,0,0,0,0,0,0,557,0,0,0,0,0,0,0,0,0,347,0,0,0,0,572,0,0,0,0, +0,0,0,0,0,832,0,0,797,809,0,0,0,0,0,0,0,0,0,0,0,528,0,0,0,861,0,0,294,0,0,0,109, +0,0,0,0,0,0,0,0,1187,290,266,0,0,0,0,49,50,748,0,0,466,399,0,0,0,0,0,0,0,378,0, +519,0,0,0,0,0,0,0,0,0,0,0,0,667,351,902,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,180, +0,0,869,0,0,0,0,0,0,0,260,0,0,0,0,0,0,0,0,0,0,523,36,0,0,587,510,809,29,260,0,0, +0,0,0,0,0,0,570,0,565,0,1464,0,0,0,0,0,0,10,0,0,787,399,380,200,0,0,0,0,516,0, +844,887,0,0,0,0,0,0,0,44,0,0,0,305,1655,0,0,0,0,0,0,0,0,0,0,0,0,0,0,786,10,0,0, +0,0,0,0,0,0,0,2031,0,0,0,0,0,684,0,0,0,0,0,1480,0,0,0,27,0,0,0,395,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,813,511,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,56,0,0,0,206, +496,0,0,0,0,0,909,0,891,0,0,0,0,0,0,0,0,0,687,0,0,0,1342,0,0,0,0,0,0,0,0,0,0, +160,41,0,0,0,0,0,0,0,0,0,0,0,1718,778,0,0,0,0,0,0,0,0,0,0,1610,0,0,0,0,0,115,0, +0,0,0,314,294,0,0,0,983,178,193,0,0,0,0,0,0,0,0,0,174,0,0,0,0,0,0,0,0,0,0,848, +1796,0,0,0,0,0,0,221,0,687,1660,0,0,0,0,262,0,0,179,0,0,0,0,0,66,0,773,0,352,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,35,0,152,0,0,1197,0,0,0,0,0,0,0,0,0,0,0,0,560,0,0, +564,0,0,0,797,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,556,0,819,0,0,0,0,0,0,0,0,719,544, +637,5,0,0,0,0,0,0,0,0,0,0,0,101,0,1441,0,0,0,893,0,0,0,0,0,0,0,0,0,238,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,1296,0,0,969,1729,314,60,0,0,0,0,0,1144,0,1147,0,0,0,0,0, +0,0,0,0,0,437,1853,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,828,0,176,0,0,0,0,0,0,434,39,0, +0,0,0,0,159,0,0,0,902,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,270,0,0,0,0,801,556,0,0, +0,0,0,0,0,416,19,197,369,0,0,0,0,0,0,0,0,0,28,34,0,757,0,0,898,1553,0,721,0,0,0, +0,1012,0,0,0,0,1102,0,898,183,0,0,0,0,0,0,0,136,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,247,277,0,0,0,435,0,0,0,0,0,1311,0,0,0,0, +0,0,211,437,0,0,0,28,0,0,750,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2012,0,702, +0,808,0,0,0,0,739,166,0,0,0,0,0,0,719,170,500,0,0,0,0,0,0,0,0,1500,327,0,0,450, +0,0,0,1318,0,0,0,1602,0,0,331,754,0,0,0,0,0,1368,0,0,557,0,0,0,799,850,0,0,0,0, +0,0,0,0,908,0,0,0,0,0,19,62,459,0,0,0,0,0,0,0,0,0,0,0,0,1802,0,0,0,0,0,0,0,0,0, +1397,0,0,0,0,120,238,0,0,0,0,0,0,0,0,0,0,0,1324,0,0,0,0,0,0,0,0,602,201,0,0,164, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,615,0,0,0,0,0,0,0,0,0,0,0,0,0,1243,0,0,0,0,968,0,0, +0,0,0,0,882,0,0,0,907,329,100,0,0,0,0,0,0,0,0,0,0,0,176,26,9,0,0,265,256,0,0,0, +0,0,0,0,0,0,643,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,127,610,0,0,0,0,973,2001,0, +0,0,0,0,0,522,0,0,0,0,0,0,0,0,0,0,0,553,0,0,0,0,0,0,1582,0,1578,0,0,0,0,0,0,0,0, +0,0,0,795,0,0,0,432,0,0,0,0,0,0,84,126,0,0,0,0,790,0,377,64,0,1529,0,0,0,0,530, +1857,539,1104,0,0,0,0,0,0,0,0,0,0,0,0,977,0,0,0,34,0,0,0,0,0,0,0,0,0,0,0,24,26, +0,0,918,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,183,379,0,0,0,0,0,0,0,792, +0,0,0,0,0,0,0,0,0,1920,0,0,0,0,0,0,0,0,0,771,0,0,0,1979,0,901,254,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,140,0,0,0,0,0,440,37,0, +508,0,0,0,513,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8,0,0,533,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,752,920,0,1048,0,153,0, +0,391,0,0,1952,0,0,0,0,0,0,0,0,0,0,126,0,0,0,0,640,0,483,69,1616,0,0,0,0,0,734, +0,0,0,0,0,0,480,0,495,0,472,0,0,0,0,0,0,0,0,874,229,0,0,0,0,948,0,0,0,0,0,0,0,0, +1009,748,0,555,0,0,0,0,0,0,193,0,653,0,0,0,0,0,0,0,0,0,0,984,0,0,0,172,0,0,0,0, +0,0,0,0,83,1568,0,0,384,0,0,0,0,0,0,0,164,880,0,0,0,0,0,0,0,0,0,0,0,367,121,0,0, +828,0,0,0,0,0,0,0,1541,0,0,0,0,0,0,0,343,0,0,0,0,0,0,0,0,561,57,0,0,0,0,0,0,0, +926,0,0,0,0,827,0,194,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,22,0,0,0,0,0,0,0, +0,0,0,896,1249,0,0,0,0,0,1614,0,0,0,860,0,0,0,0,0,0,0,0,964,102,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,899,0,569,0,0,0,0,795,2045,0,0,0, +0,0,0,104,52,0,0,0,0,0,604,0,0,0,0,779,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,32,0,0,0,0, +494,0,677,0,0,0,0,0,0,0,508,0,0,0,0,0,0,0,0,0,1014,0,957,0,0,630,310,0,0,0,570, +0,0,449,0,64,537,0,0,0,0,0,0,0,244,0,0,0,0,0,0,0,0,0,0,0,0,0,0,702,1650,49,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,338,0,0,0,0,1279,0,0,0,0,0,0,0,896,0,0, +178,0,0,0,0,0,0,0,0,0,0,0,0,0,808,695,0,0,0,0,539,1117,0,0,0,0,0,0,0,0,257,0, +1003,0,0,0,1,448,0,516,0,0,960,0,125,4,0,1268,30,748,0,0,852,0,0,0,6,0,0,848, +236,1385,862,1811,0,0,0,0,698,803,0,0,0,0,0,0,0,610,992,0,0,878,0,1847,0,0,0,0, +0,0,0,383,0,1404,0,0,0,0,986,0,347,0,0,0,0,0,0,0,0,0,0,0,592,572,0,1411,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,64,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,606,0,0,0,0,0,0, +0,0,0,0,0,0,0,1829,0,0,0,0,0,0,0,0,0,0,0,0,700,748,0,0,0,0,0,0,365,0,0,127,0,0, +83,198,0,0,0,0,0,0,864,55,0,0,0,0,726,1752,0,0,0,0,0,0,0,0,0,0,0,0,0,1066,0,764, +0,0,0,0,683,0,550,309,0,0,874,1212,0,0,0,1364,0,986,381,723,0,0,0,1573,0,0,0,0, +0,1025,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1559,0,0,0,0,493,133,0,0,0,0,148, +119,0,0,0,0,0,0,537,14,541,0,635,126,0,0,0,495,0,0,0,0,861,998,1009,0,0,0,0,0,0, +0,359,368,0,0,0,0,304,1577,0,0,0,0,0,1107,0,0,0,0,0,929,0,0,0,1142,0,0,0,0,289, +175,0,432,0,219,0,0,0,0,0,785,0,0,595,0,0,0,0,0,0,0,0,0,0,0,0,0,80,0,0,0,0,0,0, +931,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1323,0,0,0,0,290,0,559,1751,127,0,0,0, +934,1167,0,963,0,260,0,0,0,573,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +580,1689,0,0,0,0,0,0,0,0,0,1164,0,0,982,1922,0,63,0,0,0,0,0,793,0,0,0,0,0,0,0,0, +0,0,0,0,0,67,790,0,0,0,0,0,0,0,0,0,0,391,443,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,271,0,0,0,0,0,0,0,0,0,0,0,1140,0,0,0,0,340,300,0,897,0,0,0,0,0,0, +0,0,0,0,890,0,0,0,0,818,321,53,0,0,0,0,0,0,0,0,0,468,0,243,0,870,0,0,0,1765,121, +0,0,0,180,518,0,822,419,634,0,0,0,0,0,0,0,0,0,898,0,0,0,0,454,36,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,806,0,0,0,0,0,0,0,0,0,0,0,0,1326,0,104,0,0,0,0,0,0,0, +0,0,260,0,0,0,0,0,0,0,0,0,0,0,0,542,45,0,0,263,1516,42,0,0,0,0,0,468,0,1005,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,288,87,0,0,0,0,0,0,0,0,502,988,133,0,0,0,0,0,0, +141,0,0,872,1842,0,0,0,0,0,0,0,0,261,619,0,0,0,0,189,246,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,678,0,0,0,0,0,0,0,0,0,0,0,0,285,35,0,517,0,0,0,0,0,0,0,0,0,0, +540,214,667,0,74,0,0,125,0,0,0,0,0,761,131,0,0,0,0,0,0,0,0,0,0,0,0,0,333,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1338,94,0,0,0,0,0,0,0,0,0,0,0,0,449,0,646,103, +86,641,2028,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,869,87,277,117,39,0,0,0,0,0,0,0,0,938, +297,0,0,0,0,558,464,0,0,0,0,0,0,0,0,0,0,731,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1608,0, +0,0,0,0,0,0,1429,0,0,733,1010,0,0,338,1656,0,0,0,1038,979,2010,0,0,0,0,0,0,0, +1005,0,0,121,0,0,0,219,20,0,0,0,0,0,0,872,1440,0,0,0,683,0,1070,0,0,522,0,0,0,0, +439,669,0,0,0,0,0,0,0,0,1245,0,0,0,0,0,1218,0,0,547,233,0,0,0,0,0,0,0,0,0,482,0, +0,0,0,0,0,0,886,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,795,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,371,0,0,0,0,0,0,0,0,0,0,0,0,0,622,0,625,0,0,0,339,29,0,0,338,0,0,0, +0,130,0,0,0,0,0,0,0,0,0,307,0,0,0,0,0,0,0,0,0,0,2044,0,0,0,0,0,0,0,0,308,770,0, +0,0,0,0,1266,0,0,0,0,0,0,0,0,0,400,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,690,739,0,0, +0,0,0,0,0,990,0,0,0,1831,0,0,0,0,0,0,0,0,0,0,0,0,0,613,0,0,0,0,0,0,0,0,0,0,0,0, +0,763,0,878,0,0,0,977,0,100,0,0,0,0,0,0,0,0,0,463,0,0,0,0,623,318,0,0,296,463, +137,0,0,454,0,0,0,1527,58,0,0,0,0,0,0,0,18,48,0,0,0,0,0,729,0,0,0,442,0,0,0,0, +40,449,0,853,0,0,0,0,0,0,227,0,0,0,0,0,0,1491,0,0,0,0,0,0,0,0,0,0,161,55,0,450, +0,1174,62,0,207,0,0,0,0,0,0,0,0,869,0,0,0,0,80,213,0,0,0,0,0,0,0,0,0,0,354,820, +0,0,747,0,0,0,954,0,0,1073,0,556,0,0,0,692,0,191,0,804,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,831,162,0,0,35,0,0,0,0,0,0,0,0,1235,0,0,0,0,0,1234,0,0, +0,0,0,0,0,0,0,0,96,0,0,0,0,0,0,0,149,0,0,0,902,204,0,0,833,0,287,366,0,0,0,0,0, +0,992,2020,0,0,0,0,0,0,0,0,0,0,0,356,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,784,0,0,567, +630,0,0,0,539,0,0,27,0,0,0,0,0,0,0,0,0,0,755,0,0,0,0,0,0,0,0,0,0,0,0,814,0,0,0, +0,0,0,0,0,0,0,0,0,0,987,0,0,255,761,194,0,1086,0,0,0,0,0,0,1016,0,0,1396,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,562,271,913,0,0,0,0,0,0,0,0,320,153,45,475,0,0, +0,0,0,0,0,713,0,327,0,0,0,0,0,0,604,552,3,359,0,0,0,0,853,80,0,0,0,0,0,0,0,2016, +6,887,0,0,0,0,975,0,961,0,0,0,0,0,916,1891,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,100,101,390,708,0,0,0,587,983,512,0,0,0,0,0,0,0,0,0,0,0,645,0,0,0,851,0,0,0, +0,0,498,140,217,0,0,0,1448,0,0,0,0,0,0,0,0,0,905,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +643,105,0,792,0,0,0,0,0,0,0,0,0,0,0,0,56,0,0,0,0,0,0,0,0,0,0,535,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,1748,0,0,0,0,0,754,0,0,0,0,0,0,0,0,0,0,0,0,91,0,0,1565,0,91,792, +939,3,370,0,0,0,0,95,0,0,0,0,551,7,619,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1150,0, +0,0,0,0,0,0,0,0,0,0,0,0,671,0,0,0,0,0,888,368,149,0,0,105,1134,0,983,0,0,458,31, +0,643,0,0,0,312,0,740,0,0,0,1642,0,0,0,0,0,0,0,236,0,0,0,0,0,0,0,59,68,0,0,0,0, +0,867,795,0,0,0,0,970,1977,0,0,0,0,0,0,0,1148,0,775,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,970,0,0,0,0,0,0,0,0,0,665,71,0,0,0,0,827,0,0,0,0,0,0,0,0,0, +0,479,0,0,0,0,0,0,0,0,99,607,0,0,0,0,0,0,0,1960,0,0,0,793,0,0,871,41,0,0,241,94, +0,0,0,0,209,0,0,1497,0,0,0,0,0,0,0,0,0,98,0,0,0,463,0,0,0,0,291,0,0,0,0,0,0,0,0, +0,0,984,0,0,0,0,0,205,0,0,0,0,0,0,205,42,0,801,0,0,0,0,0,635,0,0,533,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,371,0,1282,0,0,0,825,0,0,0,0,0,0,0,0,0,357,879,467,0,317,0,0, +0,0,0,0,0,924,0,0,0,0,849,1795,0,0,0,0,895,1799,43,0,0,0,0,0,0,0,0,0,0,1820,0,0, +0,0,0,0,0,525,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,110,0,493,0,174,417,0,0, +0,0,0,583,733,0,0,0,0,0,0,481,215,0,0,0,0,477,0,0,0,0,0,0,0,0,308,0,0,0,0,0,0,0, +0,297,126,0,0,361,1551,0,0,0,0,0,0,871,1807,0,0,0,0,0,1307,0,685,0,0,0,0,0,0,0, +797,0,858,0,565,0,0,0,0,0,0,0,0,0,0,0,0,434,252,826,0,0,0,0,0,0,791,0,0,0,0,509, +231,178,601,0,0,0,0,0,0,0,0,43,1591,0,0,0,0,0,1683,0,0,0,0,45,0,0,0,0,0,0,0,0,0, +0,1120,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,556,494,0,398,0,0,0,1030,0,0,0,0,0,0, +168,0,0,0,0,0,0,0,0,0,0,973,0,642,0,0,0,0,0,0,0,0,0,1615,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,378,594,0,1093,0,679,112,0,0,0,0,1492,540,1374,714, +1486,0,0,0,0,825,1511,0,0,0,0,0,0,0,0,0,0,0,0,0,952,0,0,736,143,0,700,0,1540,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1557,0,0,0,860,990,0,0,0,807,0,0,0,0,0,131, +515,0,646,0,0,0,0,117,728,508,121,0,0,0,0,0,0,357,0,0,0,0,0,0,237,0,0,0,0,0,0,0, +0,0,1784,0,0,0,0,0,0,0,0,0,0,0,713,348,1536,0,738,0,0,0,0,0,0,0,434,0,0,0,0,0,0, +366,1877,39,0,0,0,0,0,0,580,0,0,0,0,0,0,0,0,0,0,0,0,0,0,873,0,0,0,0,171,0,625, +550,107,343,943,0,0,0,0,0,0,0,768,0,0,0,0,0,0,0,799,0,0,0,894,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,1673,0,0,0,0,0,0,0,0,0,0,0,1052,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +272,0,441,0,0,3,9,0,0,0,1182,0,1346,0,0,0,0,0,0,0,0,682,0,0,1004,24,0,0,968,0,0, +0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,185,0,0,0,578, +474,0,0,0,0,0,0,0,0,0,0,0,0,0,0,113,530,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,556,0,0,0,0,0,0,16,1317,0,0,97,0,0,0,703,0,0,0,0,0,0,0,0,892,0,0,0,1571,0,0, +426,186,0,1101,0,0,0,0,0,0,0,0,937,585,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,644,291, +0,0,0,0,749,0,162,0,0,381,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,762,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,628,21,0,0,0,0,0,0,0,0,919,0,0,0,0,0,0,0,0,0, +633,0,0,0,0,332,0,0,0,0,0,0,0,0,0,1489,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,832,398,0,645,0,0,0,13,0,0,0,0,0,0,0,0,0,0,20,0,800,0,0,0,0,0,0,0,0,0, +0,0,0,0,1993,0,0,0,0,769,0,0,0,665,0,0,0,0,0,0,0,0,0,0,1426,0,0,0,0,60,0,0,0, +641,1874,0,644,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1757,0,0,0,0,0,937,0,1652,0,654,0, +0,0,0,0,0,0,527,0,0,0,0,0,0,0,0,0,0,0,0,0,226,0,0,0,0,0,1486,0,0,0,0,0,0,0,0,0, +0,0,325,0,0,0,0,0,0,0,1345,0,0,91,0,404,0,0,0,0,0,0,0,0,0,0,0,0,973,0,0,0,0,0,0, +0,1176,0,549,0,0,0,0,0,0,0,0,0,0,976,0,0,0,0,0,21,0,0,0,0,0,51,0,0,0,0,314,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,0,0,0,0,0,0,0,0,198,6,0,1093,0,0,0,0,0,0,0,0,0, +0,0,0,0,1776,0,0,0,0,0,1528,0,419,0,0,0,0,0,0,0,0,76,138,0,0,0,0,638,29,0,0,0,0, +0,0,0,1418,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1710,0,0,0,0,0, +0,0,0,0,0,0,0,532,23,0,0,0,0,0,0,0,862,0,0,946,592,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,70,0,0,0,0,0,0,0,0,0,812,0,0,0,76,0,0,988,0,442,0,0,0,896,0,0,0,0,0,0, +483,0,0,0,0,1709,0,0,0,0,0,0,119,0,0,0,117,0,309,0,0,0,0,0,596,976,0,0,0,0,0,0, +0,0,0,0,0,768,0,0,0,0,0,0,0,0,0,518,0,0,0,0,0,0,0,0,0,0,0,0,0,0,863,0,0,0,24, +145,1020,0,0,1984,0,0,0,0,0,0,0,658,0,0,0,0,0,0,0,0,0,0,106,1827,0,1010,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,582,87,0,0,0,0,0,0,0,267,0,0,0,703,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,496,0,0,0,0,1121,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,249,561,0,0,0,0,0, +0,0,760,0,0,154,0,0,0,255,0,419,323,0,0,0,0,0,368,0,0,0,0,0,0,0,0,0,0,522,0,0,0, +0,0,0,0,551,562,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,92,0,0,0,0, +0,0,0,284,525,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,958,0,0,594,0,0,0,0,0,0,6,479,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,61,0,0,0,0,0,0,0,820,1641,0,1556,0,0,0,0,0,0,0,302,0,0, +0,0,0,148,0,0,676,0,0,0,0,0,0,1674,0,0,0,0,0,0,178,0,0,0,0,0,0,0,94,389,0,0,0,0, +91,8,0,0,0,0,0,0,0,0,0,0,112,0,0,0,0,0,0,0,0,0,0,747,0,0,0,0,0,0,0,1746,0,0,0,0, +0,24,0,1352,158,1530,0,0,718,130,280,1401,0,0,0,0,0,1946,8,0,0,0,0,1607,0,0,0,0, +0,0,882,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,417,0,0,0,1597,633,433,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,18,234,0,0,0,0,0,0,0,0,680,1950,0,0,0,0,249,5,0,0,0, +0,0,0,0,0,0,1216,0,1773,0,0,0,0,0,0,0,0,0,0,0,0,0,0,509,180,0,0,0,0,0,0,0,1002, +0,0,0,0,0,0,0,0,0,0,0,0,0,931,0,0,0,0,0,0,0,0,747,943,0,1837,0,0,0,0,0,0,0,641, +0,0,0,0,280,0,0,0,5,0,0,0,0,0,72,545,0,0,0,0,0,0,0,0,0,742,0,0,254,151,872,0,0, +0,0,0,0,0,0,0,0,0,0,921,0,0,517,833,0,1680,0,0,436,251,584,0,0,0,0,0,0,0,0,0,0, +0,24,500,0,0,0,0,0,0,0,0,195,1775,514,389,0,0,0,0,0,0,0,743,0,0,0,0,0,0,292,0,0, +0,227,1283,774,1805,0,0,0,0,0,0,0,0,0,0,119,81,0,0,0,0,0,0,0,0,0,0,0,0,0,0,913, +1910,0,0,0,1826,490,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1162,700,30, +0,0,0,721,839,0,0,0,617,0,0,0,0,0,0,0,0,0,169,428,0,0,0,0,0,1648,637,1205,0,0,0, +1596,0,0,4,266,0,0,0,0,0,0,0,0,0,0,0,862,0,0,0,0,0,0,0,0,0,0,16,0,0,0,0,0,0,0,0, +0,279,157,391,604,0,0,713,945,877,973,0,0,0,0,0,0,0,0,0,0,0,0,0,0,859,567,628, +1846,0,0,0,0,0,0,0,0,0,762,0,0,191,0,0,0,0,298,0,0,767,909,0,0,0,0,0,0,0,795,0, +0,301,0,0,1970,0,0,0,0,0,0,0,0,0,1236,0,0,0,0,0,0,644,369,15,0,160,71,0,0,0,0,0, +1447,0,0,0,0,0,0,0,0,735,1255,76,0,0,0,0,0,0,0,0,0,0,474,0,0,0,0,0,0,0,0,0,0, +841,0,0,0,0,0,0,0,0,0,0,836,0,0,0,0,0,1622,0,0,735,0,0,0,0,1601,804,1390,394,0, +0,0,0,0,0,96,0,289,0,0,35,688,0,0,0,667,0,513,0,0,0,0,0,0,0,2034,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,704,0,1524,0,1078,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,306, +0,0,0,0,0,0,0,431,0,1196,0,0,54,0,15,1448,0,1418,0,0,0,0,0,0,0,0,0,907,0,0,0,0, +0,0,194,1767,0,0,0,0,0,840,0,900,0,0,0,0,0,0,0,0,0,0,0,1436,0,0,0,0,642,1560,0, +0,0,0,0,0,94,386,0,0,0,0,0,0,0,0,0,0,830,416,0,0,20,731,0,0,0,0,0,0,0,0,697,0,0, +662,0,0,0,0,0,0,0,0,0,861,0,0,0,0,0,0,0,871,671,864,0,928,7,0,332,0,0,0,0,1055, +0,0,0,0,0,0,986,0,0,0,0,0,44,76,0,0,0,0,0,0,0,0,0,0,300,0,0,0,0,0,0,0,175,518, +831,1108,0,0,0,836,0,1852,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,843,1804,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,246,0,0,0,610,202,0,0,36,0,0,0,240,654,13,0,0,0,0,0,0,0, +0,391,0,403,0,0,0,0,0,0,0,0,0,0,75,0,366,815,0,0,631,0,0,0,0,0,0,0,0,345,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,952,0,0,0,0,0,0,0,0,0,0,0,673,35,662,0,287,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,5,34,0,0,0,0,0,0,0,0,151,0,427,0,0,382,0,0,0,329,0,0,279,0,0,0, +0,0,0,0,0,0,0,906,0,0,366,843,0,1443,0,1372,992,0,36,123,0,649,0,0,0,0,0,767,0, +1018,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,995,0,0,0,0,0,0,0,72,368,0,0,1345,0,0,0, +589,0,0,0,0,0,0,0,0,0,1988,0,0,220,541,0,0,0,686,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,32,196,0,0,0,0,0,0,0,0,0,0,0,0,0,381,0,0,0,0,0,0,0,0,0,1452,0, +0,0,616,0,0,0,0,0,0,0,0,0,1229,0,0,0,0,0,0,0,0,0,0,667,120,0,0,0,0,0,0,0,1146,0, +0,0,0,0,0,0,0,0,0,0,352,0,0,0,0,0,293,0,0,0,0,0,0,0,0,0,0,0,0,0,935,0,1050,0, +147,88,0,0,923,0,0,0,0,0,934,0,0,0,0,0,0,0,0,114,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,341,222,0,0,0,0,0,0,0,0,0,0,293,0,0,0,0,0,0,0,0,0,0,0,0, +637,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1159,0,0,0,847,0,0,0,0,0,0,683,0,867,944,0,0, +0,0,0,1809,0,0,0,0,0,0,0,0,0,0,395,170,0,0,0,0,0,0,0,0,0,0,618,535,0,1625,0,0,0, +0,0,0,0,0,23,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,778,0,0,0,0,0,46,0,2032,0,0,37, +1458,0,938,363,34,0,0,0,0,0,0,0,0,0,0,0,0,0,0,314,0,0,0,0,0,0,889,0,0,0,0,0,0,0, +0,0,0,0,462,0,0,0,0,525,0,0,23,0,0,0,0,0,0,0,0,0,0,0,676,0,0,0,0,0,0,0,0,0,0,0, +0,498,725,0,0,0,0,7,0,0,0,0,773,0,0,0,164,0,0,0,0,0,0,0,0,936,583,659,1462,0, +220,0,0,0,0,803,0,0,544,119,0,0,0,0,0,0,0,0,0,0,0,181,176,0,1192,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,1878,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,26,0,0,0,0,0,0, +944,0,0,0,0,0,0,0,273,0,0,0,0,0,855,0,0,0,0,5,127,0,0,0,0,0,0,0,0,752,230,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,68,162,0,654,48,156,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,240,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,197, +0,0,0,0,0,0,0,963,0,0,0,0,0,0,0,0,0,0,858,0,0,0,0,0,0,0,0,0,0,676,1978,0,0,102, +972,0,0,0,0,0,0,0,361,0,461,0,0,0,472,0,0,0,0,0,0,0,0,0,0,0,0,0,0,747,905,0,0,0, +155,0,0,0,0,0,0,0,0,0,0,319,163,0,0,0,0,0,0,0,0,0,848,0,0,36,631,0,0,0,0,0,1769, +0,0,0,0,0,144,0,0,0,0,0,0,0,0,0,0,369,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,555,247,0,0, +996,0,0,189,0,0,0,0,0,0,0,0,0,0,280,0,0,0,0,0,0,0,0,0,0,0,526,746,0,0,345,0,0,0, +1017,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,651,428,0,0,0,1162,230,327,546,792,0,0,0, +1203,0,0,0,0,0,0,0,0,0,672,189,0,0,0,0,0,0,99,0,0,0,298,0,0,0,0,0,0,555,397,0,0, +0,0,0,1157,0,0,0,0,0,0,0,0,0,0,398,1523,0,366,0,0,787,0,0,0,282,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,157,0,941,0,0,0,0,0,1336,0,0,116,0,0,0,0,0,0,787,0,0,0,0,0,0,0,0,0, +0,170,160,0,1815,0,0,0,0,0,866,0,0,0,0,0,0,0,0,0,689,0,0,0,0,820,0,498,108,0,0, +0,1119,0,0,0,244,609,1005,0,581,0,0,0,0,0,895,0,0,0,1898,0,0,0,0,0,926,0,0,0,0, +0,0,0,0,0,0,0,0,0,538,496,294,301,0,0,0,18,0,0,757,0,0,0,0,0,1263,0,820,0,722,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2028,0,0,0,0,124,1875,0,0,0,881,0,0,0,1348, +0,0,0,0,0,0,0,911,0,954,0,0,0,0,414,0,0,0,0,517,0,0,0,0,0,816,0,0,0,0,0,0,0,0, +713,0,0,0,0,0,0,0,33,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,593,150,0,0,0,0, +0,553,0,0,0,0,0,0,0,0,0,0,108,0,0,0,0,420,0,0,0,0,0,0,0,0,0,0,0,1777,0,0,55,493, +0,0,81,0,321,980,0,0,0,0,0,0,0,0,0,0,0,0,0,0,362,112,0,74,0,0,0,0,0,0,0,625,0,0, +0,0,0,0,377,16,0,0,61,281,0,0,0,0,0,0,0,0,0,0,0,0,0,0,224,1031,0,0,0,0,0,0,51,0, +0,0,0,0,0,0,211,309,15,125,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,789,173,0,439,9,648, +0,0,294,0,0,0,0,0,0,0,374,8,0,1099,0,0,0,0,0,0,0,575,0,0,0,518,0,0,0,702,0,0,0, +0,0,0,87,0,0,0,438,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,464,122,0,0,0,1802,0,0,0,0, +0,0,499,0,0,0,87,476,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,840,283,0,0,0,0,1620,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,609,1160,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,600, +323,372,0,0,0,0,471,722,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,0,0,0,0,0,0,0,0,0,0,0, +477,1304,0,1774,0,0,88,0,438,12,0,0,0,0,0,0,0,0,671,997,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,639,22,0,0,782,681,0,0,0,0,0,0,0,0,0,0,1013,664,0,942,0,1349,0,0,0,0,0,0,0, +0,0,0,0,0,356,0,0,32,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,215,289,0,1975, +109,450,0,0,0,0,0,0,0,0,0,0,705,0,0,664,0,0,0,0,0,0,0,1238,0,0,318,0,0,0,0,0,0, +0,0,0,0,0,0,0,960,1872,0,0,0,0,0,0,0,0,0,0,0,0,0,0,103,0,0,0,0,0,0,0,0,0,239, +777,0,26,0,0,0,0,0,0,0,0,0,0,0,0,375,414,0,17,0,0,0,1350,0,955,0,0,0,0,0,0,0,0, +887,960,0,0,0,0,0,0,0,0,0,0,708,710,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,919,0,0,0, +0,502,280,7,45,0,0,0,0,777,0,0,0,0,410,0,1110,0,0,0,0,0,0,414,341,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,787,0,0,0,436,0,0,0,0,0,0,0,1707,613,377,96,0,0,0,0,451, +0,0,0,0,0,0,0,0,0,0,0,0,0,680,0,483,916,0,0,0,0,0,0,937,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,739,0,0,0,0,0,0,0,0,82,0,0,663,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,128,0,0,0,0,0,0,0,0,1087,0,0,0,0,0,0,0,503,0,0,0,0,0,0,9,113,104,324,0,460,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,935,702,434,485,1014,949,423,0,900, +0,0,0,0,0,0,0,2018,574,0,0,0,0,0,0,0,0,0,0,0,0,1206,0,0,0,0,0,0,0,0,38,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,1022,0,0,0,0,143,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,2029,0,0,0,0,0,0,0,0,0,0,0,0,523,0,0,0,0,0,0,625,0,0,425,37,0,0,0,1943,0,0,0, +0,0,765,0,0,0,0,0,0,0,0,0,0,551,0,0,0,0,0,0,0,0,0,0,0,0,168,0,0,1010,0,0,1994,0, +0,0,91,0,0,0,0,532,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1884,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,240,15,0,0,0,1227,0,1534,0,0,0,0,0,0,0,0,0,0,0,0,0,0,392,0, +0,0,0,0,0,0,0,0,0,0,0,655,562,395,0,0,0,501,1019,0,0,0,0,509,267,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1099,0,0,0,0,0,0,948,0,0,0,0,0,0,0, +462,114,0,0,258,404,0,1717,0,0,0,0,82,1061,0,724,0,0,0,0,0,1133,0,0,0,0,0,0, +1021,841,0,1021,0,0,0,0,0,0,0,0,0,0,488,373,37,0,0,0,0,564,0,0,0,0,0,513,0,0,0, +825,0,0,899,0,0,778,0,0,12,1417,0,1116,0,0,0,0,0,0,0,0,0,0,0,0,0,0,114,545,0,5, +0,0,0,0,0,0,0,192,0,0,763,0,0,0,0,0,0,0,755,759,0,0,0,0,0,0,0,0,0,370,0,1237,0, +0,0,0,0,0,298,87,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,31,0,0, +0,0,0,0,814,991,0,757,57,0,0,0,0,0,0,0,0,0,540,0,0,0,0,608,0,0,0,0,0,0,0,0,1014, +0,0,0,902,0,0,0,0,553,1668,0,0,0,0,0,0,0,0,0,559,60,0,0,0,0,0,511,0,0,675,0,0, +156,0,0,0,0,0,0,709,0,698,0,0,0,1745,0,0,0,0,0,0,0,0,0,714,0,0,0,0,0,0,0,0,206, +8,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,776,0,0,0,0,0,0,0,0,0,1272,0,0, +0,0,0,1059,0,0,0,0,0,0,406,0,0,0,0,0,0,0,0,0,0,947,0,0,0,0,0,0,168,0,0,0,0,0,0, +870,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,554,0,0,0,0,784,908,0,0,0,0,0,0, +0,396,358,0,0,0,0,0,0,0,0,2,228,0,0,0,0,0,0,0,0,0,0,0,845,14,0,716,1820,594,0, +81,1428,0,161,0,782,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,64,0,0,0,0,0,998,0, +0,0,0,0,0,0,0,0,0,0,0,1043,0,1496,0,0,0,0,0,0,0,0,781,0,0,0,0,0,0,0,817,1114,0, +1814,958,0,0,0,0,812,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,139,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,236,643,0,0,0,0,0,0,0,0,0,1172,0,0,0,0,0,0,0,0,0,1338,0,0,0, +0,0,0,0,0,0,0,0,54,0,0,0,256,0,0,351,0,955,1885,0,469,0,0,0,1270,0,744,0,313,0, +0,0,0,0,0,0,0,402,969,0,0,0,0,0,0,50,0,0,0,0,572,0,0,0,0,847,0,0,0,0,0,0,0,248, +43,0,369,0,0,0,0,0,0,0,0,0,0,0,0,0,766,0,363,0,0,0,0,0,0,0,0,0,0,0,678,0,0,409, +258,82,249,0,0,0,0,0,0,0,0,0,0,0,0,32,393,0,788,0,0,0,1281,509,1968,0,0,0,0,39, +291,0,0,0,589,0,0,54,1059,0,0,0,0,0,0,824,0,0,0,0,0,0,0,0,0,0,1005,0,1598,0,0,0, +0,0,919,0,0,0,0,0,0,0,0,52,132,0,0,0,0,0,328,0,0,0,0,173,0,0,0,0,0,65,1411,0,0, +0,0,0,0,0,0,0,0,442,0,842,0,0,0,0,0,0,0,0,0,534,0,0,0,0,0,0,0,0,0,0,0,0,0,845, +210,0,0,0,0,0,0,0,0,892,0,0,223,0,0,0,0,529,0,0,0,807,0,137,218,0,1444,0,0,0,0, +0,332,661,0,0,0,0,0,0,0,76,1517,0,0,0,0,0,0,0,0,0,0,0,418,0,0,0,0,0,0,0,0,481, +379,0,0,0,0,0,149,18,0,0,0,0,0,0,0,0,742,304,142,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,799,925,195,51,0,0,0,0,688,0,0,0,0,697,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,1169,751,0,0,0,452,929,0,221,0,1437,0,0,0,0,955,1251,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,192,0,132,0,0,0,0,0,865,0,0,0,0,0,0,0,767, +672,42,0,0,0,1050,0,0,0,0,0,0,0,0,368,44,0,0,0,0,0,0,0,570,29,0,0,0,0,0,0,227,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,522,0,0,0,0,0,0,0,1529,0,0,0,0,0,0,739,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,1667,0,0,0,0,0,0,132,511,0,138,208,1020,0,0,23,565,0,344,0,0,0, +0,0,922,0,0,0,0,0,0,0,240,0,0,415,171,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,402,0,0,754,31,716,0,982,731,0,0,0,0,0,0,0,888,0,0,0,803,847,0,0,823, +0,0,0,0,0,0,785,0,0,2,0,0,0,0,0,0,0,532,0,0,681,0,0,314,0,384,684,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,649,447,0,1818,1007,0,321,0,66,360,0,0,0,385,0,0,0,0,0,0, +0,900,73,254,0,0,0,0,683,1959,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,86,0,0,725,0,0,0,0,0,196,0,0,0,0,0,831,0,0,0,0,723,0,0,0,0,0,994,627,0,0, +0,0,0,0,0,0,0,0,764,66,0,0,0,0,205,36,0,0,0,0,0,0,0,950,0,0,0,887,111,0,0,831, +388,165,0,0,0,0,0,155,0,0,0,0,0,0,0,0,0,0,0,0,0,0,780,755,0,0,0,0,898,146,0,0,0, +0,0,0,0,45,7,0,0,0,0,0,0,0,0,607,0,0,0,0,0,0,65,0,0,0,0,0,0,0,0,0,88,0,0,0,0,0, +621,600,0,367,0,0,0,0,0,0,0,561,0,559,0,585,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +287,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,672,157,0,0,0,0,714,0,0,0, +0,0,456,0,925,0,0,0,0,0,0,0,0,19,0,0,0,0,1473,0,0,0,0,0,0,0,0,0,0,113,0,0,0,0,0, +0,0,0,0,0,0,0,0,69,463,0,0,82,193,2,471,0,0,0,0,633,0,0,0,0,0,0,1148,129,1392, +542,803,0,0,0,0,0,0,0,0,0,0,0,0,438,0,0,0,0,0,0,875,0,0,0,0,0,237,0,0,0,0,0,0,0, +65,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,563,0,0,0,9,444,0,0,43,1260,0,0,0,0,0,0, +971,0,0,699,0,0,0,0,0,1116,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,829,242,0, +0,593,0,0,0,0,0,0,0,0,201,36,224,0,0,0,0,0,0,1430,0,1806,0,523,0,0,212,1889,0,0, +0,827,0,0,0,0,0,2043,136,242,0,0,0,0,0,0,284,148,10,0,0,0,0,0,0,1249,0,0,0,807, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,94,0,0,0,494,0,0,0,0,0,0,0,0,1510,0,0,0,0,0, +0,0,0,0,0,505,1306,0,0,764,268,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,384,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1703,0,0,0,0,159,964,583,0,0,0, +0,0,0,515,0,0,854,0,0,0,0,0,0,0,0,0,0,0,0,1123,0,0,0,0,0,0,0,136,0,0,0,0,0,1782, +0,0,44,1287,0,0,0,0,0,732,0,0,0,0,313,679,0,0,316,0,0,0,0,595,0,0,0,0,0,0,753, +147,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,137,0,0,0,0,414,0,1762,0,0,0,0,0,0,0,0, +0,0,0,599,0,0,0,0,0,0,0,0,0,1749,0,0,0,1627,0,488,0,0,0,0,0,83,0,0,0,0,676,0,0, +1639,0,0,0,0,0,0,0,0,0,278,0,0,0,0,0,0,97,0,14,1085,0,0,0,0,0,0,781,388,0,849, +59,229,0,0,0,0,0,1115,0,0,0,0,108,0,0,0,0,700,0,0,0,0,0,0,0,0,0,1414,0,0,0,0,0, +0,0,0,0,0,0,0,0,660,737,1035,0,0,0,0,0,0,521,690,0,0,0,0,0,0,0,0,0,0,0,0,272,0, +0,0,0,0,0,0,0,0,0,1744,0,0,0,0,0,0,128,733,0,0,277,0,0,0,0,0,0,0,0,0,4,0,0,0,0, +0,0,0,0,0,0,0,0,0,936,1981,40,0,0,0,0,0,0,0,0,775,0,0,0,0,0,0,0,0,0,306,0,0,0,0, +0,0,0,979,0,0,0,0,0,611,0,0,0,0,0,178,0,0,0,1969,0,0,0,0,0,0,0,664,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,390,0,0,0,1510,0,0,0,0,0,0,0,0,0,0,0,493,0,0,37,0,0,0,0,724,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,96,1537,0,0,168,473,0,0,0,105,0,0,0,0, +627,438,0,0,0,0,0,0,0,0,0,0,11,1256,0,0,0,1626,0,779,0,0,0,0,25,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,308,0,0,0,0,0,741,0,671,0,0,0,0,649,150,0,0,99,521,0,0,3,339,0,0,0, +543,0,0,0,0,0,0,0,0,0,1358,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,234,155, +0,0,0,0,0,0,0,1628,0,766,0,0,0,0,0,0,0,0,0,0,0,0,0,829,0,0,0,1445,0,0,0,486,0,0, +0,0,2,1635,0,0,0,0,558,0,0,0,0,0,0,0,0,0,0,1461,0,0,0,0,0,599,0,0,0,0,0,0,0,0,0, +1376,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,93,0,0,0,0,0,0,447,0,0,66,1432,0,0,0,0, +0,0,307,0,413,609,0,0,0,930,0,0,0,0,21,939,0,0,0,0,0,962,4,651,0,0,0,0,15,579,0, +0,0,0,0,597,0,0,0,0,0,981,0,0,0,545,0,0,0,0,0,0,0,1558,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,800,17,0,0,17,0,907,0,0,0,110,0,0,0,53,458,0,1983,0,0,0,0,0,0,0,0,0,0,443,0, +0,0,0,0,0,0,0,0,0,0,924,1844,0,1232,0,0,0,0,70,519,0,993,0,0,0,0,0,0,14,530,0, +907,0,0,0,0,0,733,0,0,0,0,0,0,0,0,55,0,188,531,56,0,0,1693,0,0,0,0,0,0,0,0,441, +0,192,928,0,0,0,0,0,241,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1525,0,259,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,512,185,0,464,1603,0,0,0,0,0,0,0,0,0,0,0,1113, +284,720,0,0,722,0,0,0,0,0,13,0,0,0,0,0,0,0,4,289,43,0,0,0,0,0,0,1694,0,0,0,0, +193,0,0,0,0,409,0,0,0,0,0,0,0,0,0,0,0,0,308,0,0,1863,0,0,0,0,0,0,0,0,0,790,0,0, +745,1002,0,0,0,0,0,0,0,0,0,289,68,477,13,0,0,0,0,0,0,0,0,0,0,609,0,0,0,0,0,0,0, +0,0,0,0,367,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,528,0,0,0,0,0,0,0,0,0,694,58, +548,0,0,0,0,0,0,687,0,0,0,0,1749,0,0,0,0,0,0,0,0,1004,661,0,0,0,0,0,0,445,0,0,0, +74,0,0,0,0,213,0,0,0,0,0,0,0,0,0,0,0,0,0,834,0,0,189,1672,0,0,0,0,0,0,0,1548, +192,0,0,0,0,0,0,0,0,0,0,0,0,0,32,751,0,78,0,0,0,0,0,0,544,1602,105,473,0,0,0,0, +0,0,156,1949,0,1779,0,0,0,0,0,0,0,0,0,0,0,763,0,0,0,0,0,0,0,0,29,0,0,0,0,0,0,0, +0,0,0,883,0,0,0,0,0,0,0,488,0,617,0,0,50,0,694,1518,785,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,546,0,0,0,0,0,0,0,0,0,0,22,0,0,0,0,1016,0,0,0,577,0,0,0,0,0,0, +184,935,114,720,0,0,100,0,0,0,0,0,0,0,0,0,3,0,0,0,0,0,95,14,0,969,0,0,0,0,0,0,0, +727,0,1021,0,0,0,0,0,1190,0,0,0,0,0,0,0,0,0,0,0,0,0,153,0,0,0,0,0,0,0,0,0,798,0, +587,0,0,695,42,0,1929,141,957,0,465,7,908,0,0,450,148,0,0,0,1166,0,0,0,0,0,0,0, +0,0,0,0,0,253,0,1003,0,0,0,0,0,0,0,0,0,0,0,46,0,0,879,0,806,0,1868,0,0,0,0,0, +1846,0,0,0,730,0,0,0,0,0,0,0,965,0,0,0,0,506,0,0,0,10,0,0,0,22,0,0,0,0,0,0,0,0, +0,0,0,0,0,960,296,0,0,0,0,0,0,0,0,0,0,0,587,0,0,0,0,20,0,0,0,32,982,0,0,0,0,0,0, +0,0,0,0,941,0,0,0,0,435,0,0,0,0,0,0,71,419,0,0,0,0,0,0,688,740,94,345,0,0,679, +582,0,0,0,0,0,0,0,945,0,0,0,0,0,0,0,0,0,0,0,0,539,0,684,1993,0,0,0,659,0,583,0, +803,0,704,0,0,0,0,0,198,181,347,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,481,405,203,0,0,99,826,0,0,0,0,0,0,0,492,0,408,0,0,0,0,0,0,0,0,0,0,4,0,0, +0,0,665,349,137,0,0,0,0,612,1270,0,0,0,0,0,371,0,0,0,826,0,0,0,0,21,1535,858, +374,0,0,0,0,0,0,311,0,0,0,991,1968,0,0,0,0,494,1647,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,769,0,0,0,0,0,642,0,0,157,123,0,0,0,1435,0,0,0,0,0,0,0,0,0,0,79,0,0,0, +0,0,0,1425,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,106,393,486,1690,0,0,0,0, +0,0,0,0,0,0,0,0,756,184,0,0,0,1382,0,0,0,175,0,1493,0,1007,0,0,0,0,0,0,0,0,0,0, +0,219,0,0,0,0,515,99,0,851,0,0,0,0,0,1278,0,0,0,0,0,0,0,1000,982,0,762,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,910,1819,0,0,0,0,0,0,906,0,0,0,0,0,0,0,0,0,0,1730,0,0, +0,0,0,0,0,0,0,0,0,1185,0,0,0,0,0,0,0,0,40,0,0,0,147,0,0,0,0,0,0,0,0,0,0,0,0,0, +650,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,56,30,0,553,0,0,20,597,0,1614,0,0,0,0,0,327, +49,0,0,0,0,0,0,0,78,0,0,786,134,0,0,0,12,496,0,0,0,0,0,0,0,0,0,0,42,204,0,614,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,147,247,0,0,0,0,942,0,0,2023,0,0,0,0, +0,0,67,285,0,0,8,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1309,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,41,532,0,0,0,0,0,0,0, +1692,0,0,0,0,55,1704,0,0,0,0,988,0,0,0,223,0,0,0,0,0,0,0,57,1123,0,0,0,0,0,1764, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2015,0,0,0,1599,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,129,0,0,0,0,0,0,0,0,0,0,0,534,0,0,0,0,0,0,0,0,0,0,0, +0,0,504,621,1248,321,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1397,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,441,75,0,0,0,0,0,0,0,0,0,0,841,0,0,0,0,0,693,0,650,314,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,913,0,0,0,0,0,0,0,0,0,0,0,0,0,0,880,0,475,0, +0,1016,179,602,111,329,0,0,0,1864,0,0,0,0,846,1888,0,0,780,0,0,0,82,0,0,0,0,821, +0,0,0,0,0,0,0,0,0,0,0,956,112,0,0,0,261,455,0,0,0,0,0,0,337,385,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,184,1865,0,0,721,16,0,486,0,0,0,265,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,621,0,0,0,0,0,0,0,0,234,0,0,815,0,0,743, +1987,205,197,0,0,0,0,0,0,0,0,0,314,0,0,0,0,0,0,0,0,0,0,0,0,0,0,219,452,589,0, +176,333,0,0,0,0,0,0,0,1110,47,0,0,0,0,0,0,0,0,0,0,0,864,0,0,300,0,1237,0,0,0,0, +0,0,0,0,0,0,0,1685,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,135,395,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,631,0,0,0,0,0,0,835,0,0,0,606,459,0,979,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,612,0,0,0,0,0,0,0,0,158,372,0,854,0,0,0,0,0, +0,0,1492,0,0,0,833,0,0,0,0,0,0,0,1739,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +195,0,0,0,0,0,0,0,0,730,1997,0,0,0,0,0,0,0,0,61,0,0,0,0,0,0,0,266,751,0,0,0,0,0, +0,0,821,0,0,0,715,0,0,0,868,0,959,0,0,0,0,0,0,0,0,0,0,0,1053,0,0,0,950,0,1081,0, +1595,0,0,0,0,59,0,0,0,0,0,0,0,0,0,0,47,684,0,0,0,0,0,0,1606,0,777,0,1020,0,0,0, +1094,0,0,0,0,0,0,0,350,0,0,0,0,0,0,242,1812,0,0,0,967,0,0,0,473,286,0,0,0,0,0,0, +798,629,222,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,513,337,306,0,0,0,0,0,0,0,0,0, +146,0,0,1646,0,0,0,0,0,465,0,0,0,525,0,0,0,0,0,0,299,165,0,0,0,0,0,0,0,1064,0,0, +0,0,0,596,0,0,0,0,0,0,0,0,0,0,0,0,0,0,238,1741,0,1233,451,1824,0,0,0,0,733,495, +0,0,0,0,0,1204,0,0,0,559,341,0,224,21,0,0,0,0,0,0,0,0,97,1446,0,0,0,0,0,0,0,729, +0,0,565,727,0,1948,0,0,0,519,0,0,0,0,0,0,0,0,0,1193,0,0,0,0,0,0,790,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,323,2,201,0,0,59,0,0,34,0,896,961,0,1285,0,0,46,0,479,0,0, +0,0,549,0,663,0,0,0,0,0,783,65,682,0,0,0,0,0,11,0,0,0,0,0,522,0,0,0,52,0,0,0,0, +0,383,0,0,0,0,0,0,0,0,127,0,0,0,0,0,397,194,0,0,635,0,0,0,0,0,0,0,0,0,0,975,0,0, +0,0,0,0,0,0,0,0,116,0,51,0,0,858,0,1075,535,448,0,0,0,0,0,610,0,0,0,0,0,0,0,0,0, +0,191,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,267,673,319,94,92,0,551,0,0,218, +1406,69,256,0,0,952,1980,0,833,0,0,0,0,0,0,0,0,0,0,0,0,39,0,0,0,0,0,0,0,81,0,0, +0,352,634,0,0,0,0,0,618,0,0,0,0,0,0,73,339,0,0,0,0,0,0,0,0,0,0,0,0,0,0,169,759, +0,0,0,0,0,0,0,0,0,0,0,0,0,1075,0,0,0,0,0,0,482,649,0,0,0,0,0,0,0,0,386,336,0,0, +0,1035,0,0,0,0,0,0,0,0,0,0,0,924,0,73,0,0,0,0,0,1971,0,0,0,0,0,0,0,0,0,1344,0, +501,0,0,0,0,0,0,0,0,46,799,0,0,0,0,0,0,0,276,0,0,0,0,0,0,0,770,0,0,0,0,0,0,0,0, +0,0,0,0,0,158,0,0,0,0,0,1432,0,0,0,0,0,0,0,0,0,0,25,0,0,2001,0,0,0,0,0,0,0,0,0, +0,0,0,0,478,0,0,0,0,0,0,91,1461,211,602,0,0,0,0,0,0,0,0,0,1068,0,0,124,567,0,0, +0,1006,0,0,0,0,0,0,0,0,0,735,812,0,0,323,0,0,0,304,0,0,0,0,0,0,0,0,0,148,0,0,0, +0,0,0,0,0,0,523,0,0,144,730,0,0,981,0,0,111,0,0,132,0,0,0,0,0,0,890,0,0,0,0,0, +444,0,1787,0,0,0,0,0,0,0,0,0,0,7,0,0,0,0,2041,932,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,937,0,995,0,0,255,0,0,138,863,965,0,0,631,0,0,0,0,1394,16,652,0,0,0,0,0,0, +0,0,0,0,0,0,0,897,0,321,0,0,0,0,0,922,0,619,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,844,0,0,0,0,0,0,1659,0,1100,0,0,0,1173,0,1930,268,251,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,390,711,0,0,0,0,0,0,0,0,0,0,0,0,0,744,0,0,0,0,0,0,0,0,0,624,0,0,0, +1998,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1125,0,0,0,594,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,268,0,0,0,0,0,0,0,563,0,0,0,0,0,0,0,0,2,39,0,0,0,1332,0,0,0,0,0, +0,0,508,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,66,796,0,0,0,0,527,0,0,0,0,98,0,0,576,0, +0,0,0,0,122,0,276,37,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,645,0,0,0,0, +0,0,0,0,0,0,0,290,0,0,762,1292,0,0,0,1315,0,1955,0,0,0,0,0,0,0,0,0,0,210,131,0, +0,0,0,797,0,38,0,11,488,0,936,0,441,0,0,0,0,0,595,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +991,0,0,0,0,0,0,0,0,0,0,0,653,0,523,0,0,0,903,0,0,0,0,0,0,0,0,0,0,0,0,80,0,0,0, +0,0,0,0,0,0,432,0,0,314,0,0,0,0,232,1368,534,0,0,0,0,0,27,0,0,0,12,0,0,0,0,0,0, +0,0,0,264,736,0,1657,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1117,0,127,0,0,0,1208,0,1294, +0,0,0,0,364,0,0,0,0,0,125,1334,0,0,0,0,0,0,0,0,0,0,0,0,0,0,792,0,0,0,0,0,0,0, +849,699,0,0,0,0,0,968,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1446, +124,397,0,0,0,0,0,0,0,0,0,0,0,641,0,0,0,0,0,0,0,0,0,0,0,0,127,346,0,0,517,75,0, +0,0,0,0,0,0,0,83,0,0,0,0,0,0,1031,0,0,0,0,0,0,0,1470,0,954,0,0,345,304,410,0,0, +0,0,734,0,0,0,0,0,1822,0,0,0,1798,0,0,0,0,0,0,0,0,0,0,0,0,0,14,0,0,0,0,0,0,161, +1865,69,0,0,0,0,0,0,922,0,0,0,0,0,0,0,0,0,0,0,541,0,627,0,0,0,0,0,0,0,0,0,166,0, +0,0,0,0,0,0,0,0,849,0,0,0,0,0,0,0,717,0,0,0,0,0,0,0,0,0,0,0,0,0,0,600,0,0,0,0,0, +0,654,0,0,188,273,0,0,0,543,0,410,87,0,0,941,0,0,186,250,0,1785,0,0,0,0,0,1339, +462,961,0,780,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,529,0,0,0,0,0,0,474,1276,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,24,948,0,0,0,0,657,753,0,0,0,0,941,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,706,985,837,0,1861,0,0,0,0,0,0,0,0,0,0,0,0,0,0,292,933,0,0,0,0,0, +0,0,0,0,767,0,0,0,0,0,0,0,641,0,0,0,1233,114,0,883,0,274,2008,0,1794,285,0,0, +571,0,0,0,0,0,0,0,0,0,0,823,960,16,617,0,431,0,0,0,0,0,0,0,0,0,0,567,0,401,0,2, +781,424,33,0,2006,0,0,274,0,0,1882,0,794,0,0,0,1848,0,0,0,0,0,0,448,47,0,0,0, +1199,0,0,0,0,0,0,0,0,417,0,0,0,0,0,0,0,0,0,0,295,0,0,0,0,0,0,0,1019,0,0,0,0,0,0, +0,0,0,0,0,0,0,620,0,0,0,0,464,0,0,0,0,208,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,442,0,930,0,0,0,0,0,516,68,0,0,0,0,0,1128,104,0,0,0,0,0,0,0,0,787,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,491,0,0,0,0,0,0,711,0,0,9,0,101,441,0,0,0,0,0,0,0,0, +0,0,160,396,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,679,326,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,1128,0,0,0,0,0,737,0,1796,0,0,0,0,0,0,0,0,0,0,0,0,338,574,0,0, +0,0,0,1096,491,405,0,0,0,0,0,1081,0,0,0,0,0,0,0,0,0,0,0,0,0,1676,0,1207,0,0,0,0, +0,0,969,354,0,0,0,0,598,0,297,0,0,0,0,0,0,0,0,1772,751,0,37,0,0,1828,0,0,0,0,0, +0,0,0,0,257,191,582,0,0,0,0,0,0,790,0,0,0,0,0,47,0,0,0,0,0,0,0,449,306,1011,0,0, +0,0,0,299,0,0,0,0,0,0,837,0,0,0,0,0,0,10,329,0,0,0,0,0,1320,0,0,0,0,0,0,158,657, +0,1191,0,0,0,0,0,0,7,0,974,1939,0,1665,0,0,0,0,8,0,0,0,0,0,0,0,0,0,0,0,0,0,288, +66,0,0,0,0,494,175,0,1643,0,0,0,0,0,0,0,0,570,750,719,0,0,0,0,0,0,0,0,0,0,0,0,0, +13,0,0,1247,0,0,221,356,0,0,0,0,0,0,0,0,0,0,694,1809,0,0,0,0,0,0,0,411,0,44,31, +0,0,0,0,669,0,673,0,0,0,0,0,0,0,0,0,1303,704,299,0,0,0,275,0,0,216,1761,0,0,0,0, +0,0,0,0,0,0,0,1319,0,0,428,0,0,0,0,0,0,0,0,0,0,514,0,0,0,0,0,0,49,55,102,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,364,0,0,0,0,379,0,921,971,52,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,1258,0,0,0,1058,0,0,0,0,0,656,0,0,0,0,0,144,0,0,0,0,0,0,0,0,0,0, +0,1373,10,605,0,0,0,0,0,0,0,838,0,1012,0,0,0,0,0,0,0,0,0,0,0,0,0,0,154,365,0,0, +0,0,0,0,0,0,0,340,0,0,0,0,0,810,0,0,0,0,0,0,495,0,0,0,0,0,0,0,0,0,261,0,535,248, +0,358,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,567,445,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,697,0,0,0,1336,0,0,0,0,0,0,0,0,917,174,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,972,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,351,0,0,0,0,0,0,0,0,0,0, +0,0,0,286,0,0,56,438,0,0,0,0,0,1950,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,738,0,0,0,0,0, +0,0,0,0,0,969,2047,0,0,0,0,0,0,0,818,0,0,0,0,0,0,0,866,0,0,0,0,0,0,0,1467,0,0,0, +0,0,0,0,0,0,0,0,0,0,972,0,355,0,0,0,116,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,267,189,104,0,0,0,0,1613,0,0,0,0,0,0,0,116,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,886,0,86,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,45,0,0,863,0,0,0,0,0, +0,0,1953,450,1773,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,381,0,0,0,0,0,0,0, +0,0,0,0,0,1142,0,1189,0,0,0,663,0,0,0,0,0,0,0,846,0,0,528,0,393,378,0,0,0,0,0,0, +325,899,680,1880,0,1770,0,0,0,0,0,648,0,0,0,0,0,0,185,167,0,2046,0,0,0,0,0,0, +249,1645,0,152,0,0,0,1733,0,0,0,0,0,1006,0,0,0,0,0,420,0,0,0,832,0,0,0,0,0,351, +0,0,0,0,6,40,0,0,60,0,0,0,0,1354,745,724,0,0,0,0,0,0,0,0,772,1951,275,108,639,0, +0,0,0,0,0,0,0,0,500,1758,0,0,0,0,0,0,0,0,0,0,0,1886,711,205,0,0,965,865,0,0,0, +534,0,0,0,0,691,0,0,0,237,443,0,878,0,0,0,0,0,1410,0,0,0,0,0,0,0,0,0,0,0,0,0, +995,0,0,0,0,0,0,0,0,0,0,0,0,0,578,0,0,0,0,881,0,0,0,0,0,0,0,0,822,0,923,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,924,0,0,0,665,0,0,0,0,0,1901,0,0,0,0,0,950,498,93, +0,0,0,1451,0,0,0,0,0,747,828,788,400,184,0,198,0,0,0,0,0,0,0,0,0,0,0,994,0,0,0, +0,0,0,0,0,615,320,0,0,0,978,843,905,0,0,0,0,0,0,0,0,850,974,0,0,0,0,6,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,509,0,0,0,0,0,273,0,0,0,0,0,0,0,0,0,0,0,0,0, +201,0,0,0,1041,0,0,0,1040,0,0,0,0,0,0,0,0,0,693,234,774,0,336,0,1399,22,0,805, +802,777,167,789,0,0,1705,0,0,0,0,0,0,0,0,0,0,0,10,13,11,0,0,204,264,0,0,56,0,0, +1917,0,470,0,0,0,0,0,0,0,0,0,0,0,1198,0,0,0,0,0,0,0,0,0,0,1015,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,715,0,0,1002,0,0,0,298,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,867,0,0,724,0,0,0,0,0,0,0,0,0,0,0,0,768,0,0,0,0,0,1066,0,0,0,0,67,0,174,948, +0,0,0,0,0,0,0,0,0,0,0,0,0,764,0,0,0,0,75,137,0,756,0,0,0,0,0,0,1008,842,643,0,0, +0,67,0,0,0,0,0,0,0,0,0,0,0,135,821,0,0,0,0,0,0,0,0,736,0,389,355,0,0,786,0,0,0, +0,0,0,2044,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1030,0,0,0,1083,0,0,0,0,0, +1226,0,0,0,0,356,319,8,389,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,474,0,0,0,427, +0,413,0,730,0,0,0,0,0,373,0,0,0,0,0,0,0,0,0,799,0,0,0,1793,0,0,0,322,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,89,290,2,0,0,0,0,0,0,0,0,0,0,672, +699,1860,0,0,0,737,0,0,0,1612,0,0,0,0,0,0,0,0,0,0,0,145,124,884,0,0,0,0,0,387,0, +0,0,0,0,0,0,0,0,0,0,679,0,550,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1305,0,0,0,0,0,0,0, +576,0,0,0,0,0,0,0,686,0,607,0,0,37,0,0,0,0,0,0,0,0,0,101,1726,0,0,0,0,0,958,0,0, +0,903,0,0,0,0,147,0,0,0,0,0,0,0,0,0,0,0,367,0,0,0,0,690,0,705,273,0,0,887,0,0,0, +0,0,0,0,0,0,0,0,90,0,0,0,0,0,0,0,908,0,0,0,0,0,0,0,1261,0,0,497,1235,0,429,0,0, +0,0,904,0,12,125,0,0,0,841,0,0,0,0,0,860,946,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,768,0,770,160,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,271,0,0,0,0,0,0,0,719,0,699,581,0,0,0,0,0,0,0,0,0,0,862,304,0,631,0,0,0,0,880, +1513,0,0,0,0,0,981,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,434,0,0,0,0,0,550,0,0,476,930, +824,553,0,0,452,0,151,0,0,0,0,0,0,772,0,292,135,0,0,0,0,0,0,0,504,0,0,1089,0,0, +0,0,0,0,0,0,0,0,0,783,0,0,0,0,0,0,206,393,0,0,0,0,0,0,0,0,232,912,0,0,0,0,0,977, +0,0,716,98,0,0,0,0,0,733,0,0,0,0,0,0,0,0,19,0,0,0,0,668,0,360,0,0,0,0,0,0,656,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,9,726,0,0,0,0,0,0,0,0,0,0,0,0,72,0,0,1269,0,0,463,0, +0,0,0,0,0,1454,0,1287,245,0,989,0,0,0,0,0,0,0,0,0,107,164,0,0,0,0,0,0,0,1061,0, +0,0,0,2,484,0,0,0,0,0,0,0,1127,0,0,0,0,0,0,0,460,0,0,0,0,0,932,0,0,0,0,0,0,0, +588,625,0,0,0,0,76,92,0,0,0,0,0,0,0,0,0,0,0,0,0,104,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +763,0,622,0,0,0,253,0,546,0,0,110,0,256,916,0,0,35,212,0,0,746,0,0,0,150,0,0, +1466,0,0,0,1299,0,0,0,0,0,0,0,0,0,1518,0,0,0,0,0,0,0,0,0,0,0,0,0,1229,0,0,0,816, +0,0,0,0,0,0,159,0,0,0,0,0,734,869,126,1716,0,0,0,0,0,0,202,232,0,0,0,0,212,0,0, +0,0,0,111,1003,0,0,0,0,0,0,0,0,0,0,0,1712,0,0,216,0,0,0,0,516,0,0,0,0,0,650,0,0, +0,0,57,99,0,0,0,0,300,574,0,0,0,0,1023,0,0,302,0,1871,0,728,252,0,0,461,0,0,0, +323,0,0,0,0,0,0,775,461,0,0,0,0,0,0,172,0,0,464,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,73,727,0,1023,0,0,0,0,0,0,0,0,0,0,577,0,0,0,0,0,0,0,0,1037,0,0,0,0,0,0, +0,0,280,677,0,0,0,0,0,0,0,0,0,0,0,799,0,0,0,0,159,0,446,1730,0,0,0,0,0,0,0,0,0, +395,0,0,0,0,145,0,0,0,0,0,0,0,20,0,0,426,608,0,0,0,0,0,977,0,250,0,0,0,0,0,100, +0,0,0,0,1982,0,0,0,0,0,476,0,0,0,0,0,0,594,76,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,447,0,0,0,0,526,0,0,14,1124,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,188,0,0,0,0,0,0,0,0,362,301,0,0,0,1743,0,178,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,872,0,831,0,0,208,202,0,0,0,0,0,0,0,1954,0, +0,0,0,516,872,0,0,313,224,0,0,24,0,11,546,0,0,0,1937,242,241,46,0,0,0,830,1273, +0,0,0,0,0,0,0,825,327,1006,0,0,0,0,0,1580,516,366,0,0,0,0,0,1736,0,0,0,0,0,0,0, +0,0,0,0,1935,0,826,0,0,0,0,139,331,0,0,0,0,0,0,0,0,0,0,0,288,0,916,0,0,0,0,0, +1888,0,0,0,0,0,0,0,1471,0,1570,0,394,0,0,0,0,0,0,0,1931,0,1719,0,658,228,0,0,0, +0,0,374,0,0,0,0,735,0,0,0,0,0,0,323,498,0,1063,0,0,0,0,155,0,0,0,0,0,0,0,0,906, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1139,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,108,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,616, +902,0,0,0,0,0,692,0,0,0,0,0,0,823,0,0,0,305,0,0,0,0,0,0,0,681,0,0,0,0,0,214, +1004,0,0,0,0,0,0,0,23,0,0,1703,0,0,0,0,0,0,0,0,0,1443,0,0,19,714,0,0,0,0,64,737, +0,0,345,1758,0,0,579,47,0,0,539,139,0,0,0,0,388,0,0,0,0,253,0,0,0,0,0,0,252,0, +745,0,0,0,0,0,0,0,0,0,0,0,504,107,0,871,0,0,0,229,0,0,0,0,0,903,0,0,71,0,0,549, +6,47,0,0,0,0,0,0,0,0,0,980,865,705,0,0,0,161,0,0,0,0,143,1331,0,0,0,1388,33,724, +0,0,0,19,0,0,0,395,0,0,0,0,0,846,210,0,0,0,122,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,695,937,497,0,0,0,0,0,718,0,0,0,0,0,0,0,1581,0, +0,0,0,0,0,161,49,0,0,0,0,0,0,0,0,0,597,0,0,0,1094,0,0,0,811,908,0,0,0,0,0,0,0,0, +0,0,1471,0,0,0,0,0,0,0,0,0,0,42,1935,0,0,0,2014,66,2007,0,0,586,0,0,0,0,0,0,0,0, +0,28,1077,0,0,0,1221,0,0,62,0,0,0,0,0,0,0,0,0,0,1766,0,0,0,0,0,0,0,0,0,0,0,0,25, +0,499,1388,0,0,97,10,0,0,0,0,0,481,0,0,0,0,0,0,0,0,0,0,37,134,155,486,0,1442,0, +0,0,0,0,591,0,0,0,0,0,0,310,1173,0,0,0,0,409,1156,0,0,0,482,0,0,263,926,0,0,0,0, +0,0,0,0,0,0,0,0,0,804,0,0,0,0,0,0,0,0,0,0,0,0,0,1265,0,415,0,348,0,0,0,1012,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,165,1803,0,0,0,0,0,0,0,408, +0,0,0,0,0,0,257,1321,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1138,0,0,0,249,0, +0,0,576,0,0,0,0,231,0,0,0,288,0,0,0,0,0,0,0,0,0,433,1487,569,1678,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,87,0,0,0,0,0,779,538,0,0,0,413,0,0,0, +0,0,0,0,0,0,0,495,0,0,0,0,0,191,54,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,530,567, +0,0,0,0,0,1484,0,0,0,0,0,0,815,609,0,0,0,0,0,484,0,0,0,0,0,0,0,0,0,0,900,0,0,0, +0,1335,0,1724,0,0,0,0,0,0,0,0,0,0,0,640,0,0,0,0,0,0,0,0,0,0,0,1831,0,0,0,0,0,0, +0,0,0,0,0,0,0,474,0,0,0,0,0,0,0,0,0,1103,0,1504,655,1034,0,0,0,0,0,305,0,0,0,0, +0,0,0,0,0,1236,0,0,429,217,0,0,0,0,739,278,0,0,0,0,0,0,0,708,0,0,0,0,0,1840,233, +0,0,0,0,0,0,0,0,2017,0,0,0,0,0,1488,0,0,0,1590,0,0,0,0,0,1800,28,0,0,0,0,0,0,0, +0,0,45,0,36,0,22,1442,378,0,0,0,0,0,0,1507,0,0,0,0,0,0,0,0,0,0,39,0,0,1054,725, +1955,0,2036,0,0,0,0,0,0,0,0,0,0,896,1871,0,0,0,0,0,0,0,0,0,0,805,0,0,0,0,2046,0, +0,0,0,17,712,0,617,55,320,271,0,0,0,0,0,0,0,0,0,445,0,184,103,0,0,0,0,0,0,0,0, +659,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,676,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +337,0,0,0,506,0,0,0,0,0,843,77,0,458,0,0,0,0,0,1420,382,109,142,330,0,0,0,0,0,0, +0,0,0,0,0,0,87,0,0,0,492,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1239,0,0,0,0,0,0, +211,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1049,0,321,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,1985,0,0,122,0,0,234,0,0,0,1098,0,0,0,0,0,0,549,253,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,522,131,0,0,149,0,0,0,0,0,0,0,0,0,0,0,0,0,0,507,0,0,0,0,811,630,0,0,0,343, +0,0,0,0,0,448,591,455,0,1381,0,0,0,0,0,0,0,575,0,0,0,0,0,1175,0,0,0,0,0,0,0,0,0, +653,0,0,0,1761,0,1198,0,0,0,0,297,1127,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,678,0,0, +164,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,35,0,45,0,0,0,0,0,121,0,0,0,0,0,0, +0,0,125,0,0,0,1622,0,0,0,0,0,721,145,0,0,0,970,792,0,0,0,715,0,0,0,0,0,1999,0,0, +74,531,0,0,65,0,0,0,105,220,0,0,0,0,0,0,0,960,0,0,0,0,0,0,428,19,0,0,401,96,0,0, +0,0,0,1595,116,0,1021,0,0,0,0,0,750,1961,0,0,148,0,0,0,0,0,0,0,0,0,0,0,0,0,75,0, +0,1383,0,0,0,0,0,0,0,0,0,0,0,0,0,0,779,0,0,0,0,0,0,0,0,598,0,424,0,0,0,0,0,0,0, +1222,0,0,0,876,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,133,0,0,0,0,187,0,8,0,0,0,0,0, +0,0,429,0,685,0,0,0,0,0,0,0,0,0,0,0,132,472,0,0,0,0,0,0,0,0,0,938,0,0,874,0,0,0, +0,0,774,0,0,0,0,0,92,0,0,0,0,0,0,830,701,0,0,0,0,0,426,350,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,603,59,0,0,0,0,0,0,0,0,0,0,293,0,0,0,0,0,0,0,0,0,0,0,0,0,0,441,163,4,0, +0,0,0,0,0,0,0,0,806,0,0,0,0,0,0,233,0,0,0,0,1994,0,1739,0,0,393,0,47,1038,0,0,0, +309,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,363,0,0,0,175,0,0,0,0,0,0,0,666, +0,0,1675,0,1600,0,0,0,808,0,0,0,0,0,0,0,0,0,0,0,280,54,0,0,0,0,0,0,0,0,421,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,249,0,0,103,254,0,262,1,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,805,0,0,0,0,0,0,0,0,0,1630,0,0,0,0,0,0,0,0,0,0,0,0,0,671,972,989,0,0, +0,0,0,0,0,889,0,0,0,1382,0,0,0,0,0,0,0,775,0,0,0,0,0,0,0,0,0,0,388,202,0,0,0,0, +16,560,0,0,0,841,0,0,566,0,0,0,938,0,0,0,0,0,0,0,0,0,0,912,0,0,0,1361,0,0,0,0,0, +0,618,236,0,1854,0,0,318,190,0,1376,0,0,0,0,0,0,0,349,0,0,0,0,951,1972,0,0,0,0, +0,0,344,0,0,0,0,0,0,0,0,850,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,910,0,0,0,0,0,0,0,0,0,0,0,0,0,0,19,0,163,85,0,487,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,145,0,83,0,0,1013,0,0,0,1922,0,0,169,557,66,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,1193,82,0,352,454,57,0,0,1333,396,107,0,370,0,0,0,0,0,0,0,0,0,204,0,0,0, +0,0,1706,0,0,0,0,0,0,0,0,0,0,0,0,394,1204,0,0,0,0,0,1007,0,0,0,1696,0,1519,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,981,0,0,0,0,1072,0,0,0,712,0,1629,0,0,0,0,0,0,0,728,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1271,0,0,0,1608,16,0,0,0,0,485,0,0,0,0,0,0, +153,27,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1991,0,0,0,0,0,0,0,0,52,0,21,0, +0,0,0,0,0,0,0,0,819,0,0,0,0,0,917,0,0,0,0,784,0,0,0,0,135,0,0,0,0,0,454,0,0,0,0, +0,0,0,0,0,852,1719,0,0,0,0,0,852,0,0,0,0,0,952,0,0,0,0,568,0,0,0,0,0,448,0,0,0, +67,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1826,657,0,729,666,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +669,0,0,0,0,0,0,0,402,0,0,152,0,0,0,0,912,0,0,0,0,0,0,51,320,0,445,0,0,0,0,308, +0,0,0,0,0,386,0,0,239,0,0,130,83,0,143,0,348,0,0,0,0,0,0,0,958,0,0,0,0,0,210,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,430,0,0,0,0,0,0,0,0,0,0,0,0,7,213,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,801,0,0,0,0,0,0,0,0,0,936,0,108,0,0, +0,0,0,0,0,0,0,885,587,219,398,364,0,1165,0,0,342,241,303,0,0,0,0,0,0,0,0,0,0, +1454,0,0,0,0,0,0,0,0,0,0,254,562,0,786,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1294,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,493,216,0,0,0,0,219,341,0,0,0,0,0, +0,0,0,0,0,130,1734,154,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,701,604,0,0,879,0,195, +666,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1669,0,0,0,1791,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,1228,0,0,0,0,0,623,0,0,0,0,0,0,0,798,0,0,0,0,0,0,0,0,0,0,0,0,84, +122,0,0,0,837,0,0,0,0,0,0,1013,0,0,577,0,0,0,460,932,0,0,0,0,0,0,0,0,0,0,0,31, +131,0,0,0,605,0,0,0,1246,0,0,0,0,68,278,165,307,781,0,0,0,0,0,0,33,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,1113,0,0,720,1953,203,0,0,0,0,0,0,0,425,326,0,0,0,0,0, +0,0,0,0,0,241,1316,0,0,0,0,0,416,0,0,0,1300,0,847,0,0,662,358,0,0,0,0,839,1823, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,654,1522,0,0,0,0,0,0,163,0,0,0,0,0,314,978,0,0,0, +601,0,0,0,0,0,946,434,0,0,0,402,411,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,13,1467, +410,0,0,0,0,0,0,0,0,0,0,0,0,0,0,483,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,677,0,0,0,0,0,0,0,0,0,0,0,0,70,0,0,0,0,1405,0,0,0,0,0,0,108,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,777,0,0,0,0,0,747,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,68,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,505,0,326,0,0,164,628,654,0,0,0, +37,32,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,668,152,0,0,0,0,0,0,0,0,0,0,0,581, +0,0,0,0,44,126,89,0,0,0,0,0,0,0,0,1531,0,0,0,0,0,0,0,0,203,1167,0,0,0,0,0,0,0,0, +531,1232,0,0,0,0,0,943,0,670,231,880,0,1617,0,0,0,1957,0,0,0,0,0,0,0,975,0,0,0, +0,0,0,0,0,0,0,0,242,0,0,0,0,0,0,0,0,0,421,0,0,14,834,0,0,0,0,0,0,0,0,0,0,0,0, +465,0,0,0,0,0,834,688,413,855,0,0,0,590,0,0,0,0,0,0,0,0,114,0,0,0,0,0,0,0,0,0,0, +0,45,169,0,0,0,0,0,0,0,0,0,0,0,198,0,0,565,585,0,0,0,0,0,0,0,0,0,0,0,0,0,691,0, +0,0,593,0,0,0,0,0,0,0,0,0,913,116,0,0,0,0,1360,0,0,0,802,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,673,308,0,709,1006,1895,0,228,0,0,0,1840,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,608,0,0,0,0,0,0,0,0,0,1573,0,2039,136,540,0,0,0,0,0,0,0, +897,0,0,938,1878,0,0,0,0,0,0,0,0,0,1469,0,999,0,299,0,0,0,0,0,0,0,578,0,0,0,0,0, +456,0,0,0,1679,163,693,0,0,0,0,0,0,48,755,0,0,0,0,0,0,0,0,0,0,0,0,338,0,0,0,0, +1091,0,0,0,0,695,0,0,1464,0,0,0,0,0,975,0,0,335,0,0,1979,0,0,0,0,269,1566,630, +396,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1815,634,0,0,0,966,0,0,0,0,0,0,0,9, +412,0,958,0,0,579,382,0,212,0,0,0,0,965,681,0,0,16,0,0,0,0,0,0,0,0,0,0,0,0,655, +0,0,0,0,67,0,0,0,0,0,0,751,0,0,0,0,423,231,0,0,1016,300,0,0,0,0,100,237,0,0,0, +1370,0,0,0,1208,0,0,0,0,0,1219,129,0,0,0,0,0,0,0,0,0,0,0,0,0,0,199,0,0,427,0,0, +0,0,949,665,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,712,0,0,0,0,0,1186,0,0,0,0,0,0,0,0,0,0,295,312,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +151,0,0,0,0,588,4,0,0,0,0,0,414,104,0,0,757,263,0,561,0,0,0,320,0,0,0,0,0,0,0,0, +0,0,0,225,0,0,0,0,37,817,0,974,0,0,0,0,0,0,0,0,0,0,0,0,0,2026,131,235,16,0,590, +1157,0,0,0,0,0,0,0,0,221,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,140,390,0,0,0,0, +0,0,0,1144,0,0,0,464,0,0,0,0,0,0,0,0,0,0,0,0,204,407,303,1218,0,0,0,0,5,325,0,0, +0,0,12,800,0,1783,0,0,0,0,0,0,0,0,0,0,504,621,0,0,0,0,0,0,0,0,0,920,0,376,0,0,0, +0,0,218,580,0,768,454,0,0,0,0,0,0,0,0,0,0,0,0,676,0,0,0,0,0,0,164,0,0,0,0,0,0,0, +0,50,0,0,0,0,0,0,0,0,0,0,0,0,0,120,285,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,226,343, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,29,0,0,1812,0,0,8,0,0,0,21,1125,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,1327,0,0,0,0,575,1598,0,0,0,0,0,0,0,0,0,895,0,0,0,959,0,0, +0,0,0,1759,173,0,0,0,0,266,261,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,1427,0,0,300,1033,0,0,0,0,0,0,0,0,0,0,0,584,0,0,0,0,52,734, +0,0,217,239,0,1129,0,0,0,0,0,0,0,0,732,20,0,0,0,0,0,0,0,0,0,0,0,418,0,0,0,613,0, +0,0,0,0,0,0,0,0,632,0,0,85,984,0,0,0,0,909,694,7,1109,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,167,0,0,0,0,280,62,0,0,33,0,0,359,186,980,0,0,0,0,0,0,0,0,0,0,0,585,0,0,0, +211,0,0,336,145,0,1130,0,873,0,0,840,263,0,0,0,0,0,0,0,0,0,916,0,0,0,0,0,0,0,0, +0,0,155,0,0,0,461,97,0,0,0,0,0,1356,0,0,0,0,0,0,0,593,0,0,0,0,0,1392,0,0,0,0, +126,0,0,0,0,1179,0,0,0,0,0,162,0,0,0,0,0,765,0,187,0,1286,0,0,0,0,0,0,0,0,0,635, +0,0,23,215,0,0,0,1306,0,0,97,716,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,657,0, +0,0,0,0,0,0,0,299,0,0,0,0,0,0,134,0,0,0,0,0,0,0,0,0,0,0,658,1082,0,0,0,0,0,2002, +0,0,0,0,0,0,833,248,0,0,0,0,0,1654,0,0,531,0,0,0,0,0,0,634,0,0,0,0,0,0,0,0,0, +853,573,249,0,0,0,0,0,0,0,0,527,0,0,0,0,1419,0,0,0,0,0,0,20,49,0,0,0,992,0,0,0, +728,0,0,0,0,0,0,0,0,0,0,0,0,497,1579,0,0,0,0,62,268,0,0,0,0,0,0,0,1201,0,0,0,0, +0,0,0,0,0,0,0,0,495,193,0,0,0,0,106,0,0,859,0,0,23,0,0,0,0,0,0,0,813,925,0,0, +223,613,953,0,0,0,0,0,0,0,0,666,0,0,0,0,0,0,0,0,0,670,0,0,40,216,0,0,0,0,0,0, +259,0,0,0,440,1114,0,0,0,0,0,0,0,0,74,475,0,0,188,139,0,797,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,1572,0,0,0,0,39,0,0,0,0,0,0,0,0,0,0,0,0,1594,0,0,0,0,0,0,0,290,0,232, +0,0,887,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,521,14,0,0,0,0,0,741,0,0,0,992,0, +0,0,0,0,0,0,0,111,0,0,425,0,0,0,0,0,789,0,0,0,1593,0,1768,0,0,233,0,0,0,0,943,0, +0,0,0,0,0,0,955,225,245,0,0,0,0,0,0,241,0,0,0,0,1943,0,0,0,1284,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,709,0,0,0,0,0,0,554,0,0,0,0,0,0,0,0,1564,0,0,0, +443,0,0,0,0,0,0,280,0,0,0,0,0,0,0,0,729,0,0,0,348,0,0,0,0,0,0,0,758,848,298,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,829,1422,189,121,0,0,632,812,0,0,556,0,0,0,0,0,436,172, +530,844,232,984,0,0,0,0,0,0,0,0,0,0,147,0,0,0,0,0,0,0,0,537,0,0,0,0,0,859,0,0, +842,0,0,0,0,0,0,0,0,0,0,1291,0,0,0,0,0,0,0,0,0,0,0,1482,612,392,0,0,0,262,31,0, +0,0,0,0,0,0,0,0,0,753,549,0,0,0,0,0,0,696,0,0,0,0,0,0,0,834,0,0,0,0,0,771,0,0,0, +0,0,0,0,0,0,0,0,0,0,921,0,0,0,674,0,0,0,0,0,0,0,0,0,0,308,444,0,0,0,0,0,0,805, +180,0,0,278,271,0,0,214,505,0,1215,0,0,0,0,0,0,387,271,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,1645,42,92,0,459,0,0,330,1557,0,0,0,0,0,0,0,0,113,18,0,0,0, +1742,0,0,0,965,0,0,0,0,0,0,0,0,0,0,0,0,0,182,0,0,65,0,0,0,0,0,0,0,0,0,0,0,0,973, +0,0,0,0,0,328,0,0,588,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1786, +0,0,962,1985,0,0,0,308,508,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,588,0,0,0,0,0,0,614,793,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,290,0,0,0,0,0,0,0,0,0,0,1136,0,0,0,0,0,0,0,0,0,0,796,719,0,0, +326,210,0,0,0,701,758,472,0,0,0,1947,278,1079,0,0,0,0,0,0,497,41,0,0,634,46,961, +0,810,524,0,0,33,0,0,0,0,0,0,0,0,0,0,0,0,532,0,997,0,0,0,0,0,0,0,0,0,0,0,1301,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1298,0,671,0,0,0,306,0,0,0,0,0,0,0,0,0,0, +693,1823,0,0,0,759,0,0,0,0,0,1932,0,0,0,0,0,0,0,0,0,0,0,0,0,0,88,182,0,0,0,1964, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,521,0,0,0,0,0,0,424,857,0,0,0,0,671,328,0, +529,0,0,0,0,0,716,0,1509,80,67,0,0,0,0,59,141,0,0,0,0,0,0,783,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1498,0,0,0,0,343,430,803,1183,677, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,19817,0,5579,9350,0,0,21002,19718,0,0,0,21926,0,0,0,0,0,0,0,0,0,0,0,0,0,20711, -0,0,0,20197,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,40550,0,0,0,57510,0,0,0,53895, -0,0,15017,0,17000,39367,2347,0,0,0,0,0,0,0,0,0,8588,0,0,0,0,0,3273,17862,3498, -2085,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,19048,0,0,0,0,0,11978,58631,0,0,0,0 -,0,0,523,0,12969,198,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28197,0,47846,0,0,0,0,0,0 -,0,0,0,4549,0,0,0,0,0,0,0,0,0,0,687,14917,748,8229,0,0,0,0,0,0,2476,12935,0,0,0, -0,0,0,22792,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,27528,59142,0,0,20876,20134,0,0,0, -0,440,12068,0,58951,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,48038,0,0,0,60999,0,0,0,0, -0,0,0,0,0,0,0,0,0,15716,7498,5476,0,0,0,0,20202,37959,0,0,0,0,0,0,0,0,0,0,0,0, -29801,0,5451,0,0,0,0,0,0,0,0,0,0,50790,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,24485,0 -,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,13573,0,0,22856,0,0,0,0,21927,0,0,0,0,0 -,0,9130,0,0,0,0,0,0,13732,0,0,0,0,0,0,0,0,0,0,2282,583,0,0,0,0,0,0,0,0,0,0,3726, -26503,0,0,0,0,0,0,9258,0,0,0,0,0,0,0,0,21604,0,0,0,45574,0,0,0,0,0,20710,0,0,0, -42694,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1163,6694,0,0,0,0,0,0,0,10948,0,0,0,29700,0,0, -0,0,0,58823,3796,27399,20939,10180,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -19,29287,28649,14534,0,0,16428,45607,0,0,0,0,0,0,25322,0,4908,0,0,0,0,0,0,25476, -29097,14246,11053,0,0,0,0,0,0,0,0,18502,0,0,0,44390,0,0,0,17765,0,0,0,0,0,0, -24520,0,0,0,0,0,0,0,0,0,0,17319,0,0,0,0,0,0,0,0,0,0,0,0,0,28166,0,0,0,0,0,48198, -0,0,31467,0,24585,0,0,0,0,18692,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,23596,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,7236,968,13637,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -3763,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,14791,0,0,0,12324,0,12741,0,0,0 -,0,0,0,0,0,0,11108,0,0,0,0,4009,40295,20616,4357,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -15015,0,0,0,0,0,43751,0,0,0,0,0,0,0,0,0,0,0,23013,0,0,0,0,0,0,0,0,0,0,0,0,0, -45542,0,0,0,0,0,0,0,0,0,23974,0,0,0,0,17480,20647,0,0,0,0,0,0,8876,0,0,40806,0,0 -,0,0,0,0,0,14502,17160,17764,0,0,31594,35431,0,0,2890,0,0,0,0,0,0,0,0,27524,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8228,0,56583,0,0,0,0,0,0,0,0,0,0,0,0,0 -,0,0,0,0,34278,0,0,0,0,0,0,0,0,0,0,0,0,0,2662,0,26724,0,0,0,0,0,0,0,64198,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,22281,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3049, -54983,0,0,0,0,0,0,0,837,0,17604,0,0,0,0,0,28838,0,0,0,0,0,0,26312,0,0,3910,0,0,0 -,25830,0,0,0,0,0,8391,0,19845,19240,1092,0,0,5449,0,0,0,0,17188,0,0,0,0,0,0,0,0, -0,10629,0,0,6671,61094,5832,8358,0,0,0,55078,0,0,0,0,0,29860,0,0,0,0,0,0,0,0,0,0 -,0,0,0,0,0,0,0,51494,0,28647,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,25989,0,0,30153,61318 -,0,0,0,0,0,0,0,24903,0,0,0,4388,0,42054,0,0,0,0,0,0,0,53158,0,0,0,0,0,0,0,50918, -0,0,0,0,0,0,26251,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5929,2853,0,37126, -7372,197,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2027,934,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,55686,0,0,5672,5447,0,62758,0,0,0,0,0,0,0,0,0,0,0,0,2923,0,556,1415, -0,0,0,0,0,0,0,0,0,8645,0,9477,0,0,0,0,0,0,0,48742,0,0,0,0,0,0,0,0,0,0,24235,228, -0,0,0,0,0,0,0,0,0,0,16970,18823,0,0,0,0,0,0,0,0,0,25158,0,0,0,0,0,18567,20072, -2823,14313,1830,0,0,0,0,0,0,0,0,27048,23526,0,0,0,0,0,997,492,0,14730,16677,396, -13574,0,0,0,41671,0,0,0,0,0,0,0,19045,0,0,0,421,17545,3110,0,0,0,0,0,0,0,0,0,0,0 -,0,0,0,0,47111,14475,56551,0,0,0,0,0,0,0,0,0,0,3697,0,0,0,0,0,0,49382,0,35559,0, -0,0,0,40,0,11496,15621,0,8550,0,0,0,63462,0,0,0,0,0,0,0,36966,0,50406,0,46022, -1001,0,0,12069,3249,0,0,0,0,0,0,0,0,0,0,0,0,0,15241,0,0,0,0,0,0,0,0,64743,0,0,0, -0,0,58759,0,0,0,0,1136,26981,0,0,0,0,0,0,0,17732,0,0,0,17157,20011,6629,0,43879, -0,0,0,13572,25128,10759,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28676,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,875,24007,0,0,0,0,7628,0,0,0,0,0,12268,0,0,0,0,0,0,0,0,19300 -,23210,356,0,0,0,0,0,0,0,0,0,15236,0,0,0,0,0,49670,0,0,0,0,0,0,0,21764,0,0,0,0,0 -,0,0,0,0,0,0,0,0,0,0,0,13931,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,45799,0,0,436,3589, -0,0,11402,0,0,0,0,0,0,0,0,0,0,62822,0,0,0,39814,588,0,0,0,0,0,0,27750,0,0,0,0,0, -0,1609,22660,2346,18951,0,16068,0,0,0,0,0,0,5162,11110,0,0,0,0,15048,1060,0,7879 -,18280,326,0,14886,19656,0,7594,0,0,0,0,0,781,581,0,16198,0,0,0,0,0,0,1078,9892, -0,0,0,0,0,0,0,0,0,0,4489,0,0,0,0,33798,0,0,0,54534,0,0,0,0,0,0,0,33158,0,0,0,0,0 -,0,0,0,0,42086,13834,2757,8456,16773,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3434,0,0,0, -0,0,3946,29668,0,0,30634,36775,0,0,0,0,0,24901,0,16069,6280,0,0,0,0,41990,0,0,0, -0,0,0,0,27365,0,0,0,0,0,0,0,0,0,0,1450,44807,0,0,0,32100,0,0,0,0,0,35110,0,0,0,0 -,0,0,0,0,17448,19591,0,0,0,0,0,0,0,0,0,0,0,0,1739,0,0,0,0,5511,0,0,0,32934,0,0,0 -,0,0,0,0,0,0,18180,0,0,0,23428,19754,0,0,31174,3021,31655,23464,0,0,0,0,0,0, -57255,0,0,21292,64487,0,0,0,0,0,0,25802,9189,0,0,0,0,0,49254,0,0,0,0,0,0,0,0,0,0 -,5837,50023,0,0,0,0,0,0,0,0,0,15495,0,0,0,0,0,51942,0,0,0,0,0,0,0,0,28104,58662, -0,50214,0,0,0,0,0,0,0,0,2988,0,22888,31812,0,0,0,0,0,2020,0,18916,0,0,0,0,0,0,0, -23973,0,0,0,0,17516,11717,0,0,0,55911,0,0,0,0,0,0,0,2855,0,0,0,0,0,0,0,0,0,0,0,0 -,0,0,0,0,0,46822,0,24710,28586,0,0,0,1556,0,0,30117,0,0,22090,57127,3403,14087,0 -,0,0,0,0,0,0,0,0,0,1041,0,10633,6916,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 -,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,27269,0,0,13322,18055,0,29380,0,56454,0,0,120 -,0,0,8773,0,0,0,0,16040,0,0,0,0,0,0,0,27242,23781,0,1572,0,28134,0,0,1512,0,0,0, -0,0,0,27684,0,38470,0,0,0,0,0,0,1513,8709,0,0,0,0,0,0,0,0,0,0,0,46566,0,0,0,0, -28521,61159,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,24356,0,0,0,0,0,0,0,0,0,13028,0, -5863,0,0,15693,0,0,0,0,0,0,0,1131,23398,0,0,0,0,0,0,0,26212,0,0,0,0,0,0,0,0,0,0, -0,0,0,18404,0,0,0,0,1457,26183,0,0,2475,7110,0,0,0,0,27180,60166,0,0,0,20262,0, -41862,0,0,0,0,0,0,0,0,0,0,2762,0,0,0,0,0,0,0,0,0,0,0,0,0,0,26148,0,0,0,0,0,0,0,0 -,0,28229,0,0,0,29254,0,0,0,0,0,0,0,0,0,0,27690,0,0,13636,12776,1862,0,0,0,0,0,0, -17225,3271,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28039,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 -,0,0,0,0,0,0,0,0,0,4457,18117,0,2023,402,0,0,0,0,0,0,0,0,0,0,0,0,0,104,3654,0,0, -0,0,0,0,0,0,18440,0,0,0,0,0,0,0,0,29861,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,22150,0,0,0,0,0,0,0,0,0,0,0,0,24074,0,0,0,0,0,0,0,0,12004,0,32358, -0,0,3081,0,0,0,0,0,0,0,0,0,4749,0,0,0,0,0,0,0,0,0,0,0,10792,1799,21322,0,7880, -12613,0,0,0,0,0,0,0,0,13993,0,0,0,16202,0,0,0,0,32102,0,37223,0,10500,0,0,0,0,0, -0,0,0,32008,0,0,0,0,0,23816,3236,0,0,0,0,0,23237,0,0,5642,0,4684,294,0,0,0,0,0,0 -,0,0,0,0,0,0,0,0,0,0,0,0,0,26852,0,0,0,0,0,0,7148,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,7890,61798,939,0,0,56679,0,0,0,0,0,27078,202,5029,0,0,0,0,0, -0,0,0,0,28005,0,0,15273,24741,5676,20452,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,55910,0,0 -,0,0,5069,27942,0,21092,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12517,0,0,0,0,0,0, -0,0,0,0,0,0,21384,28260,0,2502,20108,0,0,0,0,0,0,0,0,0,0,0,0,46726,0,30790,0,0,0 -,0,0,14725,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1099,6372,0,0,0,12422,15182,0,8683,0, -10665,19462,0,0,0,0,0,0,1590,0,31628,0,22632,19750,0,0,0,0,0,0,0,24198,0,0,0,0,0 -,50662,0,0,0,0,0,0,0,0,0,0,9131,0,0,0,0,0,0,0,0,0,0,0,0,0,0,11015,0,0,0,0,0,0,0, -0,16490,54695,0,0,0,0,0,0,0,0,12937,0,0,0,0,16004,0,0,0,0,0,0,0,0,0,2181,6923,0, -0,0,0,0,0,0,15624,11302,0,0,5673,7559,0,0,14668,15684,0,0,0,0,0,0,24204,48134,0, -24230,0,55527,0,0,3464,19141,0,0,0,0}; +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1357,53,0,0,0,0,590,0,0,0,0,0,0,0,0,0,0, +0,0,0,329,0,0,0,0,0,0,0,469,0,0,0,0,0,0,0,0,0,0,460,0,0,1743,0,0,963,340,0,0,0, +0,0,1603,0,0,250,0,0,0,0,0,646,218,0,1794,0,0,0,571,0,455,0,0,0,1012,0,0,0,0,0, +0,0,0,0,0,0,0,597,161,0,349,0,524,0,0,0,0,0,0,0,0,0,0,0,0,322,432,0,0,0,0,0,0, +325,223,0,0,0,0,0,566,0,0,0,1394,481,436,0,48,457,610,756,618,0,0,0,755,0,1217, +0,0,0,0,0,197,0,0,0,0,0,0,0,0,0,0,0,0,0,0,544,492,107,414,0,0,0,0,0,0,0,0,0,0,0, +1007,0,0,0,0,5,0,0,1580,0,0,0,0,0,0,0,0,0,0,0,0,0,673,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,1843,0,0,0,0,0,0,0,0,0,165,0,0,0,0,0,0,809,885,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,498,0,0,0,306,9,0,0,0,0,0,0,0,437,721,146,0,0,0,0,0,0,0,0,0,0,0,177,0,0,0,0, +0,0,0,1377,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,200,0,959,0,0,0,1928,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1435,0,481,0,0,0,0,0,0,142,84,0,0,0,0,0, +1015,0,0,0,315,0,0,0,0,0,0,759,0,0,0,0,0,0,0,0,712,0,0,0,1722,0,0,0,0,0,0,0,0,0, +0,0,0,222,0,985,1414,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1273, +538,706,0,0,0,0,0,0,0,0,115,0,0,0,0,0,0,0,0,0,0,1781,0,0,0,0,0,431,97,665,42, +237,0,0,0,264,0,0,213,0,0,0,0,0,0,0,455,0,0,0,906,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +624,0,574,0,0,0,0,0,0,0,0,0,0,0,0,354,0,0,0,1558,0,0,0,0,0,0,0,0,0,0,0,0,0,0,68, +235,723,1813,0,0,0,957,0,830,0,0,0,0,0,0,0,0,0,0,0,0,23,0,0,496,0,0,0,0,0,0,0, +547,239,88,0,0,0,0,0,0,0,0,0,1310,0,0,0,0,0,0,0,0,80,1076,0,0,118,0,0,0,479,274, +0,0,0,0,0,0,0,0,0,0,0,497,0,0,669,261,0,0,0,0,13,0,0,0,0,0,0,791,250,642,0,0,0, +1429,939,949,0,0,0,0,0,0,0,0,0,0,0,0,0,818,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,982,330,0,0,0,0,545,0,0,0,0,0,0,947,0,1188,0,0,0,0,0,904,0,0,0,0,0,1372,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,693,377,0,0,0,0,0,0,0,0,0,0,0,0,0,0,695,0,0, +713,386,0,0,0,0,128,1575,0,0,0,0,0,0,424,893,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,904,0,0,0,0,0,552,322,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,1808,49,0,0,0,0, +1832,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,421,0,0,442,415,0,0,289, +0,0,0,0,0,206,110,0,0,0,0,0,205,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +19,1539,0,0,0,0,0,1340,0,1194,0,0,0,0,0,0,0,0,549,0,0,0,0,0,0,0,0,1720,0,0,0,0, +0,0,0,0,0,319,0,0,0,0,112,1180,0,0,0,0,0,0,0,0,0,0,0,967,0,0,0,0,0,0,0,0,0,1940, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,735,0,0,0,0,0,0,0,0,0,897,132,0,0,0,0,0,0,0, +0,0,0,38,838,0,0,0,379,218,8,660,1017,0,0,0,0,0,0,111,387,647,877,0,0,53,790,0, +0,0,0,0,0,0,0,458,0,0,0,0,0,0,954,0,0,0,394,0,1367,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,882,0,0,0,0,0,0,0,1409,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,38,124,342,199,0,0,0,0, +0,0,0,0,0,0,724,628,0,0,0,0,804,266,0,0,0,0,0,208,0,79,0,0,0,0,0,0,0,0,741,0,0, +0,0,0,0,0,0,0,0,606,0,1494,821,1553,0,0,135,405,0,0,178,100,0,0,0,0,0,0,0,0,0,0, +0,0,0,481,0,0,0,1378,0,0,0,0,0,0,0,0,0,0,0,0,0,791,33,1227,857,0,467,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,447,0,0,0,0,0,0,86,128,0,0,0,0,0,0,587,0,0,0,692,1018,0, +195,0,0,0,0,0,0,0,1546,0,0,0,0,0,0,0,0,0,0,0,684,0,0,345,0,0,0,0,0,0,365,0,1683, +0,0,472,0,433,0,0,0,0,0,0,0,28,0,0,0,997,0,705,3,0,0,0,0,0,0,0,0,0,229,0,0,0,0, +102,0,0,0,0,866,1022,0,0,0,0,0,0,0,0,0,55,0,115,0,0,0,0,933,0,0,0,0,0,0,0,702,0, +0,0,0,0,0,0,1728,26,484,0,0,0,185,618,417,0,803,0,0,0,0,0,0,0,0,0,0,0,1262,0,0, +0,0,0,0,0,0,0,0,0,0,0,633,0,0,0,0,0,0,0,0,0,0,0,0,0,479,262,0,0,0,0,0,0,830,0,0, +0,0,26,70,0,0,0,0,0,0,0,0,217,0,640,51,0,0,360,1586,0,0,0,0,0,652,0,0,0,0,0,766, +0,0,0,0,298,737,0,0,0,0,0,0,0,0,0,0,655,222,906,0,0,1013,991,2009,0,0,0,0,503,0, +0,0,216,154,0,0,0,716,0,844,0,0,0,0,621,252,0,0,0,0,748,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,103,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,576,0,0,0,648,0,0,0,331,0,0,0, +0,0,0,0,0,0,0,0,0,632,0,0,0,518,107,0,0,0,0,0,0,0,0,851,0,0,0,0,504,0,0,0,0,0,0, +0,0,0,0,0,0,7,883,0,0,0,0,0,0,0,922,0,0,0,0,0,0,0,0,91,993,0,0,0,0,0,0,200,131, +10,0,0,0,0,0,0,0,0,0,0,0,0,0,365,1433,0,0,0,0,28,103,0,0,798,1013,0,0,0,0,0,0,0, +0,39,1925,0,853,0,0,271,519,0,0,0,0,338,0,0,300,470,419,0,0,0,0,0,0,836,0,0,0,0, +0,0,1937,0,0,0,0,0,393,0,0,357,0,0,0,0,0,703,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,387,0,0,0,0,0,0,75,708,453,1351,0,303,0,0,772,0,0,0,0,0,0,0,0,749,0,0, +0,0,0,0,0,0,0,0,0,0,0,1065,0,0,717,226,0,0,0,0,0,890,431,626,0,0,0,0,706,0,0,0, +51,698,0,0,0,0,0,0,0,0,0,0,0,828,0,0,17,0,0,0,0,1929,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,84,0,0,0,0,0,0,0,0,0,0,0,0,0,0,27,871,498,0,101,1793,0,0,0,0,0,0,435,0, +0,0,0,0,966,0,129,1644,0,0,0,0,0,0,0,0,0,0,0,0,0,997,502,0,0,0,0,0,0,0,0,0,0,0, +0,823,0,1927,0,0,0,0,98,1756,0,0,0,0,0,0,0,0,0,0,0,0,8,0,160,1046,0,492,0,0,0,0, +0,0,129,45,0,0,0,0,0,0,353,558,0,0,0,0,0,785,0,0,0,1145,189,0,0,0,26,353,0,0,0, +0,0,2024,0,0,0,606,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,32,855,0,0,0,0,0,0,0,0,0,0,0, +0,0,2011,0,0,5,4,0,0,461,764,0,0,0,1449,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1445,0,0, +0,1168,0,0,0,233,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,0,0,216,0,0,0,286,0,0,0, +3,0,0,0,723,536,0,0,0,0,0,285,0,0,0,560,0,0,0,0,0,690,0,0,0,0,0,1246,0,0,63,0, +33,0,0,0,0,0,520,1862,0,0,0,0,0,0,0,0,0,0,0,0,630,0,0,0,0,554,0,0,0,0,0,1001,0, +0,0,0,0,446,0,0,0,0,0,0,0,1313,0,0,837,636,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,278, +0,0,0,0,0,0,0,0,868,0,0,0,0,1010,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +1231,0,304,0,506,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,26,0,93,1408,794, +843,704,0,285,114,485,898,145,0,19,2035,0,0,0,1933,0,0,0,0,0,0,0,1728,0,0,0,0,0, +0,0,0,746,0,0,0,0,0,0,0,995,1964,0,0,0,0,0,0,0,0,0,0,0,1550,0,874,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,1018,0,0,0,814,126,0,0,1264,0,0,814,955,0,0,0,0,0,0, +0,981,0,0,0,0,0,0,0,0,915,56,0,0,100,0,0,0,0,0,0,0,0,0,638,0,0,0,0,738,0,0,0,0, +0,0,0,0,0,758,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1112,0,0,214,0,0,0,133,0,196, +168,0,0,0,0,0,1152,0,1245,0,0,538,169,871,1816,0,0,413,133,0,0,0,978,0,0,43,93, +371,0,0,0,0,0,0,526,25,0,754,335,0,0,0,0,182,0,0,0,0,0,0,0,0,0,0,0,39,601,0,0,0, +0,0,0,0,181,370,0,0,1652,358,0,0,0,0,0,0,0,0,0,176,286,0,788,0,0,0,0,0,1223,780, +254,1003,896,0,0,0,1447,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,744,0,0,0,0,0,126,0, +41,788,0,0,0,629,0,0,0,0,0,0,0,0,0,0,0,293,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,420,37,1900,0,0,0,0,542,1570,957,0,0,0,0,0,0, +0,373,31,0,0,0,0,125,325,0,0,0,0,0,0,323,0,0,1547,0,0,0,0,0,0,0,0,0,0,0,0,0, +1216,0,0,0,0,0,0,198,1905,629,15,0,0,0,0,0,0,20,75,543,1353,0,0,0,533,0,0,6,0,0, +0,0,0,0,538,0,0,0,0,0,0,0,0,0,0,0,338,0,0,0,0,11,0,0,0,284,659,0,989,0,0,0,0,0, +0,0,0,0,848,0,0,507,0,0,0,0,0,0,0,0,188,991,884,0,0,0,0,60,959,0,0,0,0,0,1653,0, +0,922,337,0,638,0,0,500,0,0,0,0,0,0,0,0,0,0,0,166,0,0,0,0,0,0,0,0,0,0,0,0,418,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,760,0,0,0,0,0,0,1277,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,770,0,0,0,0,0,0,0,243,89,0,0,0,0,0,0,0,0,0,1396,0, +560,0,0,3,1658,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,586,0,0,1271,0,0,0,505,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,637,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1947, +41,445,0,0,0,0,0,0,0,0,57,189,0,0,371,0,0,0,0,552,0,883,0,923,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,875,0,0,0,1788,49,0,0,0,0,0, +0,0,0,0,0,0,661,0,0,1945,0,0,0,0,0,794,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,1135,0,0,0,745,0,0,0,0,0,0,0,84,0,0,0,0,0,0,0,410,0,976,0,0,0,0,0,703,0,0, +0,0,0,0,187,322,0,0,0,227,0,0,0,0,560,0,31,1395,0,0,0,0,0,466,0,0,0,0,643,167,0, +0,0,1428,0,412,0,0,0,0,0,0,0,0,0,1118,562,0,0,0,0,0,256,0,0,0,0,0,0,1771,0,0,0, +0,0,1190,132,0,66,0,0,0,0,0,0,0,0,0,0,317,0,0,0,63,0,0,0,0,0,0,0,1475,0,0,0,0,0, +0,0,288,0,0,0,0,608,0,0,0,0,0,0,0,0,1225,0,1189,0,0,0,0,0,0,0,1468,0,0,0,0,0, +689,120,0,0,0,0,0,0,0,1,0,329,0,0,0,0,226,0,0,0,0,0,1855,0,0,461,0,0,0,0,1346,0, +0,0,0,0,85,0,0,299,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1171,0,0, +0,980,0,0,0,0,0,0,0,0,637,279,0,0,0,0,0,293,0,0,0,0,528,17,0,0,0,0,5,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,48,0,0,0,0,0,0,0,601,0,0,0,0,0,0,779,0, +196,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1322,737,752,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,412,192,80,0,0,8,1470,0,0,0,0,0,0,0,0,0,873,0,0,0,0,0,835,0,0,0,0,256, +38,986,0,0,0,0,0,0,0,0,0,91,257,278,911,0,0,0,0,0,0,0,0,749,151,0,0,0,0,0,0,0,0, +0,0,0,0,989,0,0,990,0,0,90,194,0,0,0,0,0,425,0,0,0,0,0,774,0,0,0,0,0,0,0,0,0,0, +646,827,752,0,0,0,662,0,22,21,0,0,0,0,0,0,95,239,0,0,0,431,0,0,0,0,0,874,0,0, +265,65,0,0,0,1350,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1887,0,0,0,0,0,0,0,809, +0,696,0,1074,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,630,0,0,802,0,0,0,56,776,0, +970,0,0,797,0,0,0,0,0,400,0,0,1951,0,0,41,0,11,118,0,0,0,0,0,0,0,0,251,615,0,0, +0,1044,0,0,0,0,0,0,0,0,0,0,0,225,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,370,0,0,0,0, +104,48,209,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,930,0,0,0,0, +0,0,0,0,0,0,0,1286,0,759,0,120,385,0,0,0,429,0,0,0,0,0,0,0,0,820,0,0,0,0,0,0, +199,0,10,151,0,0,0,761,365,0,0,0,0,0,0,0,0,0,46,1086,0,0,0,0,11,1624,58,344,0,0, +1008,1868,0,0,0,888,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,711,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,440,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,914,1913,0,958,0,885,0,0,0,0,0,0,0,0,0,0,0, +0,0,847,276,0,302,65,0,0,0,510,0,1514,0,0,0,0,0,0,152,291,0,0,0,0,0,0,0,0,0,0,0, +0,282,589,0,0,0,0,0,0,0,0,0,0,0,0,0,130,0,0,463,42,0,0,0,0,0,372,0,0,0,0,0,0,0, +0,0,680,0,0,0,0,0,0,0,0,977,1997,0,0,0,810,0,0,0,0,0,0,0,0,0,1390,0,0,0,644,0,0, +867,982,0,0,0,0,0,0,0,540,0,123,0,0,0,1978,0,0,0,0,789,623,0,1723,0,1220,0,0,0, +0,0,0,0,480,0,0,0,0,0,0,0,0,0,0,0,888,0,0,0,0,0,0,0,0,0,0,0,0,299,1995,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,788,179,0,0,0,0,0,0,431,156,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1373,39,80,196,0,0,507,0,0,0,646,0,0,0,0, +0,1214,0,0,0,0,926,0,0,0,1,114,0,0,0,0,0,446,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,490,0,0,0,491,0,1584,0,0,507,250,0,0,0,158, +10,362,1,0,0,0,0,0,0,0,0,0,408,228,860,480,0,779,0,0,0,557,0,0,142,197,0,0,0,0, +0,0,0,0,0,0,0,1490,11,378,316,1057,0,0,18,579,299,1546,0,177,0,0,0,0,0,0,0,0,0, +411,0,0,0,0,727,439,0,0,0,0,0,1528,0,0,0,0,0,0,58,0,482,0,0,0,505,1952,0,0,0,0, +0,0,0,0,0,0,0,242,0,0,0,0,0,0,0,953,0,0,0,0,802,0,0,0,0,0,0,0,0,0,0,290,0,0,791, +52,0,0,0,0,0,0,0,0,0,0,0,112,0,0,0,0,0,1028,0,0,138,0,0,0,0,1811,0,0,0,0,0,0, +934,1821,0,0,0,0,371,38,0,0,0,1296,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,723,0,0,0,0,0, +0,0,0,0,0,0,0,0,1330,0,0,0,0,0,0,0,1255,296,109,0,0,0,0,0,660,0,0,0,0,270,591,0, +0,0,0,0,0,0,1090,81,0,0,0,0,391,0,0,0,0,249,322,0,0,0,0,0,0,0,1412,0,0,0,0,0,0, +0,0,0,0,526,632,0,0,0,0,0,0,235,144,0,0,0,0,0,940,0,0,0,52,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,309,196,0,0,0,0,0,1912,0,1290,0,686,0,0,625,0,0,0,0,0,0,0,0,0,0,0,412,0, +0,0,0,43,0,0,0,0,11,967,758,0,0,0,0,0,0,0,0,0,0,0,0,0,0,220,0,0,0,0,0,0,0,0,0,0, +873,11,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,890,0,0,2,0,0,0,0,0,0,0,0,1774, +393,263,0,0,0,0,0,0,818,456,0,0,251,178,393,97,0,0,0,0,0,674,168,0,0,0,0,0,0,0, +159,1639,0,0,0,0,0,0,0,0,59,934,0,191,0,0,0,0,346,165,0,877,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,128,0,0,0,0,0,0,1297,0,0,0,0,0,0,164,0,0,0,15,132,241,1073,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,228,324,53,0,0,910,0,0,0,0,0,0,0,0,734,705, +217,73,0,0,0,0,0,0,0,0,636,389,0,1409,0,0,0,0,0,893,0,0,0,0,21,0,0,0,0,0,0,0,0, +0,0,0,0,0,721,0,0,0,959,0,0,0,0,1433,0,0,0,0,0,0,0,0,0,0,0,0,174,189,0,0,0,0,0, +0,0,0,0,0,22,2,0,0,815,354,0,0,0,0,425,0,411,60,13,1611,0,0,0,0,0,0,0,0,0,0,0,0, +0,1478,596,0,0,398,0,50,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,192,1159,0,0,0,0,0, +592,223,0,0,0,0,0,0,0,245,64,0,0,0,0,278,0,604,0,0,1502,265,0,0,0,0,0,0,0,310, +1763,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,129,0,0,0,0,0,0,0,0,0,1356,0,0,0,0,0,0,0, +0,505,0,0,0,0,0,0,0,1000,0,0,966,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,839,0,0,0,0,0,0, +0,0,0,0,0,0,0,637,0,0,0,0,0,0,0,0,0,0,0,0,0,0,590,0,0,0,0,280,0,0,0,1386,0,0,0, +281,0,1064,0,0,0,0,0,917,0,0,15,555,0,0,1014,1883,0,0,0,965,0,0,117,33,0,0,0, +801,0,0,0,0,0,877,0,824,0,0,0,0,0,0,0,0,0,0,0,365,0,0,0,0,0,0,774,7,0,430,0,0, +231,360,0,0,0,0,0,0,0,0,822,740,0,0,929,1485,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,852,0,0,0,0,17,0,0,0,0,0,0,1001,0,0,0,0,35,831,0,0,384,457,0,0,0,1351,0,27, +0,0,984,0,264,552,0,401,0,0,0,710,0,1211,0,0,11,205,0,0,0,0,0,0,0,0,0,0,0,0,5, +579,0,717,0,0,1011,0,0,0,0,0,0,0,0,0,0,0,0,0,0,805,0,0,0,0,0,0,0,0,0,0,0,489,0, +0,0,1024,0,0,0,0,0,0,0,0,0,892,0,0,0,0,0,0,0,0,0,0,0,0,473,0,0,0,659,864,0,0,0, +0,0,0,152,819,0,51,0,0,0,0,0,0,0,0,0,0,130,0,0,0,0,0,229,0,0,0,0,674,0,0,0,0,0, +0,0,0,0,770,52,79,0,0,0,1666,0,409,0,0,0,0,0,0,0,195,0,688,0,0,0,0,0,0,0,0,0,0, +0,889,174,160,0,0,0,0,0,0,0,0,0,0,0,0,0,872,0,918,569,268,0,0,0,1224,0,1361,0,0, +0,0,0,0,0,0,0,374,0,0,0,0,0,731,0,0,0,0,190,0,0,0,0,0,0,0,202,506,444,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,835,0,17,1526,0,0,0,0,0,477,0,0, +994,1374,76,0,0,0,0,0,0,0,355,287,0,1389,0,0,0,0,0,0,455,384,0,0,0,264,0,0,0,0, +0,0,0,0,0,0,0,0,1001,0,0,0,0,0,0,0,0,0,0,0,0,28,0,0,0,851,175,359,0,0,0,0,0,0,0, +0,287,740,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,857,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +819,1402,0,0,0,0,0,0,174,224,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1649, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,655,573,0,0,0,0,0,0,0,0,128,351,0,0,0,0,0,0, +0,0,0,0,0,918,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,687,0,0,0,0,0,0,0,0,0,1525, +0,0,0,1009,0,0,0,0,0,0,0,340,0,0,0,0,0,0,0,0,0,0,861,0,176,0,0,0,0,0,0,0,0,0,96, +985,0,615,0,0,0,0,0,0,0,1919,0,0,0,0,0,1131,0,0,0,0,0,0,0,247,0,0,0,0,27,23,0,0, +0,0,0,0,0,0,38,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1015,0,0,0,0,0,1088,0,0, +0,0,0,1585,0,0,0,0,227,0,0,0,478,360,0,0,0,95,0,0,0,0,0,0,699,0,0,0,26,0,0,0,0, +1119,0,0,0,739,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,741,67,0,0,0,0,0,0,464,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,42,0,96,0,0,0,26,342,0,0,0,0,0,0,203,0,0,449,0, +0,0,0,0,0,0,0,0,0,256,311,0,0,0,0,0,0,758,0,0,0,0,0,0,0,0,827,0,0,0,0,581,64,0, +1047,0,0,0,0,0,288,0,0,0,0,0,1375,0,0,0,0,0,0,0,0,0,0,0,1309,0,0,0,0,0,0,0,0, +376,12,0,0,0,0,0,154,0,1520,0,1753,95,502,0,0,0,0,0,0,0,269,291,1197,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,0,0,0,0,1341,0,1017,0,0,0,0,0,0,0, +0,857,1810,533,0,0,1453,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,836,211,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,19,0,156,0,0,0,0,1009,0,0,0,0,0,0,0,0,0,0,0,0,0,820,0,0, +0,0,0,0,0,0,0,228,0,0,0,1131,0,1276,0,0,0,0,0,0,0,0,0,0,0,0,849,1792,0,0,389, +291,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,525,0,0, +0,453,0,0,0,0,666,0,0,0,422,0,355,0,0,0,0,165,0,260,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,865,0,0,0,0,0,0,0,1625,0,0,0,234,0,1383,0,0,0,0,0,0,0,0,306,0,0,0,802,1921, +0,0,0,0,0,0,180,0,0,0,0,1312,814,0,0,0,0,0,0,0,0,0,0,707,0,0,0,1493,11,61,733,0, +0,0,341,0,0,0,98,0,0,0,0,0,0,0,0,0,0,0,1014,0,0,0,0,0,0,0,142,102,0,0,30,0,0, +823,0,1045,0,0,0,1930,0,1512,0,0,0,0,0,0,0,87,0,1243,245,0,0,0,0,0,0,0,48,68,0, +0,0,0,0,0,0,0,126,77,625,938,0,0,351,0,0,0,174,1668,0,707,0,0,0,0,0,0,0,0,0,0,0, +403,0,0,0,0,0,0,0,0,0,0,0,0,6,0,0,282,0,0,0,0,0,0,8,44,0,0,363,115,0,0,0,0,0,0, +0,0,0,0,0,0,545,761,0,0,835,1254,0,0,0,0,930,1936,0,0,0,0,0,0,0,0,653,0,0,0,0,0, +344,0,0,1483,673,185,0,0,460,93,753,478,0,0,0,0,0,1020,0,0,0,0,0,0,0,103,0,0,0, +499,0,0,0,0,0,0,207,0,0,0,0,0,0,0,0,0,0,0,0,0,0,96,0,968,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,3,0,0,0,0,399,0,0,0,0,224,563,0,0,0,0,0,704,0,0,0,0,0,0,0,0,0,0,0, +1559,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,861,0,0,0,0,946,333,746,0,0,0,0,0, +0,0,910,0,0,0,0,0,0,0,0,0,0,0,0,0,652,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +1393,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1514,0,0,0,0,201,0,510,717,0,0,528,0,0,0,0, +20,0,0,0,1251,0,0,0,1163,0,0,0,307,0,0,0,0,0,1091,0,0,0,0,0,0,0,0,0,0,0,429,0,0, +0,881,0,0,0,0,0,621,0,0,0,0,0,0,0,736,0,348,0,868,0,0,0,0,433,0,0,0,771,1495,0, +0,0,0,215,0,0,0,0,0,124,0,0,0,0,0,0,0,0,0,0,0,55,0,0,0,0,0,0,0,112,62,0,856,270, +0,572,0,0,0,0,939,0,0,0,0,0,0,0,352,0,0,0,0,0,0,0,0,0,647,0,0,0,0,10,0,0,0,0,0, +0,0,220,0,0,0,0,0,0,0,0,0,0,0,0,0,464,0,0,109,0,0,0,1746,0,0,0,515,0,0,0,566,0, +0,0,0,0,0,67,40,0,0,722,992,0,0,923,0,0,0,0,0,0,1145,0,0,0,0,0,0,0,0,0,0,0,568, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,247,0,0,0,0,645,0,0,328,0,0,0,0,0,0,0,0,0,0,0,0, +1363,0,0,0,0,0,1280,0,0,0,0,0,0,0,0,0,0,7,28,360,162,0,0,0,0,0,0,0,0,0,0,0,764, +0,0,833,862,0,856,0,0,0,0,0,0,736,92,0,0,948,1944,0,1479,63,590,0,0,0,1521,0,0, +0,709,0,0,61,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,483,0,0,0,0,1213, +0,0,0,0,29,1022,0,1712,0,466,0,0,0,0,0,0,0,0,0,0,0,0,0,731,0,0,0,0,0,0,171,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,241,0,0,0,0,0,0,0,0,0,0,0,964,2005,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,1100,0,0,0,954,0,0,0,0,0,0,0,0,0,1958,0,0,34,549,994,0,0,449, +137,850,0,0,670,146,0,0,0,0,518,159,0,0,0,0,0,0,0,0,151,0,0,1027,0,0,0,0,0,0,0, +0,0,0,983,0,0,0,0,993,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,141,501,0,0,0, +0,0,0,0,0,0,452,0,0,0,0,0,0,0,0,0,0,233,149,0,0,0,0,0,0,0,0,582,0,0,0,801,0,0,0, +0,0,0,70,0,0,369,0,36,0,0,0,0,0,0,0,204,721,430,241,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1817,16,1078,1021,0,0, +406,0,0,0,0,0,69,0,0,0,0,0,1830,0,0,0,824,0,0,0,0,0,0,0,0,0,826,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,816,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1000,717,1845,0,423,0,0, +0,0,0,0,0,0,510,0,0,1048,0,0,0,618,0,0,0,520,0,0,0,0,990,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,321,0,0,0,0,0,0,0,1135,0,0,921,0,0,0,24,397,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,856,0,0,0,139,282,981,0,288,0,0,0,1890,651,56,0,0,0,0,0,0,0, +0,261,0,0,0,0,0,0,0,0,0,0,0,617,1403,0,1205,0,0,563,0,0,0,0,0,0,0,0,333,0,0,0,0, +0,369,0,0,0,0,0,0,0,0,0,622,0,0,0,1407,0,0,0,0,0,0,0,0,0,0,0,0,624,160,0,363,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,619,0,174,292,0,0,656,616,0,0,0,685,0,0,0,0,0,0,0,0,0,0,0,0,0,647,0,0,0,631,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1267,0,0,0,1797,0,0,0,1684,0,0,469,0,531, +1230,73,0,0,0,0,0,0,0,0,0,268,0,0,0,0,0,102,558,109,65,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,595,0,0,0,0,0,374,1832,0,0,0,0,0,0,16,0,405,6,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,881,0,1495,0,0,0,0,0,0,0,0,0,142,0,0,0,0,0,0,0,0,0,0,21,466,23, +257,0,0,0,0,0,0,77,404,0,0,0,0,0,0,712,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,860, +1848,0,0,652,629,0,0,0,0,13,377,0,1842,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1501,0, +0,0,1906,0,0,0,0,0,0,0,0,0,0,0,0,0,491,234,171,0,0,0,0,631,1186,0,0,0,0,0,0,0,0, +0,0,0,0,931,0,170,0,0,0,0,0,0,0,0,0,0,1587,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +765,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,424,0,0,714,0,0,0,0,685,0,0,0,0,0, +0,285,0,0,0,0,0,0,429,0,0,0,0,0,0,0,0,0,0,71,18,0,0,0,0,0,0,0,0,0,0,116,828,0,0, +0,0,0,0,289,0,0,0,0,0,0,0,0,675,0,0,0,1424,0,0,0,0,0,647,0,0,0,1334,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,36,209,0,0,0,0,0,0,0,342,0,0,0,928,0,0,0,0,0,1838,118,856,654, +318,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,915,895,454,0,0,513,1425,0,0, +0,0,0,0,791,0,153,0,0,0,0,0,0,796,909,445,345,0,0,0,0,0,0,0,0,578,0,0,0,1387,0, +0,0,555,0,0,0,0,0,0,766,0,0,0,0,0,0,0,0,0,0,541,0,0,0,0,0,0,0,0,0,0,0,0,0,880,0, +0,0,0,0,1506,0,0,983,0,768,0,0,0,0,584,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,737, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,226,30,426,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +117,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,462,0,0,0,385,0,398,0,0,0,0,0,0, +0,0,0,347,0,0,0,0,125,1259,644,136,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,469,0,0,0,0,0, +1367,0,0,0,0,0,0,0,0,0,0,0,719,0,0,0,0,0,0,0,0,0,0,0,0,0,1423,0,0,0,0,0,0,0,0,0, +749,0,0,0,0,546,645,0,0,0,0,0,0,277,0,0,1275,0,0,0,0,0,0,0,453,536,555,0,0,987, +1107,0,0,90,0,0,0,0,0,0,0,0,860,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +257,0,1768,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1071,0,0,0,0,0,0,0,0,0,0,0,0,0,83, +0,835,0,0,0,0,0,0,0,2006,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,696,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,95,1718,0,0,0,0,0,0,0,26,0,550,0,0,0,0,0,901,0,0,0,0,0, +0,822,0,0,122,0,0,0,807,0,0,0,0,0,262,0,620,601,34,0,0,170,0,0,0,0,537,0,0,0,0, +0,0,0,0,0,332,0,0,208,1909,182,261,0,0,0,1721,0,0,0,0,0,933,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,1609,0,895,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,812,0,0,942,1916,0,0,0,0, +0,0,0,778,0,0,0,137,0,1314,0,0,0,0,0,0,0,1661,0,0,0,0,0,0,0,1591,0,0,0,0,0,0, +820,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,185,89,0,1160,230,6,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,63,29,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1740,0,0,177, +170,0,1961,0,0,0,0,0,0,0,0,0,0,0,0,91,0,17,44,0,0,0,0,0,0,0,0,0,270,0,296,0,0,0, +0,0,0,0,1523,0,0,0,0,0,0,0,0,0,0,757,7,0,0,0,0,0,0,0,0,0,0,530,588,0,0,0,0,0,0, +0,0,0,786,0,0,0,0,0,580,627,88,447,57,0,0,0,0,0,0,0,0,845,735,0,0,0,0,0,31,15,0, +460,521,12,424,0,0,0,1302,0,0,0,0,0,0,0,595,0,0,0,13,548,97,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,1472,452,1767,0,0,0,0,0,0,0,0,0,0,115,0,0,0,0,0,0,1543,0,1111,0,0,0,0, +1,0,359,488,0,267,0,0,0,1983,0,0,0,0,0,0,0,1155,0,1575,0,1438,31,0,0,377,101,0, +0,0,0,0,0,0,0,0,0,0,0,0,476,0,0,0,0,0,0,0,0,2023,0,0,0,0,0,1836,0,0,0,0,35,843, +0,0,0,0,0,0,0,554,0,0,0,536,625,207,0,1371,0,0,0,424,785,336,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,896,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,27,750,0,0,0,0,238,0,0, +0,0,0,383,0,0,0,0,0,0,0,0,603,725,11,0,0,0,0,0,0,0,0,0,476,0,0,0,0,0,1552,0,0,0, +0,0,0,0,680,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,435,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +1431,0,0,13,112,0,0,356,0,0,0,0,0,0,0,0,0,0,1963,0,0,0,1244,18,0,0,0,0,0,0,867, +0,0,0,0,0,0,50,708,73,592,0,502,0,0,0,0,0,0,161,347,0,0,0,0,470,33,0,246,571,10, +0,465,614,0,237,0,0,0,0,0,24,18,0,506,0,0,0,0,0,0,33,309,0,0,0,0,0,0,0,0,0,0, +140,0,0,0,0,1056,0,0,0,1704,0,0,0,0,0,0,0,1036,0,0,0,0,0,0,0,0,0,1315,432,86, +264,524,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,107,0,0,0,0,0,123,927,0,0,957,1149,0,0, +0,0,0,778,0,502,196,0,0,0,0,1312,0,0,0,0,0,0,0,855,0,0,0,0,0,0,0,0,0,0,45,1400, +0,0,0,1003,0,0,0,0,0,1097,0,0,0,0,0,0,0,0,545,612,0,0,0,0,0,0,0,0,0,0,0,0,54,0, +0,0,0,172,0,0,0,1029,0,0,0,0,0,0,0,0,0,568,0,0,0,732,617,0,0,974,94,989,733,0,0, +0,0,0,0,1789,0,0,665,2015,0,0,0,0,0,0,806,287,0,0,0,0,0,1539,0,0,0,0,0,0,0,0,0, +0,182,1563,0,0,0,0,0,0,0,0,0,484,0,0,0,0,0,1623,0,0,0,0,0,0,0,0,878,1833,0,1569, +0,0,0,0,0,0,0,0,93,0,715,994,0,0,0,0,0,63,0,591,0,0,0,0,0,0,0,749,0,0,0,0,547, +366,0,0,0,1747,0,0,0,0,0,0,0,89,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1463,0,772, +893,0,0,0,48,0,0,941,0,0,690,1785,106,440,0,0,0,0,0,0,0,0,0,0,32,0,332,216,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,852,0, +0,416,564,0,918,0,1764,0,0,3,0,0,274,0,0,0,0,501,0,0,0,0,0,0,0,851,743,0,49,0, +879,0,0,47,0,0,0,0,0,0,865,0,1202,0,0,0,0,0,0,47,272,0,0,0,0,0,0,0,0,0,0,0,1455, +0,0,0,0,891,1911,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,761,0,0,0,0,0,0,0,0,0,407,0, +183,0,0,490,0,0,0,0,0,0,0,35,731,0,0,0,0,0,0,0,819,0,0,0,0,0,0,0,0,0,0,0,0,0, +575,0,0,0,0,45,818,0,0,77,222,0,0,0,0,849,1880,0,0,0,633,0,1308,0,0,0,0,0,0,0,0, +0,0,86,0,0,0,0,0,0,0,0,0,0,0,0,0,0,817,0,0,0,0,0,0,0,0,0,882,0,0,0,914,0,0,0,0, +0,0,0,0,0,0,865,0,0,426,399,58,0,0,0,0,0,0,538,102,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,876,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,139,566,0,63,12,0,0,0, +0,0,0,0,0,0,0,0,0,0,3,114,0,0,0,0,0,0,0,0,576,0,0,0,0,0,0,0,0,933,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,692,0,0,0,0,0,0,0,0,0,0,0,0,752,0,0,0,0, +0,0,0,0,375,0,1011,0,0,96,0,0,0,0,0,0,0,0,0,148,0,0,0,0,0,0,0,0,0,0,0,337,56, +666,0,246,394,0,0,0,0,0,0,0,0,437,0,0,0,506,0,0,0,0,1003,0,1163,0,328,0,0,0,0,0, +0,0,0,1000,0,0,0,0,0,744,101,0,0,0,0,0,726,0,0,176,0,146,9,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,839,0,0,0,0,0,0,223,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,246,1931,29,0,0,1771,0,0,0,0,0,846,6,157,0,0,0,0,0,0,0,0,0,875,0,0,477, +773,177,639,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1747,0,0,0,0,158,873,0,659,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,391,0,0,0,0,0,0,0,0,0,0,0,0,668,883,0,78,628,0,0,0, +0,0,0,0,0,0,0,0,0,1460,0,962,0,0,0,0,0,460,0,0,0,0,0,0,0,0,0,0,0,0,0,0,34,199,0, +0,0,388,474,0,271,0,333,608,0,0,0,0,0,0,49,0,988,0,707,617,0,0,0,0,0,0,0,756,0, +0,0,0,0,1583,0,0,0,0,0,0,0,0,0,0,285,0,0,0,0,0,0,0,0,0,0,0,0,0,0,344,0,0,0,0,0, +0,0,0,515,1709,0,0,0,0,0,0,0,0,404,0,0,0,0,500,0,0,0,0,0,0,0,0,0,68,216,0,0,0,0, +0,0,0,488,353,0,0,177,236,0,0,458,490,0,0,0,0,0,0,756,1504,0,757,0,1735,0,0,108, +598,0,0,0,0}; +BROTLI_INTERNAL const uint8_t kStaticDictionaryHashLengths[32768] = { +8,0,0,0,0,0,0,0,0,4,0,0,0,0,0,0,0,6,0,0,0,0,0,6,0,0,0,0,0,0,12,0,0,0,0,4,22,5,0, +4,0,0,0,0,0,0,0,0,0,0,0,0,14,6,0,0,0,5,0,0,0,0,0,0,0,7,13,0,0,4,0,0,0,0,0,0,0,0, +0,6,0,0,0,0,8,0,0,0,0,0,0,7,0,7,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,0,0,4,0,0,0,4, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,10,4,0,5,13,7,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,9,6,0,0,8,7,0,0,9,0,8,0,0,0,0,0,0,6,0, +0,9,0,0,0,11,0,0,6,8,7,0,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,7,0,0,0,6,8,0,0,0,0,0, +0,0,11,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,0,0,9,0,0,0,8,4,13,7,0,0,0,0,0, +7,0,5,0,0,0,0,8,5,0,5,0,0,8,7,0,0,0,0,0,0,0,0,0,0,9,0,0,0,8,0,0,0,10,4,0,5,0,4, +0,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,6,0,6,0,0,0,0,8,7,0,4,9,4,0,0,0,0,0,0, +9,0,0,0,8,5,0,0,0,6,0,0,0,0,0,0,0,0,0,7,18,0,0,0,0,4,9,0,0,4,0,6,0,0,0,6,0,6,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,0,6,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,5,8,7,0,0,0, +0,9,0,0,0,0,0,0,0,8,6,10,6,0,0,0,4,0,6,8,6,0,0,0,4,0,0,0,0,0,5,0,0,0,6,0,0,0,0, +10,0,12,7,0,0,0,0,0,4,0,0,0,0,0,5,0,0,8,7,0,0,0,0,0,0,0,0,9,5,0,0,0,0,0,0,0,0,0, +0,0,0,0,6,11,0,0,0,0,0,0,0,0,0,8,7,0,0,10,0,0,0,0,0,0,0,0,6,10,0,17,0,8,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,0,0,8,6,9,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +7,0,0,11,4,0,5,0,0,0,0,0,0,0,0,0,0,10,5,0,6,8,5,0,0,0,0,0,0,0,0,0,0,11,5,0,0,0, +0,0,0,0,0,8,0,0,0,0,0,0,0,0,0,9,0,0,0,0,5,0,0,0,0,0,0,0,0,0,6,0,0,8,7,0,0,0,0,0, +0,0,0,0,0,0,5,0,0,0,6,0,0,10,0,0,0,20,0,0,0,0,0,0,0,0,6,9,5,0,0,0,0,10,4,8,0,0, +4,13,0,0,0,0,0,0,0,9,0,9,0,0,0,0,0,0,0,0,0,0,0,0,4,8,6,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,12,0,0,4,0,0,0,0,0,0,0,4,0,0,0,0,0,0,0,0,0,0,12,5,0,0,10,4,10,7,13, +0,0,0,0,0,0,0,0,6,0,6,0,6,0,0,0,0,0,0,19,0,0,4,12,6,9,0,0,0,0,4,0,4,11,0,0,0,0, +0,0,0,12,0,0,0,8,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,11,4,0,0,0,0,0,0,0,0,0,6,0,0,0,0, +0,5,0,0,0,0,0,6,0,0,0,6,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,8,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,17,0,0,0,9,6,0,0,0,0,0,4,0,4,0,0,0,0,0,0,0,0,0,4,0,0,0, +6,0,0,0,0,0,0,0,0,0,0,13,6,0,0,0,0,0,0,0,0,0,0,0,6,8,0,0,0,0,0,0,0,0,0,0,6,0,0, +0,0,0,5,0,0,0,0,14,4,0,0,0,4,12,5,0,0,0,0,0,0,0,0,0,7,0,0,0,0,0,0,0,0,0,0,8,6,0, +0,0,0,0,0,12,0,9,6,0,0,0,0,13,0,0,5,0,0,0,0,0,4,0,6,0,7,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,13,0,9,0,0,6,0,0,0,0,0,0,0,0,0,0,0,0,12,0,0,5,0,0,0,6,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,6,0,6,0,0,0,0,0,0,0,0,8,7,8,4,0,0,0,0,0,0,0,0,0,0,0,7,0,7,0,0,0,4,0, +0,0,0,0,0,0,0,0,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,0,0,8,6,8,4,0,0,0,0,0,6,0,7,0, +0,0,0,0,0,0,0,0,0,10,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,0,7,0,0,0,0,0,0,9,5,0,0, +0,0,0,7,0,0,0,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,0,0,0,0,9,4,0,0,0,0,0,0,0,4, +12,5,11,0,0,0,0,0,0,0,0,0,8,7,0,5,0,0,8,7,0,5,0,0,0,0,8,0,0,0,0,7,0,4,10,0,0,0, +0,0,0,0,9,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +13,5,0,0,0,4,0,0,0,0,0,6,0,0,0,0,0,0,14,5,0,0,0,7,0,0,10,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,6,0,4,0,5,0,0,0,0,8,5,0,0,0,0,0,0,9,5,9,0,0,0,0,0,0,0,0,6,9,0, +0,4,0,0,0,7,0,0,0,6,0,0,10,4,0,0,0,0,0,6,0,0,10,0,0,0,8,5,0,0,0,0,0,0,0,0,10,0, +0,0,0,0,18,4,12,0,0,0,0,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,6,0,0,0,0,8,7,0,0,0, +0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,8,4,0,0,8,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,0,0,0, +0,0,0,0,0,0,0,0,0,0,7,0,0,0,0,8,0,0,0,0,0,0,6,0,0,0,4,10,5,0,0,0,0,0,0,0,0,0,0, +0,4,8,7,0,0,8,6,0,0,0,0,0,0,0,0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,10,6,0, +0,0,0,8,6,0,0,0,0,0,0,12,0,0,0,0,0,0,0,0,0,0,0,10,0,0,0,0,0,0,6,0,7,0,0,0,0,0,0, +0,0,0,0,0,6,0,0,0,7,0,0,0,0,0,0,8,7,0,0,0,0,8,0,12,6,0,6,0,0,0,0,9,7,11,7,0,0,0, +0,0,0,0,0,0,0,0,0,11,0,0,0,9,0,0,0,0,0,0,0,0,0,0,0,8,7,0,0,10,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,8,6,0,0,0,0,0,0,0,5,0,0,0,0,0,0,0,0,0,7,0,0,0,0,0,0, +0,0,0,6,0,0,0,7,0,4,14,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,14,0,0,0,0,0,8,4,0,4,0,0,0,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,20,0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,12,5,0,7,0,5,0,0,10,0,0,7,0,0,0,0,0,0,0,0,0,0,14,0,0,0,0,6,0,4,9,7,0,0,0, +0,0,7,0,0,0,0,0,0,10,0,9,0,9,0,0,0,0,0,0,0,0,4,9,0,0,0,0,6,0,0,0,0,0,0,0,0,11,4, +0,6,0,0,0,0,0,0,8,0,8,0,0,0,0,0,0,0,0,0,0,4,0,0,0,5,0,0,0,0,0,0,0,0,13,6,0,0,11, +0,0,0,0,0,0,0,9,7,0,0,0,0,0,0,0,0,0,0,0,6,18,0,0,4,0,0,0,0,0,0,0,6,0,0,0,0,0,0, +0,5,0,0,0,0,0,0,0,0,9,7,0,0,0,0,0,0,0,6,0,0,0,0,9,0,8,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,7,0,0,0,0,0,0,0,0,0,0,11,7,0,0,0,0,0,6,0,0,0,7,0,0,0,0,0,0,0,0,11, +4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,4,0,0,0,0,8, +6,0,0,0,0,0,0,9,6,0,0,0,0,0,4,0,0,0,0,8,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,19,0,0,0, +0,6,0,6,0,0,0,0,0,0,0,7,0,0,0,0,0,0,0,0,0,6,0,6,0,0,10,6,0,0,0,7,0,0,8,0,8,7,0, +0,0,0,0,0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,10,6,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,9,0,0,0,0,6,0,0,0,0,0,0,0,5,0,0,18,0,0,0,0,0,0,0,0,0,0,0,0,0,9,6,0, +0,0,0,8,7,0,0,0,0,0,0,0,0,12,0,12,0,0,0,11,6,0,5,0,0,12,0,12,5,0,7,11,6,0,0,11, +0,0,0,12,0,0,4,12,7,8,6,0,0,0,0,8,5,0,0,0,0,0,0,0,4,11,0,0,6,0,7,0,0,0,0,0,0,0, +5,0,6,0,0,0,0,8,0,10,0,0,0,0,0,0,0,0,0,0,0,9,7,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,11,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,6,0,0,0, +0,0,0,0,0,0,0,0,0,11,7,0,0,0,0,0,0,10,0,0,5,0,0,12,6,0,0,0,0,0,0,10,6,0,0,0,0,8, +6,0,0,0,0,0,0,0,0,0,0,0,0,0,7,0,5,0,0,0,0,11,0,10,6,0,0,8,6,0,0,0,6,0,7,10,6,0, +0,0,7,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,0,0,0,0,10,7,0,0,0,0, +10,6,0,0,0,0,0,0,8,5,11,0,8,4,0,0,0,4,0,0,0,0,9,4,8,0,0,0,0,0,0,0,11,6,0,0,0,0, +10,7,0,0,0,0,0,6,0,0,0,0,0,6,0,0,0,7,0,0,0,0,9,6,0,5,0,7,0,0,0,0,0,7,0,0,11,0,0, +0,0,0,0,0,0,0,0,0,0,0,12,0,0,0,0,0,0,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6, +0,0,0,0,13,0,8,6,13,0,0,0,11,7,0,7,0,6,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,9,6,0,0,0,0,0,0,0,0,0,6,0,0,9,6,0,6,0,0,0,0,0,5,0,0,0,0,0,0,0,0, +0,0,0,0,0,5,9,0,0,0,0,0,0,0,0,0,0,4,9,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,4,0,0,0,0,0,0,0,0,0,0,0,6,0,0,0,0,9,7,0,7,0,0,0,0,0,0,0,0,0,0,10,0,0,0,0, +5,11,5,0,0,0,0,0,0,0,0,0,4,0,7,0,6,0,0,0,6,20,0,0,0,10,7,0,5,14,4,0,0,0,0,0,0,0, +0,0,6,0,0,0,0,8,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,9,0,0,0,0,0,0,0,0,0,0, +0,0,6,0,4,0,0,0,0,0,0,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,0,9,7,0,0,11,6,15,0,0,0,0,0, +10,0,8,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,14,7,0,0,0,0,0,0,0,0,9,7,13,0,0,0,0,0, +0,7,0,0,8,6,0,0,0,0,0,0,0,0,9,4,0,0,0,0,8,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,5,0,0,0,0,0,0,0,0,0,0,0,0,8,5,0,4,0,0,0,0,0,0,0,0,0,0,12,6,8,0,12,0,0,7,0,0,0, +0,0,5,10,0,0,0,0,0,0,0,0,0,0,0,0,0,8,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7, +14,0,0,0,0,0,0,0,0,0,0,0,0,5,0,5,8,7,10,7,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,6,18,6, +14,7,0,0,0,0,0,0,0,0,11,6,0,0,0,0,8,7,0,0,0,0,0,0,0,0,0,0,12,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,6,0,0,0,0,0,0,0,6,0,0,11,7,0,0,10,7,0,0,0,6,8,6,0,0,0,0,0,0,0,6,0,0, +19,0,0,0,9,5,0,0,0,0,0,0,11,7,0,0,0,7,0,6,0,0,11,0,0,0,0,4,8,0,0,0,0,0,0,0,0,6, +0,0,0,0,0,6,0,0,8,4,0,0,0,0,0,0,0,0,0,4,0,0,0,0,0,0,0,4,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,7, +0,7,0,0,0,7,15,0,0,5,0,0,0,0,10,0,0,0,0,0,0,0,0,0,12,0,0,0,0,0,0,0,0,0,0,7,0,0, +0,0,0,0,0,0,9,6,0,0,0,0,0,7,0,0,0,0,0,0,0,0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +11,7,0,0,0,0,0,0,0,6,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,0,0,0,0,0,0,0,0,0,0, +0,0,5,0,4,0,0,0,4,0,4,0,0,0,0,0,0,0,0,0,6,0,0,0,0,11,6,0,0,8,5,14,0,0,4,0,0,0,7, +17,0,0,0,0,0,0,0,13,5,0,0,0,0,0,5,0,0,0,5,0,0,0,0,16,6,0,4,0,0,0,0,0,0,12,0,0,0, +0,0,0,6,0,0,0,0,0,0,0,0,0,0,12,5,0,5,0,6,10,0,12,0,0,0,0,0,0,0,0,7,0,0,0,0,8,4, +0,0,0,0,0,0,0,0,0,0,8,7,0,0,8,0,0,0,8,0,0,6,0,7,0,0,0,5,0,6,0,4,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8,6,0,0,22,0,0,0,0,0,0,0,0,7,0,0,0,0,0,6,0,0,0, +0,0,0,0,0,0,0,13,0,0,0,0,0,0,0,18,0,0,0,9,4,0,0,8,0,9,7,0,0,0,0,0,0,8,6,0,0,0,0, +0,0,0,0,0,0,0,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,0,0,9,7,0,0,0,6,0,0,14,0,0,0,0, +0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,0,11,0,0,0,0,0,0,0,0,0,0,0,0,0,8,0,0,7,10,4, +0,6,0,0,0,0,0,0,8,0,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,9,6,0,0,0,0,0,0, +0,0,11,6,12,7,0,0,0,0,0,0,0,6,0,5,0,0,0,0,0,0,9,6,11,6,0,0,0,0,9,5,0,0,0,0,0,0, +0,6,8,5,0,0,0,0,8,0,10,0,0,0,0,0,9,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,9, +5,10,7,0,0,0,5,8,7,0,0,0,0,0,0,0,0,0,0,0,6,0,0,0,6,0,0,0,0,0,4,8,7,0,0,0,6,0,0, +0,0,0,0,0,0,0,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8,7,0,6,0,0,0,0,0,0,0,0,0,0,0,0,22, +0,0,0,0,0,0,0,0,0,0,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,0,0,0,0,0,5,0,0,0,0,0,0,0, +0,0,0,0,0,17,0,0,6,0,6,12,4,19,6,0,0,0,0,16,0,0,0,0,7,15,7,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,0,0,7,0,0,0,0,0,4,10,4,0,0,8,7,0,7,0,0,9, +4,0,6,0,0,0,4,0,5,0,0,0,7,0,0,0,0,0,0,0,4,0,0,0,0,0,0,0,7,10,0,0,0,0,0,11,7,0,0, +0,0,12,6,0,0,0,0,0,0,0,6,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8, +0,0,0,0,0,0,0,0,0,10,4,0,0,0,0,11,0,0,0,0,0,0,0,0,0,0,4,0,0,0,0,0,0,0,0,8,7,0,0, +0,0,0,0,0,6,0,0,0,4,0,0,11,4,0,0,12,7,0,0,0,0,9,0,0,6,0,0,0,0,0,0,0,0,0,5,0,0,0, +4,0,0,0,0,14,0,0,0,0,0,0,0,0,0,0,5,0,0,0,0,0,6,0,0,0,0,0,0,9,4,0,6,0,0,0,0,0,4, +0,0,11,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,6,0,0,0,5,0,0,0,0,0,0,0,0,0,7,9,6,0,7,0, +0,0,0,0,0,0,6,0,0,0,0,8,6,0,0,0,0,10,6,11,0,0,0,0,0,0,0,0,0,0,7,0,0,0,0,0,0,0,5, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,0,5,0,4,8,0,0,0,0,0,9,7,0,0,0,0,0,0, +13,5,0,0,0,0,8,0,0,0,0,0,0,0,0,5,0,0,0,0,0,0,0,0,8,5,0,0,11,7,0,0,0,0,0,0,8,6,0, +0,0,0,0,7,0,4,0,0,0,0,0,0,0,5,0,6,0,5,0,0,0,0,0,0,0,0,0,0,0,0,10,4,9,0,0,0,0,0, +0,4,0,0,0,0,10,5,10,7,0,0,0,0,0,0,0,0,16,7,0,0,0,0,0,7,0,0,0,0,11,0,0,0,0,0,0,0, +0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,9,5,0,4,0,0,0,7,0,0,0,0,0,0,13,0,0, +0,0,0,0,0,0,0,0,7,0,4,0,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,13,7,0,7,0,4,16,0,0,0,0,6,8,7,9,7,0,0,0,0,8,6,0,0,0,0,0,0,0,0,0,0,0,0, +0,6,0,0,8,5,0,4,0,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,0,0,0,5,11,7,0,0,11, +0,0,0,0,0,9,5,0,4,0,0,0,0,9,7,8,6,0,0,0,0,0,0,10,0,0,0,0,0,0,5,0,0,0,0,0,0,0,0, +0,7,0,0,0,0,0,0,0,0,0,0,0,4,10,6,0,7,0,0,0,0,0,0,0,5,0,0,0,0,0,0,10,7,10,0,0,0, +0,0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,9,0,0,0,0,7,0,6,8,7,12,4,0,0,0,0,0,0,0,5,14, +0,0,0,0,0,0,4,0,0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0, +6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,0,4,0,0,20,4,0,0,0,7,0,6,0,0,0,0,0,0,0,0,8,0, +0,6,15,0,0,6,0,0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,12,0,0,0,9,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,14,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,5,0,0,0,0,0,0,8,6,0,0,18,0,0,0,10,0,0,0,0,0,0,0,0,6,0,0,0,6,0,0,9,6,0, +6,0,0,0,0,0,0,0,0,9,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,11,7,0,0,0,0,9,0,9,0,0,4, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,9,5,0,0,0,0,0,0,0,0,11,0,0,0,0,0,0,0,0,0,10,0,0,0,0,7,0,0,0,0,0,0,0,0,0,7,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,8,0,8,0,0,0,16,0,0,0,0,0,0,0, +0,0,0,6,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,6,0,0,0,0,8,0,0,0,11,0,0,0,0,0,0,0,0,0,0, +6,0,0,0,0,11,0,0,0,9,7,0,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,0,0,0,0,0,7,0,7,0,6, +0,0,0,0,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,5,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,6, +0,0,0,0,0,0,0,6,0,0,18,0,8,0,0,0,0,0,0,0,0,0,0,0,0,5,0,0,0,0,0,0,0,7,0,4,0,0,0, +0,0,0,0,0,0,0,8,0,0,0,0,0,16,0,0,0,0,0,16,0,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,18,0,0,0,0,0,0,0,0,0,9,7,0,6,0,0,0,0,0,0,0,0,0,0,0,0,0,7,0,0,0,0,0,6,0,4,0, +0,0,0,0,0,0,0,9,4,0,0,0,0,12,5,0,0,0,0,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,0,12,5,0,0,0,0,0,0,0,5,0,0,10,6,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8,0,0,0,0,0,0,0,0,0,9,0,0,0,11,0,0,6,0,6,0,0, +0,7,0,0,0,0,0,0,8,0,0,0,0,6,0,0,0,0,0,0,19,0,0,0,12,0,9,0,0,0,0,0,10,7,0,0,0,0, +0,0,0,0,0,0,0,4,0,0,0,0,0,0,0,0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,9,0,0,0,16,7,12, +0,0,6,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,0,12,6,0,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,10,5,0,0,0,0,0,0,0,4,0,0,0,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,9,0,0,0,0,7,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,10,4,0,0,0,0,0,0,0,4,0,0,9,0,0,0,8,0,12,4,0,0,0,0, +0,4,0,0,0,0,0,0,0,0,0,0,8,0,0,0,0,0,0,0,8,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,9,0,0,0,0,0,0,0,12,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,11,0,0,5,0, +0,0,0,0,0,13,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,17,0,0,0,0,0,0,0,8,6,0,6,0,0,0,0,0,0, +0,4,0,0,0,0,0,6,0,0,9,0,0,0,0,0,0,6,0,0,0,0,0,0,11,0,0,0,0,0,0,0,10,6,0,0,0,0,8, +6,0,0,0,0,0,0,0,0,0,0,9,0,0,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,7,0,0,0,0,0,7,0,6, +10,7,0,0,10,5,11,6,0,0,0,0,0,7,16,0,0,0,0,6,0,0,0,0,0,0,10,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,5,0,0,0,7,9,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,9,6,0,0,0, +0,0,0,0,0,8,7,0,0,0,0,11,6,0,0,0,0,0,0,0,0,0,6,0,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +8,7,0,0,0,0,0,0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,0,0,0,0,0,0,0,12,7,0,7,0,0,0, +0,0,0,0,6,0,0,0,0,9,0,0,0,23,0,0,0,0,0,10,5,0,0,0,0,0,0,0,0,0,4,0,0,11,7,10,0,0, +0,0,0,0,0,0,0,0,0,0,6,0,0,8,7,0,7,0,0,8,7,8,0,0,0,0,0,0,0,0,0,0,0,14,5,0,0,0,0, +0,0,0,0,18,6,8,7,0,0,0,0,0,0,0,4,0,0,0,0,0,0,11,0,0,0,9,7,12,6,0,0,0,0,0,0,0,0, +0,0,12,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,9,6,0,0,0,7,11,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,6,8,7,0,0,0,6,10,0,0,0,9,0,0,0,0,0,0,0,0,0,8,6,0,0,0,0,0,6, +10,7,0,0,0,7,0,0,8,4,0,0,0,0,0,0,0,0,0,0,0,4,0,0,0,0,0,0,0,0,0,0,19,0,0,0,0,0,0, +0,0,0,8,7,8,6,0,0,11,7,10,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,9,4,8,7,0,0,0,0,0,0,0,0, +0,5,0,0,13,0,0,0,0,5,0,0,9,7,0,0,0,0,0,0,0,4,0,0,11,0,0,7,0,0,0,0,0,0,0,0,0,6,0, +0,0,0,0,0,12,7,19,0,8,6,0,0,0,0,0,6,0,0,0,0,0,0,0,0,10,6,8,0,0,0,0,0,0,0,0,0,0, +6,0,0,0,0,0,0,0,0,0,0,10,0,0,0,0,0,0,0,0,0,0,6,0,0,0,0,0,7,0,0,12,0,0,0,0,6,9,6, +14,0,0,0,0,0,0,6,0,5,0,0,8,7,0,0,0,6,0,4,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,4,0,6,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,0,0,0,0,0,0,0,5,0, +7,0,0,10,0,9,7,0,6,0,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,12,6,0,0,0,0,0,5,0,6,0,0,0,0, +0,0,0,0,0,0,0,6,0,0,0,0,9,7,0,0,0,0,0,0,11,6,0,0,0,0,0,0,0,0,0,0,11,7,0,0,13,7, +0,0,0,0,0,0,0,0,12,0,0,4,0,0,0,0,0,0,0,0,0,4,0,0,0,0,0,0,0,6,11,5,0,5,13,0,8,0, +0,0,0,6,0,0,0,0,0,0,11,0,0,0,0,0,8,7,0,0,0,0,0,0,0,0,0,0,11,0,0,0,0,0,0,0,11,5, +9,6,0,0,0,4,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8,6,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,10,0,0,0,8,5,0,0,9,0,0,0,8,7,9,0,0,0,0,0,0,0,0,7,0,6,0,0,0,0,0,0,0,0,0, +0,11,0,13,6,0,0,9,0,0,0,0,0,0,0,0,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,0,0,0,0,0,0, +0,0,0,0,0,5,21,6,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,24,5,0,0,0,0,0,0,0,0,10,0,8,0, +0,6,0,0,0,4,0,0,9,0,0,0,0,0,0,0,0,0,0,4,0,0,8,6,0,6,0,7,10,0,8,4,0,4,0,0,0,0,0, +5,0,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,0,0,0,0,0,0,0,6,12,0,0,7,0,0,0,5,0,0, +0,0,0,0,0,0,0,6,0,0,8,6,0,0,0,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +15,7,0,0,0,0,0,0,0,0,0,0,0,0,0,5,0,0,0,0,0,0,0,0,0,6,0,0,24,7,0,0,0,0,0,0,0,0,0, +7,0,0,0,0,0,0,0,0,0,0,9,6,0,0,0,0,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,4,0,0,0,0,0,6,0, +0,0,0,0,0,0,0,0,0,0,0,0,6,0,6,0,4,12,0,0,7,0,0,0,0,0,5,0,0,0,0,0,0,0,0,15,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8,7,0,0,0,0,0,0,0,0,0,0,8,0,0,0, +0,0,0,0,0,0,0,0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,0,0,0,6,0,0,0,0,0,0,9,0,9,6, +0,0,0,0,0,7,0,0,0,0,0,0,0,0,0,0,8,6,0,0,0,0,0,0,0,0,0,0,8,4,0,7,0,0,0,0,0,0,0,0, +22,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,0,0,0,0,4,0,7,0,0,21,7,0,7,9,6,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,10,0,0,0,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,4,0,0,0,0,8,0,0,6, +0,0,0,0,0,0,0,0,0,0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,8,7,0,0,0,0,23,0,0,0,0,7,0,0,0, +4,0,0,0,0,0,0,0,0,9,4,11,7,0,5,0,0,0,0,11,0,0,4,20,0,0,0,0,0,0,0,0,0,0,0,11,5,0, +7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +21,0,0,0,0,0,0,7,0,0,0,0,0,0,0,5,0,0,0,0,0,6,0,0,0,0,11,6,0,0,0,0,0,0,0,0,9,6,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8,5,0,4,9,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,9,0,0,0,0, +0,0,0,10,0,0,0,0,0,0,0,0,0,0,7,0,0,0,0,0,0,0,0,0,0,8,7,0,0,11,7,0,0,0,0,0,0,0,4, +0,4,0,0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,10,6,0,0,0,5,0,0,0,0,0,0,0,0,0,0,8,7,0, +0,0,0,0,0,0,0,0,6,0,0,21,6,0,0,0,0,0,6,0,0,0,0,0,4,0,0,0,0,0,0,0,0,0,0,14,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,9,6,0,0,8,0,0,7,0,0,0,0,0,0,0,0,0,0,10,0,0,0,0,0,0,0,0, +0,0,0,8,7,0,0,11,0,0,0,8,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,10,5,0,0,0,7,13,7,10,4,0, +0,0,6,0,0,0,0,0,0,0,0,0,5,10,0,0,0,0,0,0,5,0,0,0,7,0,0,0,0,0,0,8,4,0,0,0,0,0,6, +0,0,0,0,0,0,0,0,0,0,12,7,0,6,0,0,10,0,0,0,9,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,6,0, +0,0,0,0,7,0,0,8,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,0,10,5,0,6,0,0,0,0,0,4,0,0,0,0, +0,0,0,0,0,4,0,0,0,0,9,0,11,4,0,0,0,6,0,0,0,5,12,7,0,5,0,0,0,0,0,4,0,0,0,7,0,0,0, +0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,4,13,6,10,0,0,0,17,0,0,4,0,0,0,0,0,6,0,4,0,5,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,0,0,0,0,11,7,0,0,0,7,0,0,0,6,0,0,0,0,0,0, +0,6,0,4,0,0,0,0,8,0,0,0,0,5,0,0,0,0,0,4,0,0,0,0,0,0,0,0,9,0,0,0,0,0,0,0,9,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,9,5,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,0,12,0,0, +0,0,7,0,0,0,0,0,0,0,0,0,0,0,7,0,0,16,4,0,0,11,0,8,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +8,7,0,4,0,0,0,0,0,0,0,4,0,0,0,0,0,0,8,6,0,0,8,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,10, +7,0,0,0,0,0,0,9,0,0,0,0,0,0,0,12,5,10,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,10,5,0, +5,18,7,0,0,14,0,0,0,0,0,0,0,9,4,0,7,0,0,0,0,0,0,0,5,0,0,0,6,0,0,0,6,0,0,0,0,0,0, +8,0,0,0,10,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,10,5,0,0,0,7,0,0,0,0,0,0,11,0,0,0, +10,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,14,0,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +11,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,14,6,0,0,0,0,11,4,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,9,0,0,0,0,0,0,0,0,0,0,0,10,7,0,6,0,0,9,0,9,5,0,0,0,0,0, +0,0,0,10,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8,6,0,0,8,5,0,0,0,0,0,0,0,0,0,0,11,4,0,6, +0,6,0,0,0,0,0,0,0,0,0,0,0,0,11,0,0,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,12,4,0,6,8,6,0,0,0,0,0,0,0,0,0,0,8,0,0,5,0,0,0,0,0,0,0,7,0,0,13,0,0,0,0,0,0,0, +0,0,0,0,0,0,9,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,9,0,0,0,0,0,0,0,0,0,12,7,0,6,0,0,0, +0,0,0,0,0,0,0,0,0,13,4,0,7,0,0,0,7,0,7,0,0,0,0,0,0,0,0,10,4,0,0,0,0,0,0,0,0,0,0, +9,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,0,0,0,0,10,6,21,5,0,0,0,0,8,0,0,0,0,4,0, +7,0,0,0,0,0,0,11,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,0,0,0,4,0,0,0,0,0,0, +0,7,9,6,11,0,0,0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,6,0,7,10,0,0,0,0,0,0,6,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,5,0,0,0,0,0,0,0,0,19,0,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,18,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,7,0,0,0,0,0,0,9,4,10,4,0,7,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,9,7,9,7,10,4,0,7,0,0,0,0,0,0,0,6,12,0, +0,0,0,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,0,0,0, +0,14,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,0,8,0, +0,0,0,0,0,5,0,0,8,7,0,0,0,7,0,0,0,0,0,4,0,0,0,0,0,0,0,0,0,0,11,0,0,0,0,0,0,0,0, +0,0,0,0,4,0,0,8,0,0,6,0,0,0,7,0,0,0,0,10,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,10,6,0,0,0,6,0,6,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,11,0,0,0,0,0,0,0,0,0,0,0,0,7,9,7,0,0,0,4,8,0,0,0,0,6,11,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,10,0,0,0,0,0,0,0,13,4,0,0, +12,6,0,6,0,0,0,0,8,7,0,7,0,0,0,0,0,6,0,0,0,0,0,0,12,6,0,4,0,0,0,0,0,0,0,0,0,0,9, +7,22,0,0,0,0,4,0,0,0,0,0,6,0,0,0,4,0,0,9,0,0,6,0,0,24,7,0,7,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,10,6,0,5,0,0,0,0,0,0,0,7,0,0,8,0,0,0,0,0,0,0,10,5,0,0,0,0,0,0,0,0,0,7,0, +7,0,0,0,0,0,0,13,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,18,0, +0,0,0,0,0,7,12,0,9,4,0,0,0,0,0,0,0,0,0,4,0,0,0,0,8,0,0,0,0,0,0,0,0,4,0,0,0,7,0, +0,0,0,8,7,0,0,0,0,0,0,0,0,0,4,18,0,0,0,0,0,10,0,0,5,0,0,11,0,0,0,0,0,0,5,0,6,0, +0,0,6,0,0,0,0,0,0,0,0,0,5,0,0,0,0,0,0,0,0,8,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,4,0,0,0,0,0,0,0,0,0,7,0,0,0,0,0,6,0,0,0,0,0,0,8,0,0,0,0,0,0,0,0,0,0, +4,0,0,0,0,0,0,10,0,0,0,0,0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,0, +0,0,0,5,8,0,0,0,0,0,0,0,8,6,0,0,0,0,0,0,0,0,20,7,0,0,0,0,0,0,0,0,0,0,0,4,9,0,12, +6,8,0,14,7,0,5,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,17,0,0,0,0,0,10,0,0, +0,0,0,0,0,0,0,0,0,0,6,0,6,0,0,0,0,0,0,0,0,12,0,0,0,0,0,0,0,9,6,0,7,12,0,0,0,0,4, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8,7, +0,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,5,0,0,0,4,0,0,9,0, +12,6,0,5,0,0,0,6,0,4,0,6,0,0,0,0,0,0,0,0,10,7,0,0,0,0,0,0,8,0,0,0,0,4,0,0,0,0, +10,0,0,0,0,0,0,0,8,6,0,5,0,0,0,0,0,0,0,0,0,0,0,0,0,5,0,5,0,0,0,0,0,0,0,0,0,0,0, +6,0,0,12,6,20,5,0,0,0,0,0,0,0,0,0,0,0,0,9,5,0,5,0,0,0,6,13,7,0,0,0,0,15,6,0,0,0, +6,0,0,13,7,0,0,0,0,0,0,9,0,0,0,0,0,0,0,0,0,0,5,0,7,0,0,0,0,0,4,0,0,0,0,0,0,0,0, +10,6,0,0,0,0,0,6,0,0,0,0,9,0,0,0,0,0,19,6,0,0,0,0,0,0,0,0,0,0,13,0,11,0,0,0,0,0, +0,0,0,0,8,0,0,0,0,0,0,0,0,0,0,0,0,0,10,6,0,0,0,0,0,0,0,0,10,0,0,6,0,0,0,0,8,0,0, +0,9,0,15,4,0,6,0,0,0,0,0,6,12,0,0,0,0,0,0,0,14,7,0,0,0,0,0,0,0,0,0,0,0,5,0,0,0, +0,0,0,0,0,8,7,0,0,0,0,0,6,10,0,0,0,0,0,0,0,0,7,8,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,9,7,10,5,0,0,0,0,8,0,0,0,0,4,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,6,12,0,0,0,10,7,0,5,0,6,0,0,0,0,8,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,6,0,4,0,0,0,0,0,7,0,0,0,0,0,0,0,4,9,6,0,0,0,7,0,0,0,0,0,0,0,0,8,6,0,0, +0,0,0,0,0,4,12,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,0,0,0,0,0,0,0,7,0, +0,0,0,0,0,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,12,6,0,6,9,4,0,0,8,4,0,6, +0,0,0,0,0,4,0,0,0,0,0,0,0,6,0,0,9,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,8,0,0,6,13,4,0,5,8,0,0,0,0,0,0,0,8,0,0,0,10,5,0,0,9,0,0,0,0,0,0,6,0,0, +24,0,0,0,0,0,0,0,8,0,0,7,0,0,12,0,8,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,9,7,0, +6,8,0,10,0,9,7,0,0,0,5,0,0,0,0,0,0,0,4,8,5,0,0,0,0,8,7,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,19,0,0,4,0,0,0,0,0,6,0,0,0,0,0,5,0,0,0,0,8,0,0, +0,0,0,8,6,0,0,0,0,0,0,0,0,0,0,8,6,0,0,0,0,10,4,0,0,0,0,0,0,0,6,0,0,0,4,20,0,0,7, +10,6,0,0,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,10,7,0,0,0,0,9,6,0,0,0,0,0,0,0,4, +12,0,0,0,0,0,0,0,0,4,0,0,0,0,0,0,12,0,0,0,0,0,0,0,0,0,11,0,0,0,0,0,9,4,0,5,0,0, +0,0,0,0,0,6,0,6,0,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,6,9,0,0,0,0,7,0,0,0,0,0,6,0,5,0,0,0,0,0,0,0,0,9,0,0,0, +0,6,0,0,0,0,0,0,0,0,0,0,11,0,0,0,0,0,0,0,0,0,0,0,0,0,17,7,0,0,13,6,14,6,0,0,0,0, +8,0,0,0,0,0,0,7,12,7,8,7,0,0,0,0,0,0,0,0,0,0,0,0,8,0,0,0,0,0,0,4,0,0,0,0,0,4,0, +0,0,0,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,0,0,0,12,4,0,0,10,7,0,0,0, +0,0,0,10,0,0,6,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,12,0,0,6, +0,0,0,0,0,0,0,0,8,7,12,0,0,0,0,0,0,6,0,6,0,4,0,0,18,6,0,0,0,6,0,0,0,0,0,6,10,6, +0,0,0,0,0,0,8,7,14,0,0,0,0,0,0,6,0,0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,19, +0,0,0,8,0,0,0,0,0,0,0,0,7,0,0,0,0,0,0,0,0,0,0,8,7,0,0,10,5,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,0,0, +0,0,9,4,8,0,0,0,0,0,0,4,0,0,9,0,0,0,0,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,4,0,0,0,0, +0,6,0,0,9,7,0,0,0,0,0,5,0,0,0,0,8,7,0,0,14,0,0,0,0,6,0,0,0,0,0,0,9,6,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,10,0,0,0,0,5,0,7,0,0,0,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0, +0,0,0,6,0,0,0,6,0,4,0,0,0,0,0,4,0,0,0,0,12,0,0,7,0,0,0,0,0,0,0,0,0,6,0,0,0,0,0, +0,12,0,16,6,0,0,0,0,0,0,11,7,0,4,8,7,0,0,0,0,0,6,0,0,0,0,16,0,0,0,0,6,0,0,0,0,0, +0,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,0,0,4,10,7,0,0,0,0,0,0,12,7,0,0,0,0,0,0,0,0,0,0, +0,0,10,0,0,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,13,4,0,0,10,0,0,0,0,0,0,0,0,0,19,0,0,0, +0,0,0,0,0,0,0,0,0,0,8,6,22,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,7,0,0,0,0,0,0,0, +5,0,0,0,0,0,5,0,0,0,0,0,5,0,0,0,6,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +4,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,7,0,0,18,0,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,14,7,0,0,11,5,0,0,0,5,0,0,0,0,12,5,0,0,0,0,0,0,0,0,0,0,24,6,0,0, +0,7,0,4,0,0,0,0,8,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,0,0,0,0,7,0,4,0,0,0,0,8,7,0,0, +9,6,0,0,14,5,0,0,0,6,0,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,12,6,0,0,0,0,0,0,0,6,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,7,0,0,0,7,0,0,0,5,0,0, +0,0,12,7,0,0,0,0,10,0,0,0,0,0,0,0,0,0,0,6,0,0,0,0,0,5,0,0,0,0,0,0,0,0,0,6,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,9,0,0,0,0,0,0,6,0,0,13,7,0,0,0,0,0,0,14,0,11,4,0, +0,0,4,0,0,0,0,14,5,0,0,0,0,0,5,11,5,0,0,0,0,22,5,0,0,0,0,0,7,0,0,0,0,0,4,0,0,0, +4,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,10,6,0,0,17,0,10,0,0,0,8,0,0,0,19, +5,18,7,0,0,0,0,0,0,0,0,0,0,10,0,0,0,0,0,0,0,0,0,0,0,10,6,0,6,0,0,0,0,10,4,0,4,0, +0,0,0,0,0,14,7,0,5,0,0,0,0,0,6,0,0,0,0,0,0,0,0,8,0,9,6,12,0,0,6,0,0,0,0,0,0,0,0, +12,0,10,6,0,0,0,0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,0,4,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,5,13,0,9,7,0,0,0,0,0,0,0,0,0,0,0,7,9,7,0,0,8,0,0,0,0,0, +22,0,0,0,0,0,0,0,23,6,14,0,0,0,0,0,0,7,0,0,0,0,11,0,0,0,0,7,0,0,0,0,0,0,0,0,0,0, +0,0,10,0,0,6,0,0,0,0,0,0,0,0,0,6,0,0,8,5,0,0,0,0,0,0,0,0,0,7,11,6,21,0,0,0,0,0, +0,0,0,0,0,5,0,0,0,0,0,0,0,0,0,0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,0,0, +0,0,0,0,0,0,0,4,9,7,0,0,0,0,0,0,12,0,0,0,0,7,0,0,0,0,0,0,0,0,10,4,0,0,0,0,0,0,9, +0,0,0,20,0,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,6,0,0,11,7,0,0,0,0,0,0,0,6,15,0,0, +0,0,0,0,0,0,0,0,0,0,0,12,4,0,5,0,0,0,0,0,0,11,7,17,6,0,0,0,0,0,0,15,6,0,7,0,0,0, +0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,14,0,0,0,0,0,0,0,0,0,0,7,0,0,0,0,0,0,0,6,0,5, +0,0,11,0,11,7,9,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,0,0,0,0,0,0,0,0,0, +17,0,0,0,0,6,0,0,0,5,0,0,0,0,0,0,8,7,9,6,0,0,14,0,0,0,0,0,0,0,0,0,16,0,0,0,0,0, +8,7,0,4,0,0,0,0,0,0,0,6,0,5,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,0,0,0,0,0, +0,0,0,5,0,4,0,0,8,7,0,6,12,5,0,7,18,7,0,0,8,5,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,0, +10,0,11,0,0,0,0,0,0,0,0,0,0,0,9,0,0,4,0,6,0,7,0,0,0,0,0,6,0,0,0,6,0,0,0,0,0,0,0, +7,0,0,0,0,8,0,0,0,15,0,0,0,10,0,0,0,0,0,0,0,0,0,0,0,0,0,10,6,0,0,0,0,0,0,0,0,0, +0,0,6,0,0,0,0,23,0,0,0,10,7,0,0,0,0,0,0,0,0,0,0,8,0,0,0,0,5,0,0,0,0,0,0,8,6,0,0, +0,0,0,0,12,7,9,7,0,0,10,6,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,0,9,0,8,7,0,0,0, +6,0,6,0,4,0,5,0,0,0,0,0,5,8,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,7,10,5,0,0,11,6,0,0,0,0,0,0,0,6,0,6,0,0,0,0,0,0,0,0,0,0,14,0,0,0,0,4,9,7,0, +0,0,0,11,7,0,0,0,0,0,5,0,0,0,7,0,0,0,0,23,6,11,4,0,0,0,0,0,0,9,0,0,0,10,6,0,0,0, +0,9,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,0,0,0,0,0,6,0,0,10,6,0,0,0,7,0,0, +0,0,0,0,0,0,0,0,20,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,13, +6,11,7,0,0,0,0,0,0,0,0,0,0,0,0,10,5,0,0,0,6,0,0,0,5,0,6,0,6,0,0,0,0,0,0,0,0,0,0, +0,6,0,0,0,0,8,7,0,5,0,0,0,0,0,6,0,0,0,0,0,0,0,4,10,0,8,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,10,6,0,0,0,0,0,0,10,0,0,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,6,0,0, +0,0,0,0,0,0,10,0,0,0,9,0,0,0,0,0,0,0,0,0,0,0,0,0,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,11,6,0,4,0,0,14,5,0,7,0,0,0,0,0,6,16,0,0,0,0,0,0,0,10,0,0,7,15,0,0,0,11,7,0,0, +0,0,0,0,0,0,0,0,8,7,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,18,5,0,0,0, +0,8,0,0,6,0,0,0,0,0,0,9,5,0,0,23,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,16,6,0, +0,0,0,0,0,0,7,0,0,0,0,15,7,0,0,0,0,8,0,0,0,14,0,0,0,0,0,0,0,16,7,0,0,0,0,0,7,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,12,6,11,7, +9,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,13, +7,0,0,0,0,0,0,0,0,0,0,9,0,0,0,0,0,12,0,10,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,10,0,8,0,0,5,8,7,10,6,0,0,0,7,0,0,0,0,12,6, +0,0,9,0,0,0,12,0,0,0,0,5,0,0,0,0,0,0,0,0,0,0,0,4,10,0,0,0,10,5,0,0,0,0,0,0,9,6, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,18,6,0,0,9,5,0,4,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,0,0,0,0,0,0,0,0,9,0,0,5,0,0,8,7,8, +6,0,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,10,6,10,0,9,4,0,0,0,0,0,0,0,6, +11,0,0,0,0,0,0,0,0,0,0,0,8,0,0,6,0,6,0,0,0,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,8,7,9,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,0,0,0, +0,0,0,10,0,0,0,8,7,0,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,0,0,0,0,0,0, +0,0,8,4,0,5,0,0,0,0,0,0,0,7,0,0,0,6,0,0,0,0,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,5,0,0,0,0,0,0,0,0,8,7,0,0,0,0,0,0,0,0,22,0,0,0,0,0,0,0,8,5,0,0,0, +0,0,0,0,7,0,0,0,6,0,0,0,6,0,6,0,0,0,0,0,0,0,0,0,0,0,7,0,0,0,5,0,6,0,7,0,0,0,0, +20,0,0,0,0,0,0,0,0,0,0,7,9,0,0,0,0,0,0,6,0,6,0,7,0,0,0,7,0,0,0,0,0,0,0,4,0,0,0, +0,0,0,14,7,0,0,0,5,0,0,22,4,10,0,0,0,0,0,0,4,8,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,11,5,13,0,0,0,0,0,0,0,0,0,8,0,0,7,0,0,0,0,0,4,0,0,0,4,0,0,0,0,0,0,10,7,0, +0,0,0,0,0,0,6,0,0,0,0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,11,7,0,7,14,6,0,0,0,0,9,5, +0,0,0,0,0,6,0,0,0,5,10,0,8,6,0,0,0,0,0,0,0,0,9,7,0,0,0,0,0,0,0,6,0,0,8,4,0,6,0, +0,0,5,0,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8,7, +14,0,0,5,0,0,18,0,8,4,0,6,0,0,20,0,13,0,0,0,0,7,0,4,0,0,0,0,0,4,8,4,0,0,0,0,0,6, +0,0,0,0,0,4,0,0,0,4,0,0,0,0,0,4,0,0,0,0,0,0,0,0,14,0,0,0,0,0,9,7,0,0,9,0,0,0,0, +0,0,0,0,0,0,4,0,0,0,0,0,0,0,0,0,0,20,0,14,0,0,4,0,6,8,5,0,0,0,0,0,7,0,0,0,0,0,0, +0,0,0,0,8,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,10,4,12,7,0,6,0,0,9,7,10,5, +0,0,8,6,0,4,0,0,0,0,0,0,0,0,0,0,0,0,17,0,0,0,0,0,0,0,18,0,0,0,14,7,0,0,0,0,0,4, +0,0,0,0,0,0,17,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,13,4,0,0,0,0,0,0,0,0,0,0,0,0,0,7,0, +0,0,0,0,0,8,6,0,0,0,0,0,0,0,0,8,5,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,5,0,7,0,0,0,0,0, +7,0,0,0,0,0,0,0,0,0,7,0,6,0,0,0,0,0,0,0,0,8,5,0,0,0,0,0,0,0,7,0,0,0,0,0,0,0,5,0, +0,0,0,0,0,0,0,0,0,0,0,0,7,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,0,23,0,0,7,0,0,0,0,0,0, +0,0,0,0,0,0,0,4,0,0,0,0,0,0,12,7,8,4,0,0,0,0,0,0,0,0,0,6,0,0,9,5,0,0,0,7,0,0,0, +0,0,0,0,0,0,4,10,0,0,7,0,0,0,5,0,0,0,0,0,0,0,0,0,4,0,0,0,0,0,0,0,0,0,5,0,0,18,7, +0,0,8,0,0,5,0,0,10,0,0,0,0,0,0,6,0,0,0,0,0,5,0,7,0,0,0,0,0,0,0,0,0,0,16,0,0,0,0, +6,8,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,0,6,0,0,10,0,0,5,10,4,0,0,12,0,0,0,0, +6,22,4,0,0,0,0,0,0,0,0,0,0,0,0,0,6,0,5,0,0,0,0,0,7,0,5,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,12,0,0,0,0,0,0,6,0,7,0,0,0,6,0,6,8,5,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,8,5,0,0,0,0,0,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,5,0,0,0,7,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,0,0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0, +0,0,0,0,0,0,5,0,0,0,0,0,0,0,0,16,6,0,0,0,6,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,12,7,0,0,0,0,9,0,0,0,0,6,0,0,11,0,0,0,0,0,13,0,9,6,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,0,0,0,0,0,0,0,0,0,0,0,4,0,0,10,7,0,0,0,7,0,6,0, +0,0,0,0,0,0,0,0,0,8,7,0,0,0,0,11,0,15,0,22,7,0,4,0,6,0,0,0,0,0,7,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,4,0,7,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,0, +18,0,0,0,0,0,0,0,0,0,14,0,0,4,0,0,0,0,8,7,9,0,0,0,0,0,9,0,0,0,14,0,0,0,0,0,0,0, +0,0,11,7,0,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,0,7,0,0,0,6,0,6,0,0,0,0,8,0,0,0,0, +0,11,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,9,0,0,0,0,0,0,0,9,4,0,0,0,0,0,4,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,8,7,0,0,0,0,0,0,0,0,0,0,0,5,0,0,0,0,0,0, +0,0,0,0,0,0,8,6,0,0,9,5,0,0,0,0,0,0,0,0,14,0,0,0,0,0,0,6,0,0,0,0,0,0,0,6,0,5,0, +0,10,6,9,0,0,0,0,6,0,0,0,0,0,6,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0, +11,7,12,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,4,0,5,0,0,0,0,0,0,0,0,0,7,0,0,0,0,0, +0,0,0,0,6,0,0,0,0,0,0,0,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8,0,0,0,0,0,0,5,0,0,10,6, +0,0,0,4,0,7,13,0,0,4,0,0,11,4,0,6,0,0,0,0,0,6,8,7,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,5,0,0,0,0,0,0,8,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,5,0,0,0,0,12,6,0,0,0,0, +11,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,11,5,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8, +7,0,0,0,0,0,0,0,0,0,7,0,0,0,0,0,0,0,4,0,0,0,6,17,0,9,0,10,6,0,6,12,0,0,4,0,0,0, +0,0,0,0,0,0,0,8,5,12,7,0,4,0,0,0,0,0,0,0,0,0,0,11,0,9,0,10,6,11,5,0,7,0,0,8,0,0, +7,0,4,0,0,0,7,0,0,0,0,0,0,8,6,0,0,0,6,0,0,0,0,0,0,0,0,9,0,0,0,0,0,0,0,0,0,0,6,0, +0,0,0,0,0,0,5,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,0,0,0,11,0,0,0,0,6,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,10,0,10,0,0,0,0,0,8,6,0,0,0,0,0,6,12,0,0,0,0,0, +0,0,0,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8,0,0,0,0,0,0,6,0,0,16,0,11,5,0,0,0,0,0, +0,0,0,0,0,10,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,9,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,7,0,0,0,0,0,6,0,7,0,0,0,0,0,0,0,0,0,0,0,0,8,4,0,0,0,0,0,6,10, +7,0,0,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,7,0,6,0,0,0,0,0,0,9,5,0,0,0,0,8,0,9,0,0, +0,0,0,0,0,0,7,10,0,13,0,0,6,0,0,0,0,0,0,0,0,0,6,9,4,0,0,0,0,0,0,10,0,0,0,0,0,10, +0,0,0,0,0,0,0,10,6,11,0,0,0,0,0,9,0,0,0,0,0,0,4,0,0,0,0,0,0,10,5,0,0,0,0,0,6,0, +0,0,0,0,0,18,4,0,7,0,0,0,0,0,0,24,0,8,6,0,7,0,0,0,0,15,0,0,0,0,0,0,0,0,0,0,0,0, +0,8,5,0,0,0,0,10,7,0,6,0,0,0,0,0,0,0,0,8,5,10,0,0,0,0,0,0,0,0,0,0,0,0,0,11,0,0, +6,0,0,8,7,0,0,0,0,0,0,0,0,0,0,12,6,0,0,0,0,0,0,0,4,0,5,15,0,0,0,0,7,0,7,0,0,0,0, +0,0,0,0,0,6,10,5,0,0,0,6,0,0,8,7,0,0,0,0,0,0,0,0,0,0,0,7,0,0,12,0,0,0,0,0,0,0,0, +0,0,5,0,0,0,0,0,0,14,4,18,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,0,0,0,0,11,0,10,4,9,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,0,0,0,6,0,0,0,0,0,4,0,0,0,0,0,7,0,0,0, +0,0,0,0,0,0,0,0,7,13,7,0,0,0,0,0,0,0,5,0,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8,7,0,0, +0,0,0,0,0,0,0,5,0,0,0,0,0,6,0,0,0,0,0,0,11,0,0,0,0,0,0,0,0,0,8,0,10,6,0,4,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,6,8,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,0,0,0,6,0, +0,0,0,0,0,0,0,10,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,0,9,7,0,0,0,0,0,6, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,0,0,0,0,0,0,0,0,0,10,6,0,0,0,0,0,0,0,6,0,0,0, +0,0,0,0,5,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,6,0,0,0,5,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8,6,11,0,0,0,0,6,0,0,0,0,0,0,0,6, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,22,0,0, +6,0,0,0,0,0,0,0,6,10,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,14,0,0,0,0,0, +0,0,0,0,0,0,0,6,0,6,0,0,0,5,0,0,0,0,0,0,0,5,0,0,10,0,11,5,0,0,0,0,0,0,14,7,9,7, +0,6,0,0,0,0,0,4,0,0,0,0,0,0,11,7,0,6,0,0,0,0,0,0,9,7,0,4,0,0,0,7,0,0,0,0,0,5,0, +0,0,0,0,5,0,0,0,7,0,0,0,0,0,5,0,0,0,0,17,5,0,0,8,0,0,0,0,6,9,4,0,0,0,0,0,0,0,0, +8,7,11,7,9,0,0,0,0,0,0,0,0,0,8,7,0,0,0,0,0,0,0,0,0,0,0,6,9,5,0,0,8,6,0,0,0,5,0, +0,0,0,9,0,0,0,9,6,0,7,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,0,0,0,0,0,0,0,0, +0,0,0,0,4,0,0,0,0,10,0,0,0,0,0,0,0,0,4,0,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,4,0,0,0,5,0,0,0,0,0,7,0,0,0,0,0,7,13,5,0,0,0,7,0,0,0,0,0,7,9,6,11,7,0,7,0,0,0, +0,0,0,0,0,0,0,0,7,0,0,0,0,0,0,0,0,8,5,0,0,0,5,9,4,0,0,0,0,0,0,0,0,8,4,0,0,0,0, +24,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,0,0,0,0,7,0,0,0,0,0,0,0,0,0, +0,0,0,0,6,0,0,0,7,0,0,0,6,0,0,0,0,0,0,0,0,0,5,11,6,0,4,0,7,20,0,8,5,9,5,9,0,0,6, +0,0,0,0,0,0,0,0,0,0,0,7,23,5,0,0,8,4,0,0,10,0,0,6,0,5,0,0,0,0,0,0,0,0,0,0,0,7,0, +0,0,0,0,0,0,0,0,0,11,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,0,0,9,0,0,0, +10,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,0,8,0,0,0,0,0,0,0,0,0,0,0,0,7,0,0,0,0,0, +6,0,0,0,0,14,0,18,4,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,0,0,0,9,6,0,4,0,0,0,0,0,0,8,4, +11,0,0,0,11,0,0,0,0,0,0,0,0,0,0,0,8,4,0,0,0,0,0,0,0,0,12,0,10,7,0,0,10,0,0,0,0, +0,0,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,0,0,0,6,0,0,0,0,0,6,0,0,0,0,8, +6,10,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,0,0,0,4,0,6,0,4,0,0,0,0,0,5,0,0, +0,0,0,0,0,0,0,7,0,0,0,7,0,0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,17,7,11,0,0,0,0,0,0,0,0,0,0,4,12,6,0,0,0,5,0,0,0,6,0,0,0,0,0,0,0,0,0,0, +0,5,12,7,0,0,0,0,0,4,0,0,0,0,0,0,0,0,0,0,0,6,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +7,0,0,0,0,0,0,0,4,0,0,0,0,0,0,0,6,0,6,0,0,20,0,0,0,0,0,0,0,0,0,8,7,0,0,0,0,0,4, +0,0,0,5,0,0,0,0,12,0,0,0,0,0,0,0,0,0,0,0,10,0,0,0,0,6,0,4,13,0,0,7,0,0,0,0,0,0, +0,0,0,0,0,6,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,6,0,0,12,6,0,7,0,0,0,0,10,0,23,6,0,0, +0,4,0,0,0,0,0,6,8,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +10,0,9,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,0,0,0,0,0,0,0,11,0,9,7,0,0, +0,0,0,0,0,0,0,0,9,7,0,4,0,0,0,0,8,7,0,0,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4, +0,0,0,0,0,6,0,0,10,7,10,5,0,0,8,0,8,0,0,0,0,0,0,4,0,5,10,0,0,0,0,0,0,0,9,0,0,6, +0,0,0,0,0,0,0,0,0,0,0,7,0,0,0,0,0,0,11,7,0,0,0,0,0,0,0,0,9,4,0,0,0,0,0,6,0,0,8, +7,0,0,0,0,0,5,0,0,0,0,0,0,0,0,10,0,0,0,0,5,0,4,0,0,0,0,0,0,12,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,24,7,0,0,0,0,0,0,0,0,0,0,0,0,9,0,0,6,0,0,9,0,0,0,0,0,0,7,0,6,13,0,8, +0,0,0,0,0,0,0,0,0,9,7,0,0,0,0,0,0,0,6,0,0,0,0,8,5,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0, +4,0,0,0,0,0,4,0,0,0,0,0,0,0,6,8,0,0,0,0,6,8,0,0,0,0,0,0,0,0,0,0,0,0,0,14,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,4,0,4,0,0,0,5,0,7,0,0,10,0,10,7,0,0,12,5,0,0,9,0,0,0,10,0, +0,6,0,0,0,6,0,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,0,0,6,0,0,0,5,0,0,0,0,0,0, +12,0,0,0,0,0,8,5,13,6,0,0,0,0,0,0,9,4,0,0,0,0,8,0,0,0,0,0,8,7,0,0,0,0,0,0,0,0,0, +0,0,6,0,0,14,0,0,0,0,6,0,0,0,0,0,6,0,0,0,0,17,6,0,0,0,0,12,6,0,0,0,0,8,0,0,7,0, +7,0,4,9,0,0,6,0,0,0,6,0,0,0,0,0,0,8,7,0,0,0,0,0,0,11,0,0,4,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,18,7,0,4,0,0,0,0,0,0,0,0,0,0,8,0,0,0,0,0,0,0,0,6,0,0,0,0,0, +0,0,0,12,5,0,0,0,0,0,0,0,0,0,0,0,6,0,0,0,0,8,0,11,7,0,0,0,0,0,0,0,0,0,4,0,0,0,0, +11,0,0,0,0,0,0,0,21,0,0,6,10,0,0,0,0,0,9,0,10,0,0,0,0,0,11,0,0,0,0,6,0,0,0,0,0, +5,0,0,0,0,0,0,10,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8,0,0,0,0,4,0,0,23,7,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,0,0,0,0,0,0,0,0,9,7,0,0,0,7, +0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,6,0,0, +11,6,0,0,0,0,0,0,0,6,0,0,0,0,10,7,0,0,9,4,0,0,11,0,8,5,0,0,0,7,8,5,22,0,0,0,9,6, +0,0,0,0,0,0,0,6,10,4,0,0,0,0,0,7,9,4,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,6,0,4,0, +0,0,0,11,6,0,0,0,0,0,0,0,0,0,0,0,7,0,6,0,0,0,0,0,7,0,0,0,0,0,0,0,6,0,6,0,4,0,0, +0,0,0,0,0,7,0,7,0,4,13,0,0,0,0,0,8,0,0,0,0,7,0,0,0,0,0,0,11,6,0,7,0,0,0,0,9,0,0, +0,0,0,0,0,0,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,10,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,4,8,0,0,0,0,0,8,0,0,0,0,0,0,6,0,0,0,4,0,0,0,0,0,0,0,6,0,0,0,0,13,5,8,0,0, +0,0,0,0,0,14,0,0,6,0,0,0,0,0,0,0,0,0,7,0,0,17,6,0,0,0,0,13,4,0,0,9,6,0,0,10,5,0, +0,10,5,0,0,0,0,13,0,0,0,0,6,0,0,0,0,0,0,10,0,12,0,0,0,0,0,0,0,0,0,0,0,8,4,0,4,0, +0,0,4,0,0,0,0,0,4,0,0,12,0,0,5,9,4,0,0,0,0,0,0,0,0,0,5,8,5,0,0,0,7,0,0,0,0,8,7, +0,0,0,6,12,5,0,0,0,5,0,0,0,5,0,0,0,0,0,4,12,0,0,0,9,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,8,7,0,0,0,0,0,6,0,0,0,0,0,0,0,6,0,0,0,0,0, +0,9,6,0,0,0,0,0,0,0,0,0,4,0,0,0,6,0,0,0,4,11,0,0,0,0,0,0,0,0,0,0,7,0,0,0,0,0,0, +0,0,0,0,12,7,0,0,0,7,10,7,0,0,11,0,0,0,0,0,0,0,0,0,11,7,0,0,0,6,0,0,11,0,0,0,0, +0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,0,22,0,10,7,0,0,8,5,0,0,0,0,0,5,0,0,0,0,0,0, +0,0,0,0,9,6,8,7,0,6,0,0,0,0,0,5,0,0,0,0,0,0,8,7,0,0,0,0,9,7,0,0,0,6,0,0,8,7,0,0, +0,0,0,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,0,0,7,0,4,0,5,0,0,0,4,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,18,6,0,0,0,0,0,0,0,4,0,0,0,0,0,0,9, +6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,0,0,0,4,0,0,0,5,0,0,0,0,14,0,0,0, +9,0,0,0,0,0,0,0,0,0,9,7,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,12,0,0,0,0,0,12,7,0,0,0,5,0,0,0,0,0,0,0,0,0,0,8,0,0,0,0,0,10,7,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,8,7,0,0,0,0,0,6,0,0,0,0,0,0,9,6,0,0,0,0,0,6,0,0,0,0,0, +0,0,0,0,0,9,0,0,0,0,7,0,6,0,0,0,0,0,0,0,0,0,0,0,5,0,0,0,0,0,0,0,0,0,0,0,6,0,0,0, +0,0,0,0,0,0,0,0,0,0,4,0,0,0,0,0,0,0,0,0,6,0,7,12,6,0,0,0,0,0,5,0,0,0,0,0,0,0,0, +0,7,0,0,8,6,0,0,0,0,10,7,0,0,0,0,0,0,0,6,0,0,0,0,0,6,12,0,0,0,0,0,0,0,0,6,0,0,0, +0,0,6,0,0,0,6,0,0,0,0,0,6,16,0,0,0,0,0,0,0,0,0,9,0,17,0,14,7,8,0,0,0,0,0,0,6,0, +0,0,0,0,0,0,0,0,0,11,0,0,6,8,7,0,6,0,0,0,0,0,0,0,0,0,0,12,6,0,0,0,0,0,0,0,0,0,0, +9,0,0,0,0,7,0,0,0,0,11,5,0,4,9,6,8,0,0,0,0,0,0,0,0,0,10,0,11,7,0,0,0,0,0,0,0,0, +9,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,11, +0,0,0,12,0,0,0,0,0,10,5,0,4,0,0,0,0,0,7,10,6,11,6,0,0,0,0,0,0,0,0,0,0,0,0,17,0, +0,0,11,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,11,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,6,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,0,0,8,0,0,4,0,0,0,6,0,0,0, +0,0,0,8,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,9,6,0,0,14,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,4,0,0,0,0,9,6,0,0,0,4,0,0,0,0,0,4,10,7,0,7,0,0,0,0,0,0,0,6,0,0,0,0,0,6,0,0,0, +0,0,0,0,0,0,6,0,0,0,6,0,6,0,0,0,0,10,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,0,18,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,14,0,13,0,0,0,0,0,10,0,0,0,0,0,0,0,0,4, +0,0,0,6,0,0,0,0,0,4,8,0,0,0,11,7,0,0,0,4,0,0,0,0,0,7,0,0,8,5,0,0,16,0,0,0,13,6, +0,0,0,0,0,0,0,6,0,0,0,0,20,0,11,6,0,0,8,7,0,0,0,0,0,6,17,0,8,0,0,0,0,0,8,7,0,0, +9,0,0,0,0,0,0,0,0,0,0,0,0,0,14,0,0,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,9,0,0,0,0,0,0, +0,0,4,0,7,0,0,0,0,0,0,0,6,0,0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,0,0,0,0,8, +0,8,0,0,0,0,0,0,0,11,0,8,0,0,0,0,0,0,0,0,0,0,0,8,6,0,0,0,0,0,0,0,0,0,6,0,0,9,0, +0,0,0,0,8,0,0,0,0,0,18,0,0,0,0,0,0,4,9,0,0,0,0,0,8,5,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,9,6,0,0,0,0,0,0,0,0,0,0,13,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,8,7,0,0,0,0,0,0,0,0, +0,4,0,0,0,0,0,0,14,0,0,0,0,7,0,6,0,0,8,0,20,7,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,8,0,0,0,14,0,0,0,0,0,0,0,8,0,0,7,0,6,0,0,0,7,0,0,0,0,0,0,0,0, +0,0,0,4,12,0,0,0,0,0,0,0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,0,0,10,6,0, +5,16,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,0, +0,0,0,5,8,4,0,0,0,0,0,0,0,4,0,0,0,7,0,0,0,0,0,0,0,5,0,0,0,0,0,0,0,0,0,0,12,7,0, +0,0,0,13,6,0,0,0,7,0,0,8,0,0,0,8,0,0,0,0,0,0,0,0,0,0,5,0,0,0,7,0,0,0,0,0,0,11,5, +0,6,0,0,8,5,0,7,0,0,0,0,0,0,0,7,0,0,0,0,8,6,0,0,0,0,0,0,9,0,0,0,0,0,0,0,0,4,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +14,0,10,7,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,10,0,19,0,0,4,0,0,0,7, +0,0,11,5,11,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,16,0,10,5,18,0,0,7,9,6,0,5,0,0,0,0,0, +0,0,0,0,5,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,0,8,7,0,0,0,0,0,5,0,0,0,7,0,6,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,9,0,0,0,0,6,0,0,0,4,0,6,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,6,0,0,0,7,23,0,0,0,0,5,0,0,0,0,0,0,8,5,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,14,0,20,0,0,0,0,0,0,0,0,0,8,0,0,0,0,0, +11,0,0,0,0,7,0,0,0,0,15,0,0,0,0,0,10,0,0,0,0,0,0,0,0,0,9,6,0,0,0,0,0,7,0,0,0,0, +0,4,0,0,0,0,10,0,0,0,0,0,9,0,0,0,8,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,10,0,11,6,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,0,0,0,0,0,0,5,0,0,11,0,0,0,0,7,0,0,0,0,0,0,8,7,0, +4,0,0,0,0,11,0,0,0,0,0,11,0,0,5,0,0,8,7,0,4,0,7,0,0,0,0,0,0,0,6,0,0,0,0,0,4,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,10,5,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,0,0,0,0,0,0,0,0,0,6,0,5,0,0,0,0,0,0,0, +0,0,4,11,5,10,7,0,7,0,0,9,6,9,0,0,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,0,9,4,0,4, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,8,6,0,0,0,0,11,7,0,0,0,0,0,0,0,0,0,0,11,7,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,8,5,0,0,8,0,9,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,0,0,0,6,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,7,0,0,0,0,0,4,0,0,0,0,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,0, +10,7,0,0,0,6,0,0,0,0,0,0,8,0,0,6,0,0,0,6,10,0,0,0,0,0,0,0,0,0,0,0,8,5,0,0,0,6,0, +0,0,6,0,0,0,0,9,5,8,5,8,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,0, +0,8,7,10,0,0,0,0,0,0,0,9,6,0,0,0,0,0,0,0,0,0,0,11,7,0,0,0,0,0,5,0,0,0,6,0,7,0,0, +10,5,0,0,0,0,8,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,6,0,0,0,0,0,0,11,0,0,0,0,0,13,4, +0,0,0,4,0,0,0,0,0,5,8,0,0,0,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,7,14,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,9,0,0,0,0,7,0,0,0,0,0,0,9,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,4,0,0,0,0,0,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,14,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,5,0,0,15,6,10,0,0,0,8,6,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,9,6,0,0,0,0,0,0,0,0,0,0,0,4,0,0,0,0,14,6,10,0,0,0,0,0,0,0,0,6,0, +0,0,0,0,0,0,0,12,6,0,0,0,0,0,0,0,0,9,7,0,0,0,0,0,6,0,5,11,4,0,6,0,0,0,7,0,0,0,0, +0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,7,0,0,0,0,0,0,0,0,0,5,0,0,8,5,0,0,0,0,0,0,0,0,0,0, +0,0,10,0,0,0,0,0,9,6,9,4,0,0,0,4,0,0,0,0,0,0,0,0,11,0,0,0,0,0,0,0,0,0,0,0,8,5,0, +0,0,0,0,0,0,0,0,0,0,4,0,0,11,5,0,0,0,0,0,0,0,0,0,0,0,0,0,6,0,0,0,5,0,0,0,0,0,0, +0,0,0,7,12,0,0,0,0,6,0,0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,9,6,0, +4,9,6,0,4,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,0,0,0,0,0,0,0,0,6,0, +7,8,6,0,0,0,0,0,0,0,4,0,0,9,6,0,0,0,0,0,0,0,0,0,6,0,5,0,4,0,0,0,0,0,0,0,5,0,0,0, +0,0,5,0,0,0,7,12,7,0,0,0,0,0,0,18,4,0,0,0,0,0,0,0,0,0,0,0,0,11,0,0,0,0,6,0,0,0, +0,12,0,0,7,0,0,0,0,0,7,0,0,13,0,0,6,0,0,0,0,8,7,9,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,7,10,5,0,0,8,0,0,0,0,0,0,0,8,6,0,7,0,0,8,4,0,4,0,0,0,0,10,4,0,0,14,0, +0,0,0,0,0,0,0,0,0,0,0,5,0,0,0,0,17,0,0,0,0,0,0,6,0,0,0,0,8,6,0,0,10,5,0,0,0,0,8, +6,0,0,0,6,0,0,0,7,0,0,0,0,0,6,14,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,0,0,12,0,0,0,0,6, +8,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,0,0, +0,0,0,6,0,0,0,0,0,0,0,0,0,0,12,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,9,0,0,0,0,4,24,0,0, +0,0,0,12,6,0,0,10,6,0,5,0,0,0,4,0,0,0,0,0,0,0,0,0,0,0,4,0,0,0,0,17,7,0,5,0,0,0, +0,0,0,0,0,0,0,0,0,0,6,11,5,9,0,8,7,0,0,0,0,0,0,0,0,10,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,10,7,0,0,0,0,0,0,0,7,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,0,11,5,8,7,0,0,0, +0,8,5,0,0,0,0,10,7,0,7,0,0,0,0,0,0,0,0,0,0,13,6,0,0,0,0,0,0,0,0,0,6,0,4,0,0,0,0, +0,6,12,0,8,7,0,0,0,0,0,0,0,0,0,0,16,0,10,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,22,0,0,0, +0,0,0,0,0,0,0,0,0,0,13,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,9,6,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,22,0,0,6,0,0,21,0,0,0,22,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +6,0,0,0,0,9,6,0,0,0,0,0,0,0,0,0,6,0,0,0,5,0,0,0,0,0,7,8,0,0,0,0,6,14,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,0,0,8,6,0,0,0,0,0,0, +0,0,0,0,0,6,0,0,0,0,8,5,0,0,11,7,0,6,0,0,0,0,0,0,0,0,8,7,0,0,0,0,0,0,0,0,0,0,0, +6,0,0,0,5,0,0,0,0,0,0,0,0,0,4,0,0,8,7,0,0,0,0,8,5,11,7,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,4,0,0,0,0,8,5,0,0,10,0,0,4,13,7,0,0,0,0,0,0,0,0,0,0,0,7,0,0,0,5,0,0,13,6, +0,6,0,7,0,0,8,4,0,0,0,0,0,0,0,0,0,4,0,0,0,0,0,0,0,0,0,0,15,0,0,0,10,7,0,0,0,0,0, +7,0,0,0,0,0,0,0,4,0,0,0,0,0,6,0,0,0,0,19,0,0,0,0,6,0,0,0,0,0,4,0,0,0,0,0,6,0,5, +0,7,0,0,0,0,0,0,0,0,0,6,0,0,11,4,0,0,0,6,0,0,13,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,8,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,14,0,0,0,0,0,0,0,0,0,0,0,12,6,0,0,0,0, +0,7,0,0,0,0,0,0,11,7,0,0,0,0,0,6,0,0,10,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,5,11,6, +0,0,0,0,0,0,0,0,10,0,0,0,0,6,0,0,0,0,0,0,8,7,0,0,0,5,0,0,0,5,0,0,0,0,0,0,0,0,0, +0,0,0,8,7,0,0,0,0,9,6,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,0,10,7,0,0,0,0,10,0, +0,6,0,0,13,0,0,0,0,0,0,0,9,6,0,0,8,6,8,0,0,0,0,0,0,0,0,4,0,0,0,0,0,0,0,0,0,4,0, +0,9,7,0,0,0,0,0,0,11,0,0,0,10,7,0,0,0,0,0,0,0,0,9,6,0,0,12,4,0,4,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,6,0,0,0,0,21,0,0,0,0,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,6,0,5,0,0, +9,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8,4,0,0,0,0,0,6,0,0,0,6,0,0,0,0,0,0,0,0, +16,0,0,4,0,0,0,0,0,7,0,0,0,6,0,6,0,0,11,0,0,0,0,5,0,0,0,0,0,0,0,4,8,5,0,0,0,0,0, +0,14,0,0,0,0,6,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,0,0,0,0, +0,0,8,0,0,0,0,0,0,0,0,6,0,0,0,4,0,0,0,0,0,0,14,0,0,0,0,0,0,0,0,4,0,0,0,4,0,0,0, +0,0,0,0,6,9,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,9,6,14,7,0,0,9,7,0,0,11,0,0,0,0,0,10, +4,11,5,13,6,0,0,0,0,0,0,0,0,0,0,10,0,0,0,0,0,0,0,0,5,0,0,0,0,0,4,0,0,9,0,0,0,0, +0,0,0,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,6,12,5,0,0,0,6,14,0,0,0,0,0,0,0,0,0,0,4,9,4, +0,0,0,0,0,5,0,0,0,0,0,0,0,4,0,0,0,0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,5,0,0,0,5,0,0, +0,0,0,0,0,0,0,0,8,6,0,0,0,0,0,0,11,6,0,0,13,7,0,0,13,6,0,7,0,0,0,0,0,0,8,6,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,10,6,0,4,0,0,12,6,0,0,0,0,0,0,0,0,10,6, +0,0,0,6,0,0,0,5,0,0,0,0,0,0,0,0,0,0,0,0,0,6,0,0,10,0,0,0,0,0,0,0,0,0,0,0,0,6,0, +0,0,0,0,7,0,0,9,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,0,0,8,6,0, +0,0,7,11,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8,0,0,0, +0,0,0,5,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,0,0, +0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,0,8,7,0,0,8,5,0,0,0,4,9,5,0,0,0,7,10,6,0,0, +0,0,0,0,9,7,0,0,8,5,8,0,8,4,0,0,13,0,0,0,0,0,0,0,0,0,0,0,0,5,0,5,0,0,0,0,0,0,0, +0,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,0,6,0,0,0,4,0,0,0,0,0,0,0,0,0, +0,11,7,0,0,0,7,0,0,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,17,5,0,0,0,7,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,0,0,0,0,0,9,7,0,0,0,0,8,5,0,4,0,0,0,0,0,6,0,6,14, +6,0,0,0,0,9,6,0,0,0,0,0,0,8,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,6,0,0,0,0,14,7,9,7,8,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,16, +0,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,0,0,7,0,0,0,0,0,0,0,4,0,0,0,0,0,0,0,0,0,0,14,0, +0,6,0,0,8,6,0,0,0,0,0,6,0,0,12,0,0,0,0,0,8,5,0,7,11,0,0,5,0,4,0,0,0,6,0,0,0,0,0, +0,0,0,0,0,0,0,9,6,0,4,0,6,0,0,0,0,0,0,0,0,0,0,0,0,11,6,0,0,0,0,0,0,10,5,0,0,0,0, +0,4,0,0,0,7,11,6,0,4,8,5,9,5,0,0,0,5,0,7,0,0,0,0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,8,5,14,7,0,0,0,0,0,0,0,0,0,0,0,4,0,0,0,0,16,0,0,6,0,0,0,0,0,0,0,0,0,0,0,0,0,4, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,4,0,0,0,0,0,0,9,6,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,9,0,0,0,12,5,0,0,0,0,0,0,0,4,10,5,0,0,0,0,0,0,0,0,0,0,0,6,0, +0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,0,4,0,0,0,6,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,0,6,0,0,0,0,0,0,10,4,0,0,0,0,0,5,0,0,0,4, +0,0,0,0,0,0,9,0,0,0,0,0,0,0,0,6,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,0,8,0,10,7,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,10,7,0,0,0,0,0,0,0,0,15,0,0,0, +0,0,0,0,0,0,0,7,0,0,0,0,0,7,10,7,9,7,0,0,0,7,0,0,8,0,0,0,0,0,0,0,9,0,0,0,8,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,11,0,8,0,0,0,0,0,0,0,0,0,0,0,0,4,0,0,0,7,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,15,7,12,6,0,0,0,7,0,5,0,0,0,0,0,0,0,0,0,0,0,0,18,0,0,5,0,0,0,0, +0,0,0,6,9,5,0,0,0,0,0,0,0,0,0,7,0,0,0,0,0,0,0,0,9,7,0,0,14,0,0,0,11,7,0,0,0,0,0, +0,0,0,0,0,0,4,0,0,11,7,0,0,0,0,8,0,0,0,0,0,0,6,8,7,0,0,0,7,10,4,0,0,0,0,0,0,0,0, +0,0,0,0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8,7,0,0,0,0,10,0,0,0,0,0,0, +6,0,6,0,0,0,0,0,4,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,11,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,7,0,0,10,7,0,0,0,0,9,7,0,0,0,0,0,0,13,7,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,8,0,0,0,0,0,9,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,9,6,12,0, +0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,0,0,9,6,0,0,11,0,0, +0,0,0,14,4,0,0,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,23,7,0,0, +0,0,0,6,0,7,0,0,0,0,0,0,0,0,12,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,5,0,0,0,0,20, +7,0,0,0,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,8,0,0,0,0,0,0,0,0,0,11,5,0,0,0,0,0,0,0,0,0,0,10,4,0,0,0,5,8,5,10,4,0,0,0,0,0, +0,13,6,9,7,0,0,10,7,0,0,0,0,0,0,0,0,14,0,0,0,0,0,0,6,0,0,0,7,0,6,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,4,0,0,0,0,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8,7,10,7,0,0, +0,0,0,0,0,0,0,0,12,4,0,0,0,0,8,7,0,0,0,0,0,7,0,6,0,0,0,0,0,0,0,0,8,0,0,0,0,0,0, +0,0,0,0,6,0,6,9,6,0,0,12,5,0,0,8,6,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,0,0,6,0,0,0,0, +0,0,0,0,0,0,0,0,0,5,8,7,9,0,8,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,0,0,0,0,0,11, +4,0,0,0,0,0,0,8,0,0,0,10,7,0,4,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,6,0,0,8,0, +0,0,0,0,0,5,0,6,0,0,10,0,14,0,0,0,0,0,0,0,23,0,0,0,12,0,10,5,0,0,0,0,0,0,0,0,0, +5,0,0,0,0,8,0,0,0,0,6,8,0,0,0,0,0,0,0,0,0,22,0,8,0,0,0,0,6,0,0,0,0,0,0,0,5,0,0, +0,0,0,0,0,6,18,4,0,0,0,7,10,6,0,6,0,0,0,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0, +0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,7,10,0,0,0,0,0,0,6,0,0,0,0,11,5,0,0,0,0,0,0,0,0, +15,0,8,6,0,0,13,7,0,0,0,0,0,7,0,0,0,0,0,7,0,0,0,0,8,7,0,0,0,0,0,0,0,0,0,0,9,5,9, +0,0,6,8,6,0,0,0,0,10,0,0,0,18,5,0,0,0,5,0,7,0,0,0,0,8,6,0,0,0,0,9,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,14,0,23,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,0,0,0,6,0,0,0,5,0, +0,0,0,0,0,0,0,0,0,0,0,12,0,0,0,8,5,0,0,0,0,0,0,0,0,9,0,0,0,0,4,0,0,0,0,0,0,0,0, +0,0,0,0,20,5,0,0,0,0,0,0,0,5,0,0,0,0,0,0,0,0,9,5,0,0,0,0,0,0,8,4,24,0,0,0,0,0,0, +0,0,0,0,0,0,0,9,7,0,0,0,0,10,5,0,0,8,5,0,0,0,0,0,0,0,0,12,7,0,6,0,0,10,6,0,0,0, +0,14,0,0,4,9,5,0,0,0,0,0,0,9,0,0,0,0,0,0,6,0,0,0,0,0,4,0,0,8,0,0,0,0,0,11,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,0,0,0,0,0,0,8,5,11,7,0,4,0,0,10,0,0,0,0, +0,0,0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,6,0,0,11,6,0,0,0,0,0,5,14,6,0,0,0,0,10,0,0, +0,13,4,0,0,0,0,0,0,0,0,0,0,0,6,0,0,10,0,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,19,7,12,0,10,6,0,0,0,0,0,0,10,0,0,0,0,0,10,0,9, +7,0,0,0,0,0,0,0,0,0,0,0,0,0,7,8,0,0,0,0,0,0,0,0,0,0,0,0,4,0,7,0,0,0,0,9,7,0,0,0, +0,0,0,0,0,0,0,0,0,24,0,11,7,0,7,0,0,0,0,0,0,8,6,0,0,0,0,0,0,8,7,0,0,0,0,0,5,0,0, +0,6,9,0,0,0,23,5,0,0,0,0,0,6,0,0,0,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,16,7,0,0,0, +0,0,0,0,0,0,0,0,0,0,6,0,0,18,4,0,0,11,7,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6, +0,0,0,6,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,0,0,9,0,0,0,11,0,0,0,23,0,0, +0,10,4,0,0,0,0,0,7,0,0,0,7,0,0,0,0,0,4,0,0,0,0,0,7,0,0,19,0,11,0,0,0,0,0,12,7,0, +0,0,0,0,0,0,0,0,0,0,0,11,0,0,0,0,5,0,0,0,0,0,5,0,0,0,0,0,5,0,0,0,0,0,0,0,6,0,0, +9,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,11,0,0,0,0,0,0,0,0,4,0,0,0,0,10,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,0,4,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,22,0,8,7,10,4,11,0,13,5,8,7,9,0,8,7,0,0,0,7,0,0,0,0,0,0,0,7,0,0,0,0,0,0,0, +0,8,0,0,0,0,0,0,0,8,6,0,0,0,0,0,0,0,0,0,0,0,6,0,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,4,0,0,0,4,11,0,0,6,0,0,8,5,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,8,5,0,0, +20,0,0,0,0,0,0,0,0,0,11,0,0,0,0,5,0,0,0,0,0,0,0,0,0,5,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,7,0,0,14,0,0,0,9,0,13,7,0,0,0,0,0,6,0,7,0,0,8,6,10,6,0,0,8,6,0,0,0,6,0, +0,12,6,9,0,0,0,0,0,0,5,9,0,12,4,0,0,0,0,11,0,0,0,0,0,0,0,0,0,0,0,8,5,0,0,0,0,0, +0,0,4,8,0,0,6,8,0,0,0,0,0,0,0,0,0,13,6,0,7,0,0,0,0,0,6,8,7,8,6,0,0,0,7,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,0,0,0,0,0,18,0,11,4,0,0,0,5,0,0,0,0,0,0,0,0,0,0, +0,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,14, +6,0,0,0,0,12,7,8,0,0,0,0,0,0,0,8,7,0,0,0,0,10,4,0,0,0,0,0,0,10,0,0,6,0,0,0,0,0, +0,0,0,0,0,0,0,0,7,0,0,0,0,0,0,15,6,9,7,0,0,0,0,0,0,15,6,11,7,0,0,0,7,0,0,21,0,0, +0,0,0,0,5,0,0,0,0,0,0,0,0,0,0,0,4,0,0,0,0,17,6,0,0,10,5,0,5,0,0,0,0,0,0,0,0,0,7, +0,0,10,0,0,0,0,0,0,0,0,4,11,5,0,0,0,0,16,7,0,0,0,0,0,6,0,0,8,7,0,4,0,0,10,0,0,0, +0,0,0,0,0,0,0,0,12,0,0,0,0,0,0,0,0,0,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,8,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8,0,0,0,0, +0,0,0,10,4,0,0,0,0,0,0,0,0,0,6,0,5,0,0,9,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,10,0, +0,7,0,0,0,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,6,10,7,0,0,0,0,0,0,0,0,8,4,0,0,10,0,0,0,0,4,0,6,0,6,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,0,0,0,7,17,0,0,0,0,0, +0,0,0,0,0,0,10,0,0,7,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +6,0,0,0,5,0,0,0,0,0,0,0,5,0,0,0,0,0,0,0,5,0,4,0,0,0,0,0,6,0,0,0,0,0,0,10,5,0,0, +0,5,0,0,0,0,9,0,19,7,0,0,0,0,0,7,0,0,0,0,10,6,0,0,0,6,0,5,0,0,0,0,0,0,0,0,0,6,8, +0,0,0,0,0,11,0,0,0,0,0,0,6,0,0,0,0,0,7,9,0,15,0,0,0,0,0,0,0,0,0,0,4,0,0,0,5,0,0, +0,0,0,0,0,6,0,0,0,0,0,0,0,4,0,0,0,0,9,0,0,0,0,0,0,0,0,6,0,7,0,0,0,0,0,0,0,6,0,0, +0,0,0,6,10,0,0,0,0,0,0,0,23,0,14,0,0,0,0,7,0,0,0,0,0,7,0,0,9,0,0,0,0,7,0,0,0,0, +0,6,0,0,14,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,0,0,0,4,0,0,0, +0,0,0,0,0,9,5,0,0,0,0,0,4,0,0,0,0,9,5,0,0,0,0,22,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,22,0,0,0,0,0,0,0,10,0,0,0,0,0,0,5,0,4,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,6,11,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,14,7,0,0,12,7,0,0,0, +0,0,0,0,0,0,4,0,0,0,0,0,6,0,0,0,0,8,6,10,0,0,0,0,0,0,0,0,0,10,7,8,5,0,0,0,0,0,0, +0,0,8,4,0,0,0,0,0,0,0,0,0,0,0,0,10,0,0,5,0,0,9,5,0,0,0,0,0,5,0,0,0,0,0,4,0,0,0, +0,0,0,0,0,0,0,12,4,11,0,0,0,9,0,11,7,0,0,0,0,0,0,10,6,0,0,0,6,0,0,0,0,15,5,0,0, +11,6,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,0,0,0,0,0,0,0,4,0,4,0,6,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,0,0,8,0,0,0,19,7,0,4,0,0,9,0,0,0,0,0,10,0, +0,6,0,0,13,0,12,6,0,0,0,0,0,0,0,0,10,7,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,5,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,0,0,0,13,7,10,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,6,0,6,0,4,9,0,0,0,10,0,0,0,0,0,0,0, +0,5,0,0,0,0,0,0,10,0,23,6,0,0,0,6,8,0,0,0,0,0,0,0,0,0,17,7,0,0,0,0,11,6,22,5,0, +0,9,6,0,0,0,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,9,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,9,6,0,5,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,4,11,0,9,4,0,0, +0,7,0,7,0,0,0,0,0,0,12,4,0,0,0,0,0,0,0,0,0,0,0,0,11,4,0,0,0,0,0,0,0,0,0,0,0,0,0, +4,0,0,11,5,0,0,0,0,0,5,0,0,0,0,0,0,0,0,0,5,0,0,0,0,0,0,0,0,8,6,0,0,0,4,0,0,0,0, +0,0,0,0,0,7,0,0,0,4,0,0,10,4,0,0,0,0,0,0,0,7,0,7,0,0,0,6,0,0,0,0,8,6,0,6,0,6,0, +0,0,0,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,0,8,7,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,10,6,0,0,0,0,0,0,9,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,6,22,6,12,0,0,6,0,0,0,6,0,0,0,0,0,7,0,0,0,0,11,0,0,0, +9,7,0,0,0,0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,6,0,0,0,6,0,6,0,0,8,7,0,0,0,4,9,7,19,0,0,0,0,0,0,0,0,0,9,6,10,6,0,6,0,0,0, +4,0,0,8,7,0,0,0,0,0,0,0,0,0,0,0,6,16,7,10,6,0,0,23,6,11,7,0,4,0,0,0,0,0,0,0,0,0, +5,0,0,0,0,10,7,0,0,0,0,0,7,0,0,0,0,0,0,15,0,10,0,0,0,14,6,0,0,0,0,0,0,0,0,0,0,0, +5,0,0,0,0,0,0,0,5,0,0,0,0,11,0,0,0,0,0,0,0,0,0,0,5,0,0,11,5,0,0,0,0,0,0,0,0,0,0, +0,4,0,0,0,0,0,6,0,0,10,0,0,0,0,7,0,0,0,0,0,0,10,6,0,0,0,0,8,4,0,0,0,7,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,5,0,0,0,0,0,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,7,12,5,0,0,0,0, +0,6,0,0,0,0,9,6,0,0,0,0,0,0,0,6,9,0,0,0,0,6,0,0,0,0,8,7,0,0,0,0,0,0,0,6,0,0,0,0, +0,0,0,0,0,0,10,5,0,0,0,0,0,0,8,6,0,0,0,0,0,6,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,8,5,0,0,0,0,0,7,0,7,0,4,0,0,10,0,0,0,0,0,0,0,0,0,0,0,11,0,0,0,0,5,0,0,0,0,13, +7,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,0,0,0,0,0,0,0,0,0,8,7,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,7,0,0,13,0,0,0,0,0,0,0,0,7,10,5,0,0,0,0,0,0,9,7,0,0,8,6,9, +5,0,0,0,0,0,6,12,0,0,0,0,0,0,0,18,6,0,0,0,0,0,0,0,0,19,7,0,4,0,0,0,0,9,5,0,5,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,8,0,0,0,0,0,0,7,0,0,0,0,0,0,14,0,0,0,23,7,8,7,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8,6,22,0,0,7,0,0,0,0,0,0,0,0,9,7,8,4,0, +0,0,0,0,0,0,0,8,5,0,6,0,0,0,0,0,6,0,0,0,0,8,0,0,0,0,0,0,0,0,0,0,0,0,0,12,0,0,0, +8,0,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,0,12,5,0,0,0,0,0,0,0,0,0,0,8,6,0,0,11,7,0,0,0, +0,12,0,8,6,19,7,0,0,0,0,0,0,0,0,0,0,0,0,0,6,11,0,0,6,0,7,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,11,7,0,0,0,0,0,4,10,0,0,0,0,0,0,0,8,7,0,0,0,0,14,0,8,0,0,6,10,0,0, +0,0,0,0,0,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,0,0,0,0,0,0,0,0,0,6,0,0,0,0, +0,0,0,0,13,0,0,0,0,0,0,0,11,0,0,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0, +0,0,0,0,0,0,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,9,0,0,0,0,5,0,0,0,6,0,0,0,5,0,7,0,0,0, +0,0,6,0,0,21,7,0,0,9,6,0,0,0,6,0,0,13,7,0,0,0,5,0,0,0,0,0,4,0,6,0,0,0,0,0,0,0,0, +0,0,0,4,0,0,0,0,0,0,11,5,0,6,0,0,10,5,0,0,0,0,0,0,0,0,9,6,0,0,8,7,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,4,0,0,0,0,9,0,0,0,0,0,0,6,0,0,0,0,15,4,0,0,12,7,0,0,0,6, +0,7,0,0,8,0,9,5,0,4,0,0,0,6,0,6,0,0,23,4,0,0,0,0,0,0,0,0,0,0,0,0,10,7,0,4,0,0,8, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,0,0,0,0,0,0,0,0,0,0,4,0,0,0,6,0,0,0,0,0,0,0,0,0, +7,0,0,0,0,0,0,0,0,0,0,0,0,9,0,0,0,12,6,0,0,0,0,0,0,10,7,0,7,0,0,0,0,0,0,0,0,0,0, +9,0,0,0,0,0,8,0,0,0,0,4,0,0,0,0,0,0,0,0,0,4,11,5,0,0,0,6,0,6,0,0,0,0,0,0,0,6,0, +4,0,0,0,0,0,0,0,0,0,0,0,5,8,4,0,0,0,0,0,0,0,0,0,0,0,0,0,6,0,6,8,7,0,0,0,6,0,6,0, +0,0,0,0,0,0,0,0,5,0,0,0,0,0,5,0,0,0,0,11,0,0,0,0,0,0,0,10,5,9,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8,0,23,7,0,0,0,0,0,7,0,0,10,6,18,0,0,0, +0,0,0,0,8,7,0,6,0,0,0,0,0,0,8,5,0,0,0,5,0,0,0,0,0,0,0,0,0,0,0,0,8,0,0,0,0,0,0,0, +0,0,0,0,0,6,0,0,0,4,12,7,0,0,0,0,0,0,0,0,10,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,9,6,0,0,0,0,0,0,13,5,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8,4,0,0,0,0,0,0,0,0, +11,7,0,0,0,0,0,0,0,0,0,0,0,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,0,0,0,0,0, +0,0,0,0,6,0,0,0,4,0,0,0,0,0,0,0,4,0,0,0,0,0,0,0,0,0,0,10,0,11,0,0,0,0,0,0,0,0,0, +17,5,0,4,0,0,0,0,0,0,0,7,0,0,0,0,0,6,0,0,0,0,0,0,0,4,0,0,0,0,8,7,0,0,0,0,0,0,0, +0,13,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,0,0,0,0,6,0,0,0,0,0,6,0,0,0,0, +10,0,0,0,8,6,0,0,0,7,0,0,0,0,0,0,8,0,0,0,14,0,0,0,0,7,0,0,0,4,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,9,4,0,0,0,0,0,0,8,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,14,0, +10,0,0,0,16,5,0,0,0,0,0,0,8,0,0,4,0,0,0,0,0,0,0,0,0,0,9,6,0,0,0,0,0,0,10,0,0,0, +0,0,0,0,0,5,0,0,0,0,12,5,0,7,0,0,0,0,0,6,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,7,0, +0,0,0,0,0,0,0,12,6,0,0,0,0,0,7,0,6,0,6,12,6,0,0,0,0,0,0,0,4,8,7,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,0,0,0,0,6,0,6,0,0,0,0,0,0,0,0,10,6,8,0,0, +6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +16,0,8,0,0,0,0,5,0,0,0,0,0,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,23,5,0,0,0,7,0,6,0, +0,0,0,0,0,0,0,0,0,0,0,10,6,0,0,9,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,10,0,0,0,14,0,0,0,0,7,0,0,0,4,17,5,0,0,0,0,11,0,9,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,5,0,0,0,0,0,0,0,6,0,0,0,5,0,7,0,0,0,0,0,0,0,0,8,0,0,0, +12,6,0,0,0,0,0,0,13,0,0,0,0,7,9,0,0,0,0,0,0,0,0,0,0,5,0,0,0,7,10,7,12,0,0,0,9,0, +0,0,14,0,0,0,0,0,0,0,0,0,0,0,8,0,0,0,0,0,0,0,15,6,0,0,23,0,0,7,0,6,0,0,0,7,0,6, +0,0,0,0,0,0,0,6,0,6,9,0,0,0,0,0,0,0,8,7,0,0,0,0,0,0,0,0,8,7,9,4,0,0,10,0,0,0,10, +6,0,7,0,0,0,0,0,0,0,0,0,0,0,5,0,0,0,0,0,0,0,0,0,0,0,0,23,0,0,6,0,0,0,0,0,0,9,4, +0,0,10,7,0,0,0,0,0,0,0,0,0,0,0,0,9,7,0,0,9,6,0,0,0,0,8,6,0,0,0,0,0,0,0,0,12,0,0, +0,0,0,8,0,0,6,11,6,0,0,8,7,8,5,0,0,0,0,0,5,0,0,0,0,0,0,0,4,0,0,0,4,0,0,0,0,0,0, +10,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,10,0,0,0,0, +7,0,0,0,0,9,6,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,8,0,0,0,0,6,12,5,0,0,0,0,0,0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,6,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,0,0,0,0,10,0,10, +7,0,0,8,0,0,0,0,4,0,0,0,6,0,0,0,6,0,0,0,6,0,0,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,5,0, +0,0,4,0,0,0,0,0,4,0,0,0,0,0,0,0,6,0,6,0,5,0,0,0,0,8,0,0,0,10,7,0,0,0,0,10,0,0,0, +0,0,13,0,0,0,0,0,0,0,0,0,0,0,12,0,0,0,0,0,0,0,19,7,0,4,12,0,8,0,0,0,0,6,0,0,0,0, +0,0,0,6,0,0,0,0,0,0,0,0,0,4,0,0,0,0,18,0,0,0,0,0,0,0,10,0,0,0,0,0,0,0,0,0,0,0,0, +0,14,0,0,4,0,0,0,6,0,0,0,6,0,0,0,7,0,0,0,0,0,0,10,4,0,0,9,7,0,0,11,0,0,0,0,0,0, +7,0,0,0,0,0,0,0,0,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,9,0,0,0,0,4,0,0,12,0,0,0, +0,0,0,0,0,0,0,0,0,6,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,0,22,5,9,7,0,0,0,0,0,0,0,0,0, +0,0,6,0,0,9,6,0,5,0,0,0,0,0,0,10,5,0,0,8,6,0,6,10,5,0,0,0,6,0,0,0,6,0,0,20,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,9,0,0,0,0,6,0,0,0,0,17,4,0,7,0,6, +0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,0,0,0,0,0,14,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,10, +0,0,0,0,0,0,0,0,0,0,0,8,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,0,0,0,7,0,0,0,0,0,0,0, +0,0,7,0,0,8,6,12,0,0,7,18,7,0,0,8,4,0,0,0,0,9,6,0,0,0,0,0,0,0,0,13,0,0,6,0,0,0, +0,0,0,0,0,0,0,10,0,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,10,7,0,0, +0,0,0,0,0,0,0,5,0,0,0,0,0,0,0,0,0,0,8,5,0,0,0,0,0,0,0,0,12,0,0,0,8,0,0,0,0,0,0, +4,0,0,10,0,16,0,0,0,0,0,0,0,12,7,10,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,16,6,10,0,0,5,0,0,0,0,0,6,0,0,0,0, +0,7,0,0,0,7,0,0,0,0,0,0,0,0,0,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,9,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,5,8,7,0,7,0,0,0,0,0,0,0,0,8,0,0,6,0,0,0,6,0,0,0,4,0,0,0,0, +8,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,0,0,0,0,0,0,7,0,0,8,0,0,0, +9,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,0,0,0,7,13,5,0,5,0,0,0,7,8,4,0,0,0,0,0,0,0, +0,12,0,0,0,0,0,0,0,0,0,0,0,8,6,0,6,0,0,11,0,0,0,0,0,0,0,0,6,0,0,0,0,0,4,0,0,0,0, +0,0,0,0,0,6,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,0,10,7,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,9,0,11,6,0,0,10,6,0,0, +0,6,0,0,0,0,0,0,0,0,0,0,0,0,0,7,0,0,0,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6, +0,0,0,6,0,0,0,7,0,0,9,0,8,7,11,0,0,0,0,0,0,0,0,0,12,0,0,0,0,0,9,6,10,5,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8,0,0,0,0,0,10,7,0,0,0,0,0,0,11,0,9,6,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,5,0,6,0,0,0,0,0,0,0,0,0,5,0,0,0,0,0,0,0,0,0,0,15,5,12,5, +0,0,0,0,0,0,12,7,0,0,0,0,0,0,8,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8,6,0,0,12,6,0, +0,0,0,24,4,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,0,0,0,7,0,0,0,0,0,0,0,0,0,0, +0,0,0,4,10,4,0,0,0,0,10,7,0,0,0,0,0,0,0,0,0,0,0,0,9,0,11,0,0,0,0,0,0,0,0,0,0,6, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5, +0,0,8,0,0,0,0,7,0,0,0,0,0,0,10,0,0,0,0,0,0,4,0,0,0,0,0,0,0,0,0,0,10,7,0,0,0,0,0, +0,0,0,0,0,14,7,0,0,0,0,0,0,10,0,0,0,0,0,0,0,0,4,0,0,0,6,0,0,0,0,0,6,0,0,0,6,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,11,6,0,0,0,0,0,0,0,4,0,0,0,4,0,0,0,0,0,7,20,7,11,4,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,19,7,9,6,0,0,12,7,0,0,0,0,0,0,10,0,12,0, +0,0,0,0,0,4,9,6,13,0,0,0,0,0,0,0,0,6,0,0,0,6,0,0,0,5,0,0,0,0,0,0,8,0,0,0,0,0,0, +0,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,6,0,0,0,0,0,6,0,0,11,0,9,0,0,0,0,4,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,8,5,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,19,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,0,0, +0,4,0,5,0,0,0,0,0,0,0,0,0,4,0,0,0,0,9,7,8,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,0,0, +0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,5,0,0,0,0,0,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,6, +0,0,0,0,8,7,0,0,0,0,0,0,12,0,0,6,0,0,0,0,0,0,0,6,8,4,0,0,10,7,0,0,10,0,0,0,0,0, +0,0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,7,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,0,0,6,0,4,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,9,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,9,7,0,0,0,0,0,0,0,5, +0,4,0,0,0,0,0,6,0,0,0,0,0,0,8,0,0,6,0,0,0,6,0,0,0,0,0,7,0,5,8,4,0,0,9,0,0,0,0,4, +0,0,0,0,0,0,0,0,0,5,0,0,15,6,8,6,0,0,0,6,0,0,0,0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,6,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,0,0,9,6,0,0,0,0,0,0,0,7,0,0,0,4,0, +6,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,6,0,0,0,0,0,0,11,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,9,5,0,6,12,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,11,6,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,6,0,0,8,7,0,6,0,0,0,0,0,0,0,0,0,0,0,0,11,0,12,7,0,0,0,0, +0,0,0,0,0,5,0,5,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,0,11,4,0,0,0,0,0,0,0,0,0,0,10, +7,0,0,0,0,0,0,0,0,0,6,0,0,0,0,0,7,8,7,9,6,0,0,0,0,0,0,0,0,8,6,0,0,0,0,0,5,12,0, +10,5,12,6,0,0,0,7,0,0,0,0,0,0,0,5,0,0,0,5,9,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7, +11,7,0,0,0,0,0,0,0,0,0,0,17,0,0,0,0,0,0,6,0,7,0,0,0,0,8,0,8,5,0,6,0,0,0,6,0,0,0, +0,0,0,0,6,0,6,0,6,9,0,0,5,17,0,0,0,0,0,0,0,0,0,0,0,0,0,9,0,0,0,0,0,0,0,0,7,0,0, +0,0,0,7,0,0,0,0,16,5,0,0,0,0,0,0,0,4,0,0,0,5,11,5,0,7,0,0,0,4,8,7,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,11,7,0,0,0,0,12,0,0,0, +0,0,12,0,0,0,0,0,0,0,0,4,10,4,0,0,0,0,0,0,0,0,0,4,0,0,0,0,0,6,0,0,0,0,0,0,0,4,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,11,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,0,0,20,5,0,0, +10,0,0,0,0,0,0,0,0,0,0,6,0,0,0,6,12,0,0,0,0,0,0,6,0,0,0,0,0,0,9,4,10,7,0,4,0,0, +0,0,0,0,10,6,0,0,0,0,8,4,0,7,8,6,0,6,8,0,10,0,0,0,0,0,13,5,0,6,0,0,0,0,0,0,22,4, +0,0,0,0,0,0,0,0,0,0,9,0,0,0,0,6,0,0,0,6,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,6,10, +5,8,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,10,0,0,0,0,0,10,4,0,0,10,7,0,0,0,0,0,5,0, +5,8,0,0,0,0,6,0,0,0,0,0,0,0,5,0,0,0,0,0,0,0,0,0,0,10,7,0,0,0,4,0,0,0,0,0,6,0,0, +0,0,0,0,0,0,8,7,0,0,0,0,0,0,0,0,0,0,0,0,11,0,0,0,0,7,0,0,0,6,0,0,0,0,0,0,0,0,0, +4,0,0,0,4,10,0,0,6,13,7,8,0,0,0,0,0,0,7,0,0,12,7,0,0,0,0,0,0,10,5,0,0,0,0,0,6,0, +0,0,0,0,0,0,0,0,0,13,7,0,0,0,0,0,0,0,0,0,7,0,0,0,0,0,6,0,0,0,0,0,0,0,0,8,6,0,6, +0,0,0,0,0,0,0,0,12,0,8,4,0,0,0,0,0,4,0,4,0,0,0,0,0,0,0,5,0,0,0,0,12,5,0,0,0,7,0, +0,0,0,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,0,6,10,0,0,0,20,0,0,5,0,0,10, +7,11,7,0,0,0,0,0,0,0,0,0,0,17,0,9,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,0,0,10,7,0,4,0,6,0,0,24,0,0,5,0,0,0,0,8,0,0, +0,0,0,0,0,10,5,0,4,0,6,0,0,8,0,0,0,0,0,0,4,0,6,0,0,0,0,0,0,9,5,0,0,0,0,0,0,0,0, +0,0,0,6,0,0,0,0,9,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,0,0,0,0,0,0,0,0,4,0,7, +0,0,13,0,0,0,0,0,0,0,11,6,0,0,0,0,0,0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,0,0,0, +17,7,0,0,11,6,0,0,0,0,12,6,0,0,0,6,0,6,0,0,0,0,0,0,0,0,0,0,10,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,4,0,0,0,0,0,0,0,0,0,5,0,0,0,6,0,0,0,0,0,0,0,0,0,0,10,0,0,4,8,6,0,0,0, +0,0,0,9,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,9,5,0,7,18,0,0,0,0,0,0,0,0,0,0,0,0,0,8,6,0,0,0,0,0,0,0,0,8,0,0,0, +0,0,0,0,0,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0, +0,0,0,0,0,0,10,0,0,0,0,0,0,0,0,4,0,6,0,0,9,0,0,0,0,0,0,0,0,0,13,0,0,0,0,0,0,0,0, +0,0,0,8,7,10,0,8,5,0,0,0,0,0,0,0,0,9,0,0,0,10,0,0,0,0,6,0,7,0,4,0,0,0,0,0,0,0,0, +8,0,0,0,0,0,8,4,0,0,0,0,0,5,0,0,10,0,12,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +4,0,0,0,0,0,0,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,18,6,11,0,0, +7,0,0,0,0,0,6,10,5,0,0,0,0,0,0,0,0,0,5,0,0,9,5,12,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,6,0,0,0,0,13,6,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,0,0,0,0,0,0,0,0,0, +0,0,0,8,4,0,6,12,0,0,0,0,0,0,0,0,0,0,0,0,6,0,6,0,0,0,0,0,5,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,11,4,0,0,0,6,14,0,11,0,9,6,0,0,0,0,0,0,22,0,12,0,8,6,0,0,0,0,0,0,0,6,0, +0,0,0,0,6,0,0,0,0,0,0,0,0,0,0,11,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,0,0,0,0,0,0,0,0, +10,7,0,0,0,0,0,0,0,0,9,0,0,0,0,4,0,0,0,0,0,0,0,0,0,5,11,0,0,0,0,0,0,0,8,6,0,0,9, +7,0,0,12,4,0,0,0,0,0,0,12,6,0,6,0,7,0,0,8,5,0,0,0,0}; #if defined(__cplusplus) || defined(c_plusplus) } /* extern "C" */ diff --git a/modules/brotli/enc/dictionary_hash.h b/modules/brotli/enc/dictionary_hash.h index b3bb9599f4..e553ea5d4e 100644 --- a/modules/brotli/enc/dictionary_hash.h +++ b/modules/brotli/enc/dictionary_hash.h @@ -15,7 +15,8 @@ extern "C" { #endif -extern const uint16_t kStaticDictionaryHash[32768]; +extern const uint16_t kStaticDictionaryHashWords[32768]; +extern const uint8_t kStaticDictionaryHashLengths[32768]; #if defined(__cplusplus) || defined(c_plusplus) } /* extern "C" */ diff --git a/modules/brotli/enc/encode.c b/modules/brotli/enc/encode.c index 141e70aa2a..8d90937b43 100644 --- a/modules/brotli/enc/encode.c +++ b/modules/brotli/enc/encode.c @@ -54,12 +54,19 @@ typedef enum BrotliEncoderStreamState { BROTLI_STREAM_METADATA_BODY = 4 } BrotliEncoderStreamState; +typedef enum BrotliEncoderFlintState { + BROTLI_FLINT_NEEDS_2_BYTES = 2, + BROTLI_FLINT_NEEDS_1_BYTE = 1, + BROTLI_FLINT_WAITING_FOR_PROCESSING = 0, + BROTLI_FLINT_WAITING_FOR_FLUSHING = -1, + BROTLI_FLINT_DONE = -2 +} BrotliEncoderFlintState; + typedef struct BrotliEncoderStateStruct { BrotliEncoderParams params; MemoryManager memory_manager_; - HasherHandle hasher_; uint64_t input_pos_; RingBuffer ringbuffer_; size_t cmd_alloc_size_; @@ -73,10 +80,17 @@ typedef struct BrotliEncoderStateStruct { int saved_dist_cache_[4]; uint16_t last_bytes_; uint8_t last_bytes_bits_; + /* "Flint" is a tiny uncompressed block emitted before the continuation + block to unwire literal context from previous data. Despite being int8_t, + field is actually BrotliEncoderFlintState enum. */ + int8_t flint_; uint8_t prev_byte_; uint8_t prev_byte2_; size_t storage_size_; uint8_t* storage_; + + Hasher hasher_; + /* Hash table for FAST_ONE_PASS_COMPRESSION_QUALITY mode. */ int small_table_[1 << 10]; /* 4KiB */ int* large_table_; /* Allocated only when needed */ @@ -114,8 +128,6 @@ typedef struct BrotliEncoderStateStruct { BROTLI_BOOL is_initialized_; } BrotliEncoderStateStruct; -static BROTLI_BOOL EnsureInitialized(BrotliEncoderState* s); - static size_t InputBlockSize(BrotliEncoderState* s) { return (size_t)1 << s->params.lgblock; } @@ -174,6 +186,11 @@ BROTLI_BOOL BrotliEncoderSetParameter( state->params.dist.num_direct_distance_codes = value; return BROTLI_TRUE; + case BROTLI_PARAM_STREAM_OFFSET: + if (value > (1u << 30)) return BROTLI_FALSE; + state->params.stream_offset = value; + return BROTLI_TRUE; + default: return BROTLI_FALSE; } } @@ -195,7 +212,7 @@ static uint8_t* GetBrotliStorage(BrotliEncoderState* s, size_t size) { if (s->storage_size_ < size) { BROTLI_FREE(m, s->storage_); s->storage_ = BROTLI_ALLOC(m, uint8_t, size); - if (BROTLI_IS_OOM(m)) return NULL; + if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(s->storage_)) return NULL; s->storage_size_ = size; } return s->storage_; @@ -234,7 +251,7 @@ static int* GetHashTable(BrotliEncoderState* s, int quality, s->large_table_size_ = htsize; BROTLI_FREE(m, s->large_table_); s->large_table_ = BROTLI_ALLOC(m, int, htsize); - if (BROTLI_IS_OOM(m)) return 0; + if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(s->large_table_)) return 0; } table = s->large_table_; } @@ -499,7 +516,7 @@ static BROTLI_BOOL ShouldCompress( /* TODO: find more precise minimal block overhead. */ if (bytes <= 2) return BROTLI_FALSE; if (num_commands < (bytes >> 8) + 2) { - if (num_literals > 0.99 * (double)bytes) { + if ((double)num_literals > 0.99 * (double)bytes) { uint32_t literal_histo[256] = { 0 }; static const uint32_t kSampleRate = 13; static const double kMinEntropy = 7.92; @@ -617,11 +634,7 @@ static void WriteMetaBlockInternal(MemoryManager* m, /* The number of distance symbols effectively used for distance histograms. It might be less than distance alphabet size for "Large Window Brotli" (32-bit). */ - uint32_t num_effective_dist_codes = block_params.dist.alphabet_size; - if (num_effective_dist_codes > BROTLI_NUM_HISTOGRAM_DISTANCE_SYMBOLS) { - num_effective_dist_codes = BROTLI_NUM_HISTOGRAM_DISTANCE_SYMBOLS; - } - BrotliOptimizeHistograms(num_effective_dist_codes, &mb); + BrotliOptimizeHistograms(block_params.dist.alphabet_size_limit, &mb); } BrotliStoreMetaBlock(m, data, wrapped_last_flush_pos, bytes, mask, prev_byte, prev_byte2, @@ -678,12 +691,23 @@ static BROTLI_BOOL EnsureInitialized(BrotliEncoderState* s) { s->last_bytes_bits_ = 0; s->last_bytes_ = 0; + s->flint_ = BROTLI_FLINT_DONE; s->remaining_metadata_bytes_ = BROTLI_UINT32_MAX; SanitizeParams(&s->params); s->params.lgblock = ComputeLgBlock(&s->params); ChooseDistanceParams(&s->params); + if (s->params.stream_offset != 0) { + s->flint_ = BROTLI_FLINT_NEEDS_2_BYTES; + /* Poison the distance cache. -16 +- 3 is still less than zero (invalid). */ + s->dist_cache_[0] = -16; + s->dist_cache_[1] = -16; + s->dist_cache_[2] = -16; + s->dist_cache_[3] = -16; + memcpy(s->saved_dist_cache_, s->dist_cache_, sizeof(s->saved_dist_cache_)); + } + RingBufferSetup(&s->params, &s->ringbuffer_); /* Initialize last byte with stream header. */ @@ -693,8 +717,14 @@ static BROTLI_BOOL EnsureInitialized(BrotliEncoderState* s) { s->params.quality == FAST_TWO_PASS_COMPRESSION_QUALITY) { lgwin = BROTLI_MAX(int, lgwin, 18); } - EncodeWindowBits(lgwin, s->params.large_window, - &s->last_bytes_, &s->last_bytes_bits_); + if (s->params.stream_offset == 0) { + EncodeWindowBits(lgwin, s->params.large_window, + &s->last_bytes_, &s->last_bytes_bits_); + } else { + /* Bigger values have the same effect, but could cause overflows. */ + s->params.stream_offset = BROTLI_MIN(size_t, + s->params.stream_offset, BROTLI_MAX_BACKWARD_LIMIT(lgwin)); + } } if (s->params.quality == FAST_ONE_PASS_COMPRESSION_QUALITY) { @@ -712,13 +742,15 @@ static void BrotliEncoderInitParams(BrotliEncoderParams* params) { params->quality = BROTLI_DEFAULT_QUALITY; params->lgwin = BROTLI_DEFAULT_WINDOW; params->lgblock = 0; + params->stream_offset = 0; params->size_hint = 0; params->disable_literal_context_modeling = BROTLI_FALSE; BrotliInitEncoderDictionary(¶ms->dictionary); params->dist.distance_postfix_bits = 0; params->dist.num_direct_distance_codes = 0; - params->dist.alphabet_size = + params->dist.alphabet_size_max = BROTLI_DISTANCE_ALPHABET_SIZE(0, 0, BROTLI_MAX_DISTANCE_BITS); + params->dist.alphabet_size_limit = params->dist.alphabet_size_max; params->dist.max_distance = BROTLI_MAX_DISTANCE; } @@ -734,7 +766,7 @@ static void BrotliEncoderInitState(BrotliEncoderState* s) { s->prev_byte2_ = 0; s->storage_size_ = 0; s->storage_ = 0; - s->hasher_ = NULL; + HasherInit(&s->hasher_); s->large_table_ = NULL; s->large_table_size_ = 0; s->cmd_code_numbits_ = 0; @@ -902,6 +934,7 @@ static void ExtendLastCommand(BrotliEncoderState* s, uint32_t* bytes, (*bytes)--; (*wrapped_last_processed_pos)++; } + } else { } /* The copy length is at most the metablock size, and thus expressible. */ GetLengthCode(last_command->insert_len_, @@ -934,6 +967,7 @@ static BROTLI_BOOL EncodeData( uint32_t mask; MemoryManager* m = &s->memory_manager_; ContextType literal_context_mode; + ContextLut literal_context_lut; data = s->ringbuffer_.buffer_; mask = s->ringbuffer_.mask_; @@ -951,7 +985,10 @@ static BROTLI_BOOL EncodeData( BROTLI_ALLOC(m, uint32_t, kCompressFragmentTwoPassBlockSize); s->literal_buf_ = BROTLI_ALLOC(m, uint8_t, kCompressFragmentTwoPassBlockSize); - if (BROTLI_IS_OOM(m)) return BROTLI_FALSE; + if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(s->command_buf_) || + BROTLI_IS_NULL(s->literal_buf_)) { + return BROTLI_FALSE; + } } if (s->params.quality == FAST_ONE_PASS_COMPRESSION_QUALITY || @@ -1009,7 +1046,7 @@ static BROTLI_BOOL EncodeData( newsize += (bytes / 4) + 16; s->cmd_alloc_size_ = newsize; new_commands = BROTLI_ALLOC(m, Command, newsize); - if (BROTLI_IS_OOM(m)) return BROTLI_FALSE; + if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(new_commands)) return BROTLI_FALSE; if (s->commands_) { memcpy(new_commands, s->commands_, sizeof(Command) * s->num_commands_); BROTLI_FREE(m, s->commands_); @@ -1024,6 +1061,7 @@ static BROTLI_BOOL EncodeData( literal_context_mode = ChooseContextMode( &s->params, data, WrapPosition(s->last_flush_pos_), mask, (size_t)(s->input_pos_ - s->last_flush_pos_)); + literal_context_lut = BROTLI_CONTEXT_LUT(literal_context_mode); if (BROTLI_IS_OOM(m)) return BROTLI_FALSE; @@ -1034,20 +1072,23 @@ static BROTLI_BOOL EncodeData( if (s->params.quality == ZOPFLIFICATION_QUALITY) { BROTLI_DCHECK(s->params.hasher.type == 10); BrotliCreateZopfliBackwardReferences(m, bytes, wrapped_last_processed_pos, - data, mask, &s->params, s->hasher_, s->dist_cache_, + data, mask, literal_context_lut, &s->params, + &s->hasher_, s->dist_cache_, &s->last_insert_len_, &s->commands_[s->num_commands_], &s->num_commands_, &s->num_literals_); if (BROTLI_IS_OOM(m)) return BROTLI_FALSE; } else if (s->params.quality == HQ_ZOPFLIFICATION_QUALITY) { BROTLI_DCHECK(s->params.hasher.type == 10); BrotliCreateHqZopfliBackwardReferences(m, bytes, wrapped_last_processed_pos, - data, mask, &s->params, s->hasher_, s->dist_cache_, + data, mask, literal_context_lut, &s->params, + &s->hasher_, s->dist_cache_, &s->last_insert_len_, &s->commands_[s->num_commands_], &s->num_commands_, &s->num_literals_); if (BROTLI_IS_OOM(m)) return BROTLI_FALSE; } else { BrotliCreateBackwardReferences(bytes, wrapped_last_processed_pos, - data, mask, &s->params, s->hasher_, s->dist_cache_, + data, mask, literal_context_lut, &s->params, + &s->hasher_, s->dist_cache_, &s->last_insert_len_, &s->commands_[s->num_commands_], &s->num_commands_, &s->num_literals_); } @@ -1072,7 +1113,7 @@ static BROTLI_BOOL EncodeData( s->num_commands_ < max_commands) { /* Merge with next input block. Everything will happen later. */ if (UpdateLastProcessedPos(s)) { - HasherReset(s->hasher_); + HasherReset(&s->hasher_); } *out_size = 0; return BROTLI_TRUE; @@ -1113,7 +1154,7 @@ static BROTLI_BOOL EncodeData( s->last_bytes_bits_ = storage_ix & 7u; s->last_flush_pos_ = s->input_pos_; if (UpdateLastProcessedPos(s)) { - HasherReset(s->hasher_); + HasherReset(&s->hasher_); } if (s->last_flush_pos_ > 0) { s->prev_byte_ = data[((uint32_t)s->last_flush_pos_ - 1) & mask]; @@ -1174,7 +1215,6 @@ static BROTLI_BOOL BrotliCompressBufferQuality10( size_t total_out_size = 0; uint16_t last_bytes; uint8_t last_bytes_bits; - HasherHandle hasher = NULL; const size_t hasher_eff_size = BROTLI_MIN(size_t, input_size, BROTLI_MAX_BACKWARD_LIMIT(lgwin) + BROTLI_WINDOW_GAP); @@ -1190,6 +1230,9 @@ static BROTLI_BOOL BrotliCompressBufferQuality10( uint8_t prev_byte = 0; uint8_t prev_byte2 = 0; + Hasher hasher; + HasherInit(&hasher); + BrotliEncoderInitParams(¶ms); params.quality = 10; params.lgwin = lgwin; @@ -1226,6 +1269,7 @@ static BROTLI_BOOL BrotliCompressBufferQuality10( ContextType literal_context_mode = ChooseContextMode(¶ms, input_buffer, metablock_start, mask, metablock_end - metablock_start); + ContextLut literal_context_lut = BROTLI_CONTEXT_LUT(literal_context_mode); size_t block_start; for (block_start = metablock_start; block_start < metablock_end; ) { @@ -1234,12 +1278,12 @@ static BROTLI_BOOL BrotliCompressBufferQuality10( ZopfliNode* nodes = BROTLI_ALLOC(m, ZopfliNode, block_size + 1); size_t path_size; size_t new_cmd_alloc_size; - if (BROTLI_IS_OOM(m)) goto oom; + if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(nodes)) goto oom; BrotliInitZopfliNodes(nodes, block_size + 1); - StitchToPreviousBlockH10(hasher, block_size, block_start, + StitchToPreviousBlockH10(&hasher.privat._H10, block_size, block_start, input_buffer, mask); path_size = BrotliZopfliComputeShortestPath(m, block_size, block_start, - input_buffer, mask, ¶ms, dist_cache, hasher, + input_buffer, mask, literal_context_lut, ¶ms, dist_cache, &hasher, nodes); if (BROTLI_IS_OOM(m)) goto oom; /* We allocate a command buffer in the first iteration of this loop that @@ -1254,7 +1298,7 @@ static BROTLI_BOOL BrotliCompressBufferQuality10( num_commands + path_size + 1); if (cmd_alloc_size != new_cmd_alloc_size) { Command* new_commands = BROTLI_ALLOC(m, Command, new_cmd_alloc_size); - if (BROTLI_IS_OOM(m)) goto oom; + if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(new_commands)) goto oom; cmd_alloc_size = new_cmd_alloc_size; if (commands) { memcpy(new_commands, commands, sizeof(Command) * num_commands); @@ -1286,7 +1330,7 @@ static BROTLI_BOOL BrotliCompressBufferQuality10( if (metablock_size == 0) { /* Write the ISLAST and ISEMPTY bits. */ storage = BROTLI_ALLOC(m, uint8_t, 16); - if (BROTLI_IS_OOM(m)) goto oom; + if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(storage)) goto oom; storage[0] = (uint8_t)last_bytes; storage[1] = (uint8_t)(last_bytes >> 8); BrotliWriteBits(2, 3, &storage_ix, storage); @@ -1297,7 +1341,7 @@ static BROTLI_BOOL BrotliCompressBufferQuality10( CreateBackwardReferences is now unused. */ memcpy(dist_cache, saved_dist_cache, 4 * sizeof(dist_cache[0])); storage = BROTLI_ALLOC(m, uint8_t, metablock_size + 16); - if (BROTLI_IS_OOM(m)) goto oom; + if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(storage)) goto oom; storage[0] = (uint8_t)last_bytes; storage[1] = (uint8_t)(last_bytes >> 8); BrotliStoreUncompressedMetaBlock(is_last, input_buffer, @@ -1318,14 +1362,10 @@ static BROTLI_BOOL BrotliCompressBufferQuality10( /* The number of distance symbols effectively used for distance histograms. It might be less than distance alphabet size for "Large Window Brotli" (32-bit). */ - uint32_t num_effective_dist_codes = block_params.dist.alphabet_size; - if (num_effective_dist_codes > BROTLI_NUM_HISTOGRAM_DISTANCE_SYMBOLS) { - num_effective_dist_codes = BROTLI_NUM_HISTOGRAM_DISTANCE_SYMBOLS; - } - BrotliOptimizeHistograms(num_effective_dist_codes, &mb); + BrotliOptimizeHistograms(block_params.dist.alphabet_size_limit, &mb); } storage = BROTLI_ALLOC(m, uint8_t, 2 * metablock_size + 503); - if (BROTLI_IS_OOM(m)) goto oom; + if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(storage)) goto oom; storage[0] = (uint8_t)last_bytes; storage[1] = (uint8_t)(last_bytes >> 8); BrotliStoreMetaBlock(m, input_buffer, metablock_start, metablock_size, @@ -1576,7 +1616,10 @@ static BROTLI_BOOL BrotliEncoderCompressStreamFast( BROTLI_ALLOC(m, uint32_t, kCompressFragmentTwoPassBlockSize); s->literal_buf_ = BROTLI_ALLOC(m, uint8_t, kCompressFragmentTwoPassBlockSize); - if (BROTLI_IS_OOM(m)) return BROTLI_FALSE; + if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(s->command_buf_) || + BROTLI_IS_NULL(s->literal_buf_)) { + return BROTLI_FALSE; + } } if (s->command_buf_) { command_buf = s->command_buf_; @@ -1584,7 +1627,10 @@ static BROTLI_BOOL BrotliEncoderCompressStreamFast( } else { tmp_command_buf = BROTLI_ALLOC(m, uint32_t, buf_size); tmp_literal_buf = BROTLI_ALLOC(m, uint8_t, buf_size); - if (BROTLI_IS_OOM(m)) return BROTLI_FALSE; + if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(tmp_command_buf) || + BROTLI_IS_NULL(tmp_literal_buf)) { + return BROTLI_FALSE; + } command_buf = tmp_command_buf; literal_buf = tmp_literal_buf; } @@ -1640,8 +1686,10 @@ static BROTLI_BOOL BrotliEncoderCompressStreamFast( &storage_ix, storage); if (BROTLI_IS_OOM(m)) return BROTLI_FALSE; } - *next_in += block_size; - *available_in -= block_size; + if (block_size != 0) { + *next_in += block_size; + *available_in -= block_size; + } if (inplace) { size_t out_bytes = storage_ix >> 3; BROTLI_DCHECK(out_bytes <= *available_out); @@ -1786,6 +1834,10 @@ BROTLI_BOOL BrotliEncoderCompressStream( } while (BROTLI_TRUE) { size_t remaining_block_size = RemainingInputBlockSize(s); + /* Shorten input to flint size. */ + if (s->flint_ >= 0 && remaining_block_size > (size_t)s->flint_) { + remaining_block_size = (size_t)s->flint_; + } if (remaining_block_size != 0 && *available_in != 0) { size_t copy_input_size = @@ -1793,10 +1845,18 @@ BROTLI_BOOL BrotliEncoderCompressStream( CopyInputToRingBuffer(s, copy_input_size, *next_in); *next_in += copy_input_size; *available_in -= copy_input_size; + if (s->flint_ > 0) s->flint_ = (int8_t)(s->flint_ - (int)copy_input_size); continue; } if (InjectFlushOrPushOutput(s, available_out, next_out, total_out)) { + /* Exit the "emit flint" workflow. */ + if (s->flint_ == BROTLI_FLINT_WAITING_FOR_FLUSHING) { + CheckFlushComplete(s); + if (s->stream_state_ == BROTLI_STREAM_PROCESSING) { + s->flint_ = BROTLI_FLINT_DONE; + } + } continue; } @@ -1810,6 +1870,11 @@ BROTLI_BOOL BrotliEncoderCompressStream( BROTLI_BOOL force_flush = TO_BROTLI_BOOL( (*available_in == 0) && op == BROTLI_OPERATION_FLUSH); BROTLI_BOOL result; + /* Force emitting (uncompressed) piece containing flint. */ + if (!is_last && s->flint_ == 0) { + s->flint_ = BROTLI_FLINT_WAITING_FOR_FLUSHING; + force_flush = BROTLI_TRUE; + } UpdateSizeHint(s, *available_in); result = EncodeData(s, is_last, force_flush, &s->available_out_, &s->next_out_); diff --git a/modules/brotli/enc/encoder_dict.c b/modules/brotli/enc/encoder_dict.c index 8b2f6ad4a4..c9e963b89d 100644 --- a/modules/brotli/enc/encoder_dict.c +++ b/modules/brotli/enc/encoder_dict.c @@ -17,14 +17,15 @@ extern "C" { void BrotliInitEncoderDictionary(BrotliEncoderDictionary* dict) { dict->words = BrotliGetDictionary(); + dict->num_transforms = (uint32_t)BrotliGetTransforms()->num_transforms; - dict->hash_table = kStaticDictionaryHash; + dict->hash_table_words = kStaticDictionaryHashWords; + dict->hash_table_lengths = kStaticDictionaryHashLengths; dict->buckets = kStaticDictionaryBuckets; dict->dict_words = kStaticDictionaryWords; dict->cutoffTransformsCount = kCutoffTransformsCount; dict->cutoffTransforms = kCutoffTransforms; - } #if defined(__cplusplus) || defined(c_plusplus) diff --git a/modules/brotli/enc/encoder_dict.h b/modules/brotli/enc/encoder_dict.h index 3cb6b0ac15..a1c329fbf4 100644 --- a/modules/brotli/enc/encoder_dict.h +++ b/modules/brotli/enc/encoder_dict.h @@ -19,13 +19,15 @@ extern "C" { /* Dictionary data (words and transforms) for 1 possible context */ typedef struct BrotliEncoderDictionary { const BrotliDictionary* words; + uint32_t num_transforms; /* cut off for fast encoder */ uint32_t cutoffTransformsCount; uint64_t cutoffTransforms; /* from dictionary_hash.h, for fast encoder */ - const uint16_t* hash_table; + const uint16_t* hash_table_words; + const uint8_t* hash_table_lengths; /* from static_dict_lut.h, for slow encoder */ const uint16_t* buckets; diff --git a/modules/brotli/enc/entropy_encode.c b/modules/brotli/enc/entropy_encode.c index 97f9dfb82a..b50ccb5d1f 100644 --- a/modules/brotli/enc/entropy_encode.c +++ b/modules/brotli/enc/entropy_encode.c @@ -18,6 +18,8 @@ extern "C" { #endif +const size_t kBrotliShellGaps[] = {132, 57, 23, 10, 4, 1}; + BROTLI_BOOL BrotliSetDepth( int p0, HuffmanTree* pool, uint8_t* depth, int max_depth) { int stack[16]; diff --git a/modules/brotli/enc/entropy_encode.h b/modules/brotli/enc/entropy_encode.h index f23d9c379d..9618e1d359 100644 --- a/modules/brotli/enc/entropy_encode.h +++ b/modules/brotli/enc/entropy_encode.h @@ -76,12 +76,12 @@ BROTLI_INTERNAL void BrotliConvertBitDepthsToSymbols(const uint8_t* depth, size_t len, uint16_t* bits); +BROTLI_INTERNAL extern const size_t kBrotliShellGaps[6]; /* Input size optimized Shell sort. */ typedef BROTLI_BOOL (*HuffmanTreeComparator)( const HuffmanTree*, const HuffmanTree*); static BROTLI_INLINE void SortHuffmanTreeItems(HuffmanTree* items, const size_t n, HuffmanTreeComparator comparator) { - static const size_t gaps[] = {132, 57, 23, 10, 4, 1}; if (n < 13) { /* Insertion sort. */ size_t i; @@ -101,7 +101,7 @@ static BROTLI_INLINE void SortHuffmanTreeItems(HuffmanTree* items, /* Shell sort. */ int g = n < 57 ? 2 : 0; for (; g < 6; ++g) { - size_t gap = gaps[g]; + size_t gap = kBrotliShellGaps[g]; size_t i; for (i = gap; i < n; ++i) { size_t j = i; diff --git a/modules/brotli/enc/fast_log.c b/modules/brotli/enc/fast_log.c new file mode 100644 index 0000000000..2319baeb74 --- /dev/null +++ b/modules/brotli/enc/fast_log.c @@ -0,0 +1,105 @@ +/* Copyright 2013 Google Inc. All Rights Reserved. + + Distributed under MIT license. + See file LICENSE for detail or copy at https://opensource.org/licenses/MIT +*/ + +#include "./fast_log.h" + +#if defined(__cplusplus) || defined(c_plusplus) +extern "C" { +#endif + +/* ", ".join(["%.16ff" % x for x in [0.0]+[log2(x) for x in range(1, 256)]]) */ +const double kBrotliLog2Table[BROTLI_LOG2_TABLE_SIZE] = { + 0.0000000000000000f, 0.0000000000000000f, 1.0000000000000000f, + 1.5849625007211563f, 2.0000000000000000f, 2.3219280948873622f, + 2.5849625007211561f, 2.8073549220576042f, 3.0000000000000000f, + 3.1699250014423126f, 3.3219280948873626f, 3.4594316186372978f, + 3.5849625007211565f, 3.7004397181410922f, 3.8073549220576037f, + 3.9068905956085187f, 4.0000000000000000f, 4.0874628412503400f, + 4.1699250014423122f, 4.2479275134435852f, 4.3219280948873626f, + 4.3923174227787607f, 4.4594316186372973f, 4.5235619560570131f, + 4.5849625007211570f, 4.6438561897747244f, 4.7004397181410926f, + 4.7548875021634691f, 4.8073549220576037f, 4.8579809951275728f, + 4.9068905956085187f, 4.9541963103868758f, 5.0000000000000000f, + 5.0443941193584534f, 5.0874628412503400f, 5.1292830169449664f, + 5.1699250014423122f, 5.2094533656289501f, 5.2479275134435852f, + 5.2854022188622487f, 5.3219280948873626f, 5.3575520046180838f, + 5.3923174227787607f, 5.4262647547020979f, 5.4594316186372973f, + 5.4918530963296748f, 5.5235619560570131f, 5.5545888516776376f, + 5.5849625007211570f, 5.6147098441152083f, 5.6438561897747244f, + 5.6724253419714961f, 5.7004397181410926f, 5.7279204545631996f, + 5.7548875021634691f, 5.7813597135246599f, 5.8073549220576046f, + 5.8328900141647422f, 5.8579809951275719f, 5.8826430493618416f, + 5.9068905956085187f, 5.9307373375628867f, 5.9541963103868758f, + 5.9772799234999168f, 6.0000000000000000f, 6.0223678130284544f, + 6.0443941193584534f, 6.0660891904577721f, 6.0874628412503400f, + 6.1085244567781700f, 6.1292830169449672f, 6.1497471195046822f, + 6.1699250014423122f, 6.1898245588800176f, 6.2094533656289510f, + 6.2288186904958804f, 6.2479275134435861f, 6.2667865406949019f, + 6.2854022188622487f, 6.3037807481771031f, 6.3219280948873617f, + 6.3398500028846252f, 6.3575520046180847f, 6.3750394313469254f, + 6.3923174227787598f, 6.4093909361377026f, 6.4262647547020979f, + 6.4429434958487288f, 6.4594316186372982f, 6.4757334309663976f, + 6.4918530963296748f, 6.5077946401986964f, 6.5235619560570131f, + 6.5391588111080319f, 6.5545888516776376f, 6.5698556083309478f, + 6.5849625007211561f, 6.5999128421871278f, 6.6147098441152092f, + 6.6293566200796095f, 6.6438561897747253f, 6.6582114827517955f, + 6.6724253419714952f, 6.6865005271832185f, 6.7004397181410917f, + 6.7142455176661224f, 6.7279204545631988f, 6.7414669864011465f, + 6.7548875021634691f, 6.7681843247769260f, 6.7813597135246599f, + 6.7944158663501062f, 6.8073549220576037f, 6.8201789624151887f, + 6.8328900141647422f, 6.8454900509443757f, 6.8579809951275719f, + 6.8703647195834048f, 6.8826430493618416f, 6.8948177633079437f, + 6.9068905956085187f, 6.9188632372745955f, 6.9307373375628867f, + 6.9425145053392399f, 6.9541963103868758f, 6.9657842846620879f, + 6.9772799234999168f, 6.9886846867721664f, 7.0000000000000000f, + 7.0112272554232540f, 7.0223678130284544f, 7.0334230015374501f, + 7.0443941193584534f, 7.0552824355011898f, 7.0660891904577721f, + 7.0768155970508317f, 7.0874628412503400f, 7.0980320829605272f, + 7.1085244567781700f, 7.1189410727235076f, 7.1292830169449664f, + 7.1395513523987937f, 7.1497471195046822f, 7.1598713367783891f, + 7.1699250014423130f, 7.1799090900149345f, 7.1898245588800176f, + 7.1996723448363644f, 7.2094533656289492f, 7.2191685204621621f, + 7.2288186904958804f, 7.2384047393250794f, 7.2479275134435861f, + 7.2573878426926521f, 7.2667865406949019f, 7.2761244052742384f, + 7.2854022188622487f, 7.2946207488916270f, 7.3037807481771031f, + 7.3128829552843557f, 7.3219280948873617f, 7.3309168781146177f, + 7.3398500028846243f, 7.3487281542310781f, 7.3575520046180847f, + 7.3663222142458151f, 7.3750394313469254f, 7.3837042924740528f, + 7.3923174227787607f, 7.4008794362821844f, 7.4093909361377026f, + 7.4178525148858991f, 7.4262647547020979f, 7.4346282276367255f, + 7.4429434958487288f, 7.4512111118323299f, 7.4594316186372973f, + 7.4676055500829976f, 7.4757334309663976f, 7.4838157772642564f, + 7.4918530963296748f, 7.4998458870832057f, 7.5077946401986964f, + 7.5156998382840436f, 7.5235619560570131f, 7.5313814605163119f, + 7.5391588111080319f, 7.5468944598876373f, 7.5545888516776376f, + 7.5622424242210728f, 7.5698556083309478f, 7.5774288280357487f, + 7.5849625007211561f, 7.5924570372680806f, 7.5999128421871278f, + 7.6073303137496113f, 7.6147098441152075f, 7.6220518194563764f, + 7.6293566200796095f, 7.6366246205436488f, 7.6438561897747244f, + 7.6510516911789290f, 7.6582114827517955f, 7.6653359171851765f, + 7.6724253419714952f, 7.6794800995054464f, 7.6865005271832185f, + 7.6934869574993252f, 7.7004397181410926f, 7.7073591320808825f, + 7.7142455176661224f, 7.7210991887071856f, 7.7279204545631996f, + 7.7347096202258392f, 7.7414669864011465f, 7.7481928495894596f, + 7.7548875021634691f, 7.7615512324444795f, 7.7681843247769260f, + 7.7747870596011737f, 7.7813597135246608f, 7.7879025593914317f, + 7.7944158663501062f, 7.8008998999203047f, 7.8073549220576037f, + 7.8137811912170374f, 7.8201789624151887f, 7.8265484872909159f, + 7.8328900141647422f, 7.8392037880969445f, 7.8454900509443757f, + 7.8517490414160571f, 7.8579809951275719f, 7.8641861446542798f, + 7.8703647195834048f, 7.8765169465650002f, 7.8826430493618425f, + 7.8887432488982601f, 7.8948177633079446f, 7.9008668079807496f, + 7.9068905956085187f, 7.9128893362299619f, 7.9188632372745955f, + 7.9248125036057813f, 7.9307373375628867f, 7.9366379390025719f, + 7.9425145053392399f, 7.9483672315846778f, 7.9541963103868758f, + 7.9600019320680806f, 7.9657842846620870f, 7.9715435539507720f, + 7.9772799234999168f, 7.9829935746943104f, 7.9886846867721664f, + 7.9943534368588578f +}; + +#if defined(__cplusplus) || defined(c_plusplus) +} /* extern "C" */ +#endif diff --git a/modules/brotli/enc/fast_log.h b/modules/brotli/enc/fast_log.h index cade1235ad..2094f13e55 100644 --- a/modules/brotli/enc/fast_log.h +++ b/modules/brotli/enc/fast_log.h @@ -19,10 +19,8 @@ extern "C" { #endif static BROTLI_INLINE uint32_t Log2FloorNonZero(size_t n) { - /* TODO: generalize and move to platform.h */ -#if BROTLI_GNUC_HAS_BUILTIN(__builtin_clz, 3, 4, 0) || \ - BROTLI_INTEL_VERSION_CHECK(16, 0, 0) - return 31u ^ (uint32_t)__builtin_clz((uint32_t)n); +#if defined(BROTLI_BSR32) + return BROTLI_BSR32((uint32_t)n); #else uint32_t result = 0; while (n >>= 1) result++; @@ -30,110 +28,31 @@ static BROTLI_INLINE uint32_t Log2FloorNonZero(size_t n) { #endif } -/* A lookup table for small values of log2(int) to be used in entropy - computation. +#define BROTLI_LOG2_TABLE_SIZE 256 - ", ".join(["%.16ff" % x for x in [0.0]+[log2(x) for x in range(1, 256)]]) */ -static const float kLog2Table[] = { - 0.0000000000000000f, 0.0000000000000000f, 1.0000000000000000f, - 1.5849625007211563f, 2.0000000000000000f, 2.3219280948873622f, - 2.5849625007211561f, 2.8073549220576042f, 3.0000000000000000f, - 3.1699250014423126f, 3.3219280948873626f, 3.4594316186372978f, - 3.5849625007211565f, 3.7004397181410922f, 3.8073549220576037f, - 3.9068905956085187f, 4.0000000000000000f, 4.0874628412503400f, - 4.1699250014423122f, 4.2479275134435852f, 4.3219280948873626f, - 4.3923174227787607f, 4.4594316186372973f, 4.5235619560570131f, - 4.5849625007211570f, 4.6438561897747244f, 4.7004397181410926f, - 4.7548875021634691f, 4.8073549220576037f, 4.8579809951275728f, - 4.9068905956085187f, 4.9541963103868758f, 5.0000000000000000f, - 5.0443941193584534f, 5.0874628412503400f, 5.1292830169449664f, - 5.1699250014423122f, 5.2094533656289501f, 5.2479275134435852f, - 5.2854022188622487f, 5.3219280948873626f, 5.3575520046180838f, - 5.3923174227787607f, 5.4262647547020979f, 5.4594316186372973f, - 5.4918530963296748f, 5.5235619560570131f, 5.5545888516776376f, - 5.5849625007211570f, 5.6147098441152083f, 5.6438561897747244f, - 5.6724253419714961f, 5.7004397181410926f, 5.7279204545631996f, - 5.7548875021634691f, 5.7813597135246599f, 5.8073549220576046f, - 5.8328900141647422f, 5.8579809951275719f, 5.8826430493618416f, - 5.9068905956085187f, 5.9307373375628867f, 5.9541963103868758f, - 5.9772799234999168f, 6.0000000000000000f, 6.0223678130284544f, - 6.0443941193584534f, 6.0660891904577721f, 6.0874628412503400f, - 6.1085244567781700f, 6.1292830169449672f, 6.1497471195046822f, - 6.1699250014423122f, 6.1898245588800176f, 6.2094533656289510f, - 6.2288186904958804f, 6.2479275134435861f, 6.2667865406949019f, - 6.2854022188622487f, 6.3037807481771031f, 6.3219280948873617f, - 6.3398500028846252f, 6.3575520046180847f, 6.3750394313469254f, - 6.3923174227787598f, 6.4093909361377026f, 6.4262647547020979f, - 6.4429434958487288f, 6.4594316186372982f, 6.4757334309663976f, - 6.4918530963296748f, 6.5077946401986964f, 6.5235619560570131f, - 6.5391588111080319f, 6.5545888516776376f, 6.5698556083309478f, - 6.5849625007211561f, 6.5999128421871278f, 6.6147098441152092f, - 6.6293566200796095f, 6.6438561897747253f, 6.6582114827517955f, - 6.6724253419714952f, 6.6865005271832185f, 6.7004397181410917f, - 6.7142455176661224f, 6.7279204545631988f, 6.7414669864011465f, - 6.7548875021634691f, 6.7681843247769260f, 6.7813597135246599f, - 6.7944158663501062f, 6.8073549220576037f, 6.8201789624151887f, - 6.8328900141647422f, 6.8454900509443757f, 6.8579809951275719f, - 6.8703647195834048f, 6.8826430493618416f, 6.8948177633079437f, - 6.9068905956085187f, 6.9188632372745955f, 6.9307373375628867f, - 6.9425145053392399f, 6.9541963103868758f, 6.9657842846620879f, - 6.9772799234999168f, 6.9886846867721664f, 7.0000000000000000f, - 7.0112272554232540f, 7.0223678130284544f, 7.0334230015374501f, - 7.0443941193584534f, 7.0552824355011898f, 7.0660891904577721f, - 7.0768155970508317f, 7.0874628412503400f, 7.0980320829605272f, - 7.1085244567781700f, 7.1189410727235076f, 7.1292830169449664f, - 7.1395513523987937f, 7.1497471195046822f, 7.1598713367783891f, - 7.1699250014423130f, 7.1799090900149345f, 7.1898245588800176f, - 7.1996723448363644f, 7.2094533656289492f, 7.2191685204621621f, - 7.2288186904958804f, 7.2384047393250794f, 7.2479275134435861f, - 7.2573878426926521f, 7.2667865406949019f, 7.2761244052742384f, - 7.2854022188622487f, 7.2946207488916270f, 7.3037807481771031f, - 7.3128829552843557f, 7.3219280948873617f, 7.3309168781146177f, - 7.3398500028846243f, 7.3487281542310781f, 7.3575520046180847f, - 7.3663222142458151f, 7.3750394313469254f, 7.3837042924740528f, - 7.3923174227787607f, 7.4008794362821844f, 7.4093909361377026f, - 7.4178525148858991f, 7.4262647547020979f, 7.4346282276367255f, - 7.4429434958487288f, 7.4512111118323299f, 7.4594316186372973f, - 7.4676055500829976f, 7.4757334309663976f, 7.4838157772642564f, - 7.4918530963296748f, 7.4998458870832057f, 7.5077946401986964f, - 7.5156998382840436f, 7.5235619560570131f, 7.5313814605163119f, - 7.5391588111080319f, 7.5468944598876373f, 7.5545888516776376f, - 7.5622424242210728f, 7.5698556083309478f, 7.5774288280357487f, - 7.5849625007211561f, 7.5924570372680806f, 7.5999128421871278f, - 7.6073303137496113f, 7.6147098441152075f, 7.6220518194563764f, - 7.6293566200796095f, 7.6366246205436488f, 7.6438561897747244f, - 7.6510516911789290f, 7.6582114827517955f, 7.6653359171851765f, - 7.6724253419714952f, 7.6794800995054464f, 7.6865005271832185f, - 7.6934869574993252f, 7.7004397181410926f, 7.7073591320808825f, - 7.7142455176661224f, 7.7210991887071856f, 7.7279204545631996f, - 7.7347096202258392f, 7.7414669864011465f, 7.7481928495894596f, - 7.7548875021634691f, 7.7615512324444795f, 7.7681843247769260f, - 7.7747870596011737f, 7.7813597135246608f, 7.7879025593914317f, - 7.7944158663501062f, 7.8008998999203047f, 7.8073549220576037f, - 7.8137811912170374f, 7.8201789624151887f, 7.8265484872909159f, - 7.8328900141647422f, 7.8392037880969445f, 7.8454900509443757f, - 7.8517490414160571f, 7.8579809951275719f, 7.8641861446542798f, - 7.8703647195834048f, 7.8765169465650002f, 7.8826430493618425f, - 7.8887432488982601f, 7.8948177633079446f, 7.9008668079807496f, - 7.9068905956085187f, 7.9128893362299619f, 7.9188632372745955f, - 7.9248125036057813f, 7.9307373375628867f, 7.9366379390025719f, - 7.9425145053392399f, 7.9483672315846778f, 7.9541963103868758f, - 7.9600019320680806f, 7.9657842846620870f, 7.9715435539507720f, - 7.9772799234999168f, 7.9829935746943104f, 7.9886846867721664f, - 7.9943534368588578f -}; +/* A lookup table for small values of log2(int) to be used in entropy + computation. */ +BROTLI_INTERNAL extern const double kBrotliLog2Table[BROTLI_LOG2_TABLE_SIZE]; + +/* Visual Studio 2012 and Android API levels < 18 do not have the log2() + * function defined, so we use log() and a multiplication instead. */ +#if !defined(BROTLI_HAVE_LOG2) +#if ((defined(_MSC_VER) && _MSC_VER <= 1700) || \ + (defined(__ANDROID_API__) && __ANDROID_API__ < 18)) +#define BROTLI_HAVE_LOG2 0 +#else +#define BROTLI_HAVE_LOG2 1 +#endif +#endif #define LOG_2_INV 1.4426950408889634 /* Faster logarithm for small integers, with the property of log2(0) == 0. */ static BROTLI_INLINE double FastLog2(size_t v) { - if (v < sizeof(kLog2Table) / sizeof(kLog2Table[0])) { - return kLog2Table[v]; + if (v < BROTLI_LOG2_TABLE_SIZE) { + return kBrotliLog2Table[v]; } -#if (defined(_MSC_VER) && _MSC_VER <= 1700) || \ - (defined(__ANDROID_API__) && __ANDROID_API__ < 18) - /* Visual Studio 2012 and Android API levels < 18 do not have the log2() - * function defined, so we use log() and a multiplication instead. */ +#if !(BROTLI_HAVE_LOG2) return log((double)v) * LOG_2_INV; #else return log2((double)v); diff --git a/modules/brotli/enc/find_match_length.h b/modules/brotli/enc/find_match_length.h index bc428cffda..f8853a70fb 100644 --- a/modules/brotli/enc/find_match_length.h +++ b/modules/brotli/enc/find_match_length.h @@ -17,8 +17,7 @@ extern "C" { #endif /* Separate implementation for little-endian 64-bit targets, for speed. */ -#if defined(__GNUC__) && defined(_LP64) && defined(BROTLI_LITTLE_ENDIAN) - +#if defined(BROTLI_TZCNT64) && BROTLI_64_BITS && BROTLI_LITTLE_ENDIAN static BROTLI_INLINE size_t FindMatchLengthWithLimit(const uint8_t* s1, const uint8_t* s2, size_t limit) { @@ -32,7 +31,7 @@ static BROTLI_INLINE size_t FindMatchLengthWithLimit(const uint8_t* s1, } else { uint64_t x = BROTLI_UNALIGNED_LOAD64LE(s2) ^ BROTLI_UNALIGNED_LOAD64LE(s1 + matched); - size_t matching_bits = (size_t)__builtin_ctzll(x); + size_t matching_bits = (size_t)BROTLI_TZCNT64(x); matched += matching_bits >> 3; return matched; } diff --git a/modules/brotli/enc/hash.h b/modules/brotli/enc/hash.h index 8c5a7bb5ad..6362f69b9f 100644 --- a/modules/brotli/enc/hash.h +++ b/modules/brotli/enc/hash.h @@ -27,34 +27,19 @@ extern "C" { #endif -/* Pointer to hasher data. - * - * Excluding initialization and destruction, hasher can be passed as - * HasherHandle by value. - * - * Typically hasher data consists of 3 sections: - * * HasherCommon structure - * * private structured hasher data, depending on hasher type - * * private dynamic hasher data, depending on hasher type and parameters - * - * Using "define" instead of "typedef", because on MSVC __restrict does not work - * on typedef pointer types. */ -#define HasherHandle uint8_t* - typedef struct { + /* Dynamically allocated area; first member for quickest access. */ + void* extra; + + size_t dict_num_lookups; + size_t dict_num_matches; + BrotliHasherParams params; /* False if hasher needs to be "prepared" before use. */ BROTLI_BOOL is_prepared_; - - size_t dict_num_lookups; - size_t dict_num_matches; } HasherCommon; -static BROTLI_INLINE HasherCommon* GetHasherCommon(HasherHandle handle) { - return (HasherCommon*)handle; -} - #define score_t size_t static const uint32_t kCutoffTransformsCount = 10; @@ -149,17 +134,13 @@ static BROTLI_INLINE score_t BackwardReferencePenaltyUsingLastDistance( } static BROTLI_INLINE BROTLI_BOOL TestStaticDictionaryItem( - const BrotliEncoderDictionary* dictionary, size_t item, + const BrotliEncoderDictionary* dictionary, size_t len, size_t word_idx, const uint8_t* data, size_t max_length, size_t max_backward, size_t max_distance, HasherSearchResult* out) { - size_t len; - size_t word_idx; size_t offset; size_t matchlen; size_t backward; score_t score; - len = item & 0x1F; - word_idx = item >> 5; offset = dictionary->words->offsets_by_length[len] + len * word_idx; if (len > max_length) { return BROTLI_FALSE; @@ -193,25 +174,24 @@ static BROTLI_INLINE BROTLI_BOOL TestStaticDictionaryItem( static BROTLI_INLINE void SearchInStaticDictionary( const BrotliEncoderDictionary* dictionary, - HasherHandle handle, const uint8_t* data, size_t max_length, + HasherCommon* common, const uint8_t* data, size_t max_length, size_t max_backward, size_t max_distance, HasherSearchResult* out, BROTLI_BOOL shallow) { size_t key; size_t i; - HasherCommon* self = GetHasherCommon(handle); - if (self->dict_num_matches < (self->dict_num_lookups >> 7)) { + if (common->dict_num_matches < (common->dict_num_lookups >> 7)) { return; } key = Hash14(data) << 1; for (i = 0; i < (shallow ? 1u : 2u); ++i, ++key) { - size_t item = dictionary->hash_table[key]; - self->dict_num_lookups++; - if (item != 0) { + common->dict_num_lookups++; + if (dictionary->hash_table_lengths[key] != 0) { BROTLI_BOOL item_matches = TestStaticDictionaryItem( - dictionary, item, data, + dictionary, dictionary->hash_table_lengths[key], + dictionary->hash_table_words[key], data, max_length, max_backward, max_distance, out); if (item_matches) { - self->dict_num_matches++; + common->dict_num_matches++; } } } @@ -260,37 +240,37 @@ static BROTLI_INLINE size_t BackwardMatchLengthCode(const BackwardMatch* self) { /* MAX_NUM_MATCHES == 64 + MAX_TREE_SEARCH_DEPTH */ #define MAX_NUM_MATCHES_H10 128 -/* For BUCKET_SWEEP == 1, enabling the dictionary lookup makes compression +/* For BUCKET_SWEEP_BITS == 0, enabling the dictionary lookup makes compression a little faster (0.5% - 1%) and it compresses 0.15% better on small text and HTML inputs. */ #define HASHER() H2 #define BUCKET_BITS 16 -#define BUCKET_SWEEP 1 +#define BUCKET_SWEEP_BITS 0 #define HASH_LEN 5 #define USE_DICTIONARY 1 #include "./hash_longest_match_quickly_inc.h" /* NOLINT(build/include) */ -#undef BUCKET_SWEEP +#undef BUCKET_SWEEP_BITS #undef USE_DICTIONARY #undef HASHER #define HASHER() H3 -#define BUCKET_SWEEP 2 +#define BUCKET_SWEEP_BITS 1 #define USE_DICTIONARY 0 #include "./hash_longest_match_quickly_inc.h" /* NOLINT(build/include) */ #undef USE_DICTIONARY -#undef BUCKET_SWEEP +#undef BUCKET_SWEEP_BITS #undef BUCKET_BITS #undef HASHER #define HASHER() H4 #define BUCKET_BITS 17 -#define BUCKET_SWEEP 4 +#define BUCKET_SWEEP_BITS 2 #define USE_DICTIONARY 1 #include "./hash_longest_match_quickly_inc.h" /* NOLINT(build/include) */ #undef USE_DICTIONARY #undef HASH_LEN -#undef BUCKET_SWEEP +#undef BUCKET_SWEEP_BITS #undef BUCKET_BITS #undef HASHER @@ -334,13 +314,13 @@ static BROTLI_INLINE size_t BackwardMatchLengthCode(const BackwardMatch* self) { #define HASHER() H54 #define BUCKET_BITS 20 -#define BUCKET_SWEEP 4 +#define BUCKET_SWEEP_BITS 2 #define HASH_LEN 7 #define USE_DICTIONARY 0 #include "./hash_longest_match_quickly_inc.h" /* NOLINT(build/include) */ #undef USE_DICTIONARY #undef HASH_LEN -#undef BUCKET_SWEEP +#undef BUCKET_SWEEP_BITS #undef BUCKET_BITS #undef HASHER @@ -393,97 +373,107 @@ static BROTLI_INLINE size_t BackwardMatchLengthCode(const BackwardMatch* self) { #undef CAT #undef EXPAND_CAT -#define FOR_GENERIC_HASHERS(H) H(2) H(3) H(4) H(5) H(6) H(40) H(41) H(42) H(54)\ - H(35) H(55) H(65) +#define FOR_SIMPLE_HASHERS(H) H(2) H(3) H(4) H(5) H(6) H(40) H(41) H(42) H(54) +#define FOR_COMPOSITE_HASHERS(H) H(35) H(55) H(65) +#define FOR_GENERIC_HASHERS(H) FOR_SIMPLE_HASHERS(H) FOR_COMPOSITE_HASHERS(H) #define FOR_ALL_HASHERS(H) FOR_GENERIC_HASHERS(H) H(10) -static BROTLI_INLINE void DestroyHasher( - MemoryManager* m, HasherHandle* handle) { - if (*handle == NULL) return; - BROTLI_FREE(m, *handle); +typedef struct { + HasherCommon common; + + union { +#define MEMBER_(N) \ + H ## N _H ## N; + FOR_ALL_HASHERS(MEMBER_) +#undef MEMBER_ + } privat; +} Hasher; + +/* MUST be invoked before any other method. */ +static BROTLI_INLINE void HasherInit(Hasher* hasher) { + hasher->common.extra = NULL; } -static BROTLI_INLINE void HasherReset(HasherHandle handle) { - if (handle == NULL) return; - GetHasherCommon(handle)->is_prepared_ = BROTLI_FALSE; +static BROTLI_INLINE void DestroyHasher(MemoryManager* m, Hasher* hasher) { + if (hasher->common.extra == NULL) return; + BROTLI_FREE(m, hasher->common.extra); +} + +static BROTLI_INLINE void HasherReset(Hasher* hasher) { + hasher->common.is_prepared_ = BROTLI_FALSE; } static BROTLI_INLINE size_t HasherSize(const BrotliEncoderParams* params, BROTLI_BOOL one_shot, const size_t input_size) { - size_t result = sizeof(HasherCommon); switch (params->hasher.type) { -#define SIZE_(N) \ - case N: \ - result += HashMemAllocInBytesH ## N(params, one_shot, input_size); \ - break; +#define SIZE_(N) \ + case N: \ + return HashMemAllocInBytesH ## N(params, one_shot, input_size); FOR_ALL_HASHERS(SIZE_) #undef SIZE_ default: break; } - return result; + return 0; /* Default case. */ } -static BROTLI_INLINE void HasherSetup(MemoryManager* m, HasherHandle* handle, +static BROTLI_INLINE void HasherSetup(MemoryManager* m, Hasher* hasher, BrotliEncoderParams* params, const uint8_t* data, size_t position, size_t input_size, BROTLI_BOOL is_last) { - HasherHandle self = NULL; - HasherCommon* common = NULL; BROTLI_BOOL one_shot = (position == 0 && is_last); - if (*handle == NULL) { + if (hasher->common.extra == NULL) { size_t alloc_size; ChooseHasher(params, ¶ms->hasher); alloc_size = HasherSize(params, one_shot, input_size); - self = BROTLI_ALLOC(m, uint8_t, alloc_size); - if (BROTLI_IS_OOM(m)) return; - *handle = self; - common = GetHasherCommon(self); - common->params = params->hasher; - switch (common->params.type) { -#define INITIALIZE_(N) \ - case N: \ - InitializeH ## N(*handle, params); \ + hasher->common.extra = BROTLI_ALLOC(m, uint8_t, alloc_size); + if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(hasher->common.extra)) return; + hasher->common.params = params->hasher; + switch (hasher->common.params.type) { +#define INITIALIZE_(N) \ + case N: \ + InitializeH ## N(&hasher->common, \ + &hasher->privat._H ## N, params); \ break; FOR_ALL_HASHERS(INITIALIZE_); #undef INITIALIZE_ default: break; } - HasherReset(*handle); + HasherReset(hasher); } - self = *handle; - common = GetHasherCommon(self); - if (!common->is_prepared_) { - switch (common->params.type) { -#define PREPARE_(N) \ - case N: \ - PrepareH ## N(self, one_shot, input_size, data); \ + if (!hasher->common.is_prepared_) { + switch (hasher->common.params.type) { +#define PREPARE_(N) \ + case N: \ + PrepareH ## N( \ + &hasher->privat._H ## N, \ + one_shot, input_size, data); \ break; FOR_ALL_HASHERS(PREPARE_) #undef PREPARE_ default: break; } if (position == 0) { - common->dict_num_lookups = 0; - common->dict_num_matches = 0; + hasher->common.dict_num_lookups = 0; + hasher->common.dict_num_matches = 0; } - common->is_prepared_ = BROTLI_TRUE; + hasher->common.is_prepared_ = BROTLI_TRUE; } } static BROTLI_INLINE void InitOrStitchToPreviousBlock( - MemoryManager* m, HasherHandle* handle, const uint8_t* data, size_t mask, + MemoryManager* m, Hasher* hasher, const uint8_t* data, size_t mask, BrotliEncoderParams* params, size_t position, size_t input_size, BROTLI_BOOL is_last) { - HasherHandle self; - HasherSetup(m, handle, params, data, position, input_size, is_last); + HasherSetup(m, hasher, params, data, position, input_size, is_last); if (BROTLI_IS_OOM(m)) return; - self = *handle; - switch (GetHasherCommon(self)->params.type) { -#define INIT_(N) \ - case N: \ - StitchToPreviousBlockH ## N(self, input_size, position, data, mask); \ + switch (hasher->common.params.type) { +#define INIT_(N) \ + case N: \ + StitchToPreviousBlockH ## N( \ + &hasher->privat._H ## N, \ + input_size, position, data, mask); \ break; FOR_ALL_HASHERS(INIT_) #undef INIT_ diff --git a/modules/brotli/enc/hash_composite_inc.h b/modules/brotli/enc/hash_composite_inc.h index b266aa2f8d..cba156c0e2 100644 --- a/modules/brotli/enc/hash_composite_inc.h +++ b/modules/brotli/enc/hash_composite_inc.h @@ -28,20 +28,25 @@ static BROTLI_INLINE size_t FN(StoreLookahead)(void) { } typedef struct HashComposite { - HasherHandle ha; - HasherHandle hb; + HASHER_A ha; + HASHER_B hb; + HasherCommon hb_common; + + /* Shortcuts. */ + void* extra; + HasherCommon* common; + + BROTLI_BOOL fresh; const BrotliEncoderParams* params; } HashComposite; -static BROTLI_INLINE HashComposite* FN(Self)(HasherHandle handle) { - return (HashComposite*)&(GetHasherCommon(handle)[1]); -} +static void FN(Initialize)(HasherCommon* common, + HashComposite* BROTLI_RESTRICT self, const BrotliEncoderParams* params) { + self->common = common; + self->extra = common->extra; -static void FN(Initialize)( - HasherHandle handle, const BrotliEncoderParams* params) { - HashComposite* self = FN(Self)(handle); - self->ha = 0; - self->hb = 0; + self->hb_common = *self->common; + self->fresh = BROTLI_TRUE; self->params = params; /* TODO: Initialize of the hashers is defered to Prepare (and params remembered here) because we don't get the one_shot and input_size params @@ -49,87 +54,71 @@ static void FN(Initialize)( those params to all hashers FN(Initialize) */ } -static void FN(Prepare)(HasherHandle handle, BROTLI_BOOL one_shot, - size_t input_size, const uint8_t* data) { - HashComposite* self = FN(Self)(handle); - if (!self->ha) { - HasherCommon* common_a; - HasherCommon* common_b; +static void FN(Prepare)( + HashComposite* BROTLI_RESTRICT self, BROTLI_BOOL one_shot, + size_t input_size, const uint8_t* BROTLI_RESTRICT data) { + if (self->fresh) { + self->fresh = BROTLI_FALSE; + self->hb_common.extra = (uint8_t*)self->extra + + FN_A(HashMemAllocInBytes)(self->params, one_shot, input_size); - self->ha = handle + sizeof(HasherCommon) + sizeof(HashComposite); - common_a = (HasherCommon*)self->ha; - common_a->params = self->params->hasher; - common_a->is_prepared_ = BROTLI_FALSE; - common_a->dict_num_lookups = 0; - common_a->dict_num_matches = 0; - FN_A(Initialize)(self->ha, self->params); - - self->hb = self->ha + sizeof(HasherCommon) + FN_A(HashMemAllocInBytes)( - self->params, one_shot, input_size); - common_b = (HasherCommon*)self->hb; - common_b->params = self->params->hasher; - common_b->is_prepared_ = BROTLI_FALSE; - common_b->dict_num_lookups = 0; - common_b->dict_num_matches = 0; - FN_B(Initialize)(self->hb, self->params); + FN_A(Initialize)(self->common, &self->ha, self->params); + FN_B(Initialize)(&self->hb_common, &self->hb, self->params); } - FN_A(Prepare)(self->ha, one_shot, input_size, data); - FN_B(Prepare)(self->hb, one_shot, input_size, data); + FN_A(Prepare)(&self->ha, one_shot, input_size, data); + FN_B(Prepare)(&self->hb, one_shot, input_size, data); } static BROTLI_INLINE size_t FN(HashMemAllocInBytes)( const BrotliEncoderParams* params, BROTLI_BOOL one_shot, size_t input_size) { - return sizeof(HashComposite) + 2 * sizeof(HasherCommon) + - FN_A(HashMemAllocInBytes)(params, one_shot, input_size) + + return FN_A(HashMemAllocInBytes)(params, one_shot, input_size) + FN_B(HashMemAllocInBytes)(params, one_shot, input_size); } -static BROTLI_INLINE void FN(Store)(HasherHandle BROTLI_RESTRICT handle, +static BROTLI_INLINE void FN(Store)(HashComposite* BROTLI_RESTRICT self, const uint8_t* BROTLI_RESTRICT data, const size_t mask, const size_t ix) { - HashComposite* self = FN(Self)(handle); - FN_A(Store)(self->ha, data, mask, ix); - FN_B(Store)(self->hb, data, mask, ix); + FN_A(Store)(&self->ha, data, mask, ix); + FN_B(Store)(&self->hb, data, mask, ix); } -static BROTLI_INLINE void FN(StoreRange)(HasherHandle handle, - const uint8_t* data, const size_t mask, const size_t ix_start, +static BROTLI_INLINE void FN(StoreRange)( + HashComposite* BROTLI_RESTRICT self, const uint8_t* BROTLI_RESTRICT data, + const size_t mask, const size_t ix_start, const size_t ix_end) { - HashComposite* self = FN(Self)(handle); - FN_A(StoreRange)(self->ha, data, mask, ix_start, ix_end); - FN_B(StoreRange)(self->hb, data, mask, ix_start, ix_end); + FN_A(StoreRange)(&self->ha, data, mask, ix_start, ix_end); + FN_B(StoreRange)(&self->hb, data, mask, ix_start, ix_end); } -static BROTLI_INLINE void FN(StitchToPreviousBlock)(HasherHandle handle, +static BROTLI_INLINE void FN(StitchToPreviousBlock)( + HashComposite* BROTLI_RESTRICT self, size_t num_bytes, size_t position, const uint8_t* ringbuffer, size_t ring_buffer_mask) { - HashComposite* self = FN(Self)(handle); - FN_A(StitchToPreviousBlock)(self->ha, num_bytes, position, ringbuffer, - ring_buffer_mask); - FN_B(StitchToPreviousBlock)(self->hb, num_bytes, position, ringbuffer, - ring_buffer_mask); + FN_A(StitchToPreviousBlock)(&self->ha, num_bytes, position, + ringbuffer, ring_buffer_mask); + FN_B(StitchToPreviousBlock)(&self->hb, num_bytes, position, + ringbuffer, ring_buffer_mask); } static BROTLI_INLINE void FN(PrepareDistanceCache)( - HasherHandle handle, int* BROTLI_RESTRICT distance_cache) { - HashComposite* self = FN(Self)(handle); - FN_A(PrepareDistanceCache)(self->ha, distance_cache); - FN_B(PrepareDistanceCache)(self->hb, distance_cache); + HashComposite* BROTLI_RESTRICT self, int* BROTLI_RESTRICT distance_cache) { + FN_A(PrepareDistanceCache)(&self->ha, distance_cache); + FN_B(PrepareDistanceCache)(&self->hb, distance_cache); } -static BROTLI_INLINE void FN(FindLongestMatch)(HasherHandle handle, +static BROTLI_INLINE void FN(FindLongestMatch)( + HashComposite* BROTLI_RESTRICT self, const BrotliEncoderDictionary* dictionary, const uint8_t* BROTLI_RESTRICT data, const size_t ring_buffer_mask, const int* BROTLI_RESTRICT distance_cache, const size_t cur_ix, const size_t max_length, const size_t max_backward, - const size_t gap, const size_t max_distance, + const size_t dictionary_distance, const size_t max_distance, HasherSearchResult* BROTLI_RESTRICT out) { - HashComposite* self = FN(Self)(handle); - FN_A(FindLongestMatch)(self->ha, dictionary, data, ring_buffer_mask, - distance_cache, cur_ix, max_length, max_backward, gap, + FN_A(FindLongestMatch)(&self->ha, dictionary, data, ring_buffer_mask, + distance_cache, cur_ix, max_length, max_backward, dictionary_distance, max_distance, out); - FN_B(FindLongestMatch)(self->hb, dictionary, data, ring_buffer_mask, - distance_cache, cur_ix, max_length, max_backward, gap, + FN_B(FindLongestMatch)(&self->hb, dictionary, data, ring_buffer_mask, + distance_cache, cur_ix, max_length, max_backward, dictionary_distance, max_distance, out); } diff --git a/modules/brotli/enc/hash_forgetful_chain_inc.h b/modules/brotli/enc/hash_forgetful_chain_inc.h index 41cb3ff03a..bfae6ba6a2 100644 --- a/modules/brotli/enc/hash_forgetful_chain_inc.h +++ b/modules/brotli/enc/hash_forgetful_chain_inc.h @@ -28,7 +28,7 @@ static BROTLI_INLINE size_t FN(HashTypeLength)(void) { return 4; } static BROTLI_INLINE size_t FN(StoreLookahead)(void) { return 4; } /* HashBytes is the function that chooses the bucket to place the address in.*/ -static BROTLI_INLINE size_t FN(HashBytes)(const uint8_t* data) { +static BROTLI_INLINE size_t FN(HashBytes)(const uint8_t* BROTLI_RESTRICT data) { const uint32_t h = BROTLI_UNALIGNED_LOAD32LE(data) * kHashMul32; /* The higher bits contain more mixture from the multiplication, so we take our results from there. */ @@ -45,28 +45,56 @@ typedef struct FN(Bank) { } FN(Bank); typedef struct HashForgetfulChain { - uint32_t addr[BUCKET_SIZE]; - uint16_t head[BUCKET_SIZE]; - /* Truncated hash used for quick rejection of "distance cache" candidates. */ - uint8_t tiny_hash[65536]; - FN(Bank) banks[NUM_BANKS]; - uint16_t free_slot_idx[NUM_BANKS]; + uint16_t free_slot_idx[NUM_BANKS]; /* Up to 1KiB. Move to dynamic? */ size_t max_hops; + + /* Shortcuts. */ + void* extra; + HasherCommon* common; + + /* --- Dynamic size members --- */ + + /* uint32_t addr[BUCKET_SIZE]; */ + + /* uint16_t head[BUCKET_SIZE]; */ + + /* Truncated hash used for quick rejection of "distance cache" candidates. */ + /* uint8_t tiny_hash[65536];*/ + + /* FN(Bank) banks[NUM_BANKS]; */ } HashForgetfulChain; -static BROTLI_INLINE HashForgetfulChain* FN(Self)(HasherHandle handle) { - return (HashForgetfulChain*)&(GetHasherCommon(handle)[1]); +static uint32_t* FN(Addr)(void* extra) { + return (uint32_t*)extra; +} + +static uint16_t* FN(Head)(void* extra) { + return (uint16_t*)(&FN(Addr)(extra)[BUCKET_SIZE]); +} + +static uint8_t* FN(TinyHash)(void* extra) { + return (uint8_t*)(&FN(Head)(extra)[BUCKET_SIZE]); +} + +static FN(Bank)* FN(Banks)(void* extra) { + return (FN(Bank)*)(&FN(TinyHash)(extra)[65536]); } static void FN(Initialize)( - HasherHandle handle, const BrotliEncoderParams* params) { - FN(Self)(handle)->max_hops = - (params->quality > 6 ? 7u : 8u) << (params->quality - 4); + HasherCommon* common, HashForgetfulChain* BROTLI_RESTRICT self, + const BrotliEncoderParams* params) { + self->common = common; + self->extra = common->extra; + + self->max_hops = (params->quality > 6 ? 7u : 8u) << (params->quality - 4); } -static void FN(Prepare)(HasherHandle handle, BROTLI_BOOL one_shot, - size_t input_size, const uint8_t* data) { - HashForgetfulChain* self = FN(Self)(handle); +static void FN(Prepare)( + HashForgetfulChain* BROTLI_RESTRICT self, BROTLI_BOOL one_shot, + size_t input_size, const uint8_t* BROTLI_RESTRICT data) { + uint32_t* BROTLI_RESTRICT addr = FN(Addr)(self->extra); + uint16_t* BROTLI_RESTRICT head = FN(Head)(self->extra); + uint8_t* BROTLI_RESTRICT tiny_hash = FN(TinyHash)(self->extra); /* Partial preparation is 100 times slower (per socket). */ size_t partial_prepare_threshold = BUCKET_SIZE >> 6; if (one_shot && input_size <= partial_prepare_threshold) { @@ -74,17 +102,17 @@ static void FN(Prepare)(HasherHandle handle, BROTLI_BOOL one_shot, for (i = 0; i < input_size; ++i) { size_t bucket = FN(HashBytes)(&data[i]); /* See InitEmpty comment. */ - self->addr[bucket] = 0xCCCCCCCC; - self->head[bucket] = 0xCCCC; + addr[bucket] = 0xCCCCCCCC; + head[bucket] = 0xCCCC; } } else { /* Fill |addr| array with 0xCCCCCCCC value. Because of wrapping, position processed by hasher never reaches 3GB + 64M; this makes all new chains to be terminated after the first node. */ - memset(self->addr, 0xCC, sizeof(self->addr)); - memset(self->head, 0, sizeof(self->head)); + memset(addr, 0xCC, sizeof(uint32_t) * BUCKET_SIZE); + memset(head, 0, sizeof(uint16_t) * BUCKET_SIZE); } - memset(self->tiny_hash, 0, sizeof(self->tiny_hash)); + memset(tiny_hash, 0, sizeof(uint8_t) * 65536); memset(self->free_slot_idx, 0, sizeof(self->free_slot_idx)); } @@ -94,51 +122,58 @@ static BROTLI_INLINE size_t FN(HashMemAllocInBytes)( BROTLI_UNUSED(params); BROTLI_UNUSED(one_shot); BROTLI_UNUSED(input_size); - return sizeof(HashForgetfulChain); + return sizeof(uint32_t) * BUCKET_SIZE + sizeof(uint16_t) * BUCKET_SIZE + + sizeof(uint8_t) * 65536 + sizeof(FN(Bank)) * NUM_BANKS; } /* Look at 4 bytes at &data[ix & mask]. Compute a hash from these, and prepend node to corresponding chain; also update tiny_hash for current position. */ -static BROTLI_INLINE void FN(Store)(HasherHandle BROTLI_RESTRICT handle, +static BROTLI_INLINE void FN(Store)(HashForgetfulChain* BROTLI_RESTRICT self, const uint8_t* BROTLI_RESTRICT data, const size_t mask, const size_t ix) { - HashForgetfulChain* self = FN(Self)(handle); + uint32_t* BROTLI_RESTRICT addr = FN(Addr)(self->extra); + uint16_t* BROTLI_RESTRICT head = FN(Head)(self->extra); + uint8_t* BROTLI_RESTRICT tiny_hash = FN(TinyHash)(self->extra); + FN(Bank)* BROTLI_RESTRICT banks = FN(Banks)(self->extra); const size_t key = FN(HashBytes)(&data[ix & mask]); const size_t bank = key & (NUM_BANKS - 1); const size_t idx = self->free_slot_idx[bank]++ & (BANK_SIZE - 1); - size_t delta = ix - self->addr[key]; - self->tiny_hash[(uint16_t)ix] = (uint8_t)key; + size_t delta = ix - addr[key]; + tiny_hash[(uint16_t)ix] = (uint8_t)key; if (delta > 0xFFFF) delta = CAPPED_CHAINS ? 0 : 0xFFFF; - self->banks[bank].slots[idx].delta = (uint16_t)delta; - self->banks[bank].slots[idx].next = self->head[key]; - self->addr[key] = (uint32_t)ix; - self->head[key] = (uint16_t)idx; + banks[bank].slots[idx].delta = (uint16_t)delta; + banks[bank].slots[idx].next = head[key]; + addr[key] = (uint32_t)ix; + head[key] = (uint16_t)idx; } -static BROTLI_INLINE void FN(StoreRange)(HasherHandle handle, - const uint8_t* data, const size_t mask, const size_t ix_start, - const size_t ix_end) { +static BROTLI_INLINE void FN(StoreRange)( + HashForgetfulChain* BROTLI_RESTRICT self, + const uint8_t* BROTLI_RESTRICT data, const size_t mask, + const size_t ix_start, const size_t ix_end) { size_t i; for (i = ix_start; i < ix_end; ++i) { - FN(Store)(handle, data, mask, i); + FN(Store)(self, data, mask, i); } } -static BROTLI_INLINE void FN(StitchToPreviousBlock)(HasherHandle handle, +static BROTLI_INLINE void FN(StitchToPreviousBlock)( + HashForgetfulChain* BROTLI_RESTRICT self, size_t num_bytes, size_t position, const uint8_t* ringbuffer, size_t ring_buffer_mask) { if (num_bytes >= FN(HashTypeLength)() - 1 && position >= 3) { /* Prepare the hashes for three last bytes of the last write. These could not be calculated before, since they require knowledge of both the previous and the current block. */ - FN(Store)(handle, ringbuffer, ring_buffer_mask, position - 3); - FN(Store)(handle, ringbuffer, ring_buffer_mask, position - 2); - FN(Store)(handle, ringbuffer, ring_buffer_mask, position - 1); + FN(Store)(self, ringbuffer, ring_buffer_mask, position - 3); + FN(Store)(self, ringbuffer, ring_buffer_mask, position - 2); + FN(Store)(self, ringbuffer, ring_buffer_mask, position - 1); } } static BROTLI_INLINE void FN(PrepareDistanceCache)( - HasherHandle handle, int* BROTLI_RESTRICT distance_cache) { - BROTLI_UNUSED(handle); + HashForgetfulChain* BROTLI_RESTRICT self, + int* BROTLI_RESTRICT distance_cache) { + BROTLI_UNUSED(self); PrepareDistanceCache(distance_cache, NUM_LAST_DISTANCES_TO_CHECK); } @@ -153,14 +188,18 @@ static BROTLI_INLINE void FN(PrepareDistanceCache)( Does not look for matches further away than max_backward. Writes the best match into |out|. |out|->score is updated only if a better match is found. */ -static BROTLI_INLINE void FN(FindLongestMatch)(HasherHandle handle, +static BROTLI_INLINE void FN(FindLongestMatch)( + HashForgetfulChain* BROTLI_RESTRICT self, const BrotliEncoderDictionary* dictionary, const uint8_t* BROTLI_RESTRICT data, const size_t ring_buffer_mask, const int* BROTLI_RESTRICT distance_cache, const size_t cur_ix, const size_t max_length, const size_t max_backward, - const size_t gap, const size_t max_distance, + const size_t dictionary_distance, const size_t max_distance, HasherSearchResult* BROTLI_RESTRICT out) { - HashForgetfulChain* self = FN(Self)(handle); + uint32_t* BROTLI_RESTRICT addr = FN(Addr)(self->extra); + uint16_t* BROTLI_RESTRICT head = FN(Head)(self->extra); + uint8_t* BROTLI_RESTRICT tiny_hashes = FN(TinyHash)(self->extra); + FN(Bank)* BROTLI_RESTRICT banks = FN(Banks)(self->extra); const size_t cur_ix_masked = cur_ix & ring_buffer_mask; /* Don't accept a short copy from far away. */ score_t min_score = out->score; @@ -176,7 +215,7 @@ static BROTLI_INLINE void FN(FindLongestMatch)(HasherHandle handle, const size_t backward = (size_t)distance_cache[i]; size_t prev_ix = (cur_ix - backward); /* For distance code 0 we want to consider 2-byte matches. */ - if (i > 0 && self->tiny_hash[(uint16_t)prev_ix] != tiny_hash) continue; + if (i > 0 && tiny_hashes[(uint16_t)prev_ix] != tiny_hash) continue; if (prev_ix >= cur_ix || backward > max_backward) { continue; } @@ -204,16 +243,16 @@ static BROTLI_INLINE void FN(FindLongestMatch)(HasherHandle handle, const size_t bank = key & (NUM_BANKS - 1); size_t backward = 0; size_t hops = self->max_hops; - size_t delta = cur_ix - self->addr[key]; - size_t slot = self->head[key]; + size_t delta = cur_ix - addr[key]; + size_t slot = head[key]; while (hops--) { size_t prev_ix; size_t last = slot; backward += delta; if (backward > max_backward || (CAPPED_CHAINS && !delta)) break; prev_ix = (cur_ix - backward) & ring_buffer_mask; - slot = self->banks[bank].slots[last].next; - delta = self->banks[bank].slots[last].delta; + slot = banks[bank].slots[last].next; + delta = banks[bank].slots[last].delta; if (cur_ix_masked + best_len > ring_buffer_mask || prev_ix + best_len > ring_buffer_mask || data[cur_ix_masked + best_len] != data[prev_ix + best_len]) { @@ -238,11 +277,11 @@ static BROTLI_INLINE void FN(FindLongestMatch)(HasherHandle handle, } } } - FN(Store)(handle, data, ring_buffer_mask, cur_ix); + FN(Store)(self, data, ring_buffer_mask, cur_ix); } if (out->score == min_score) { SearchInStaticDictionary(dictionary, - handle, &data[cur_ix_masked], max_length, max_backward + gap, + self->common, &data[cur_ix_masked], max_length, dictionary_distance, max_distance, out, BROTLI_FALSE); } } diff --git a/modules/brotli/enc/hash_longest_match64_inc.h b/modules/brotli/enc/hash_longest_match64_inc.h index cb953a644f..956fb304b3 100644 --- a/modules/brotli/enc/hash_longest_match64_inc.h +++ b/modules/brotli/enc/hash_longest_match64_inc.h @@ -20,7 +20,7 @@ static BROTLI_INLINE size_t FN(HashTypeLength)(void) { return 8; } static BROTLI_INLINE size_t FN(StoreLookahead)(void) { return 8; } /* HashBytes is the function that chooses the bucket to place the address in. */ -static BROTLI_INLINE uint32_t FN(HashBytes)(const uint8_t* data, +static BROTLI_INLINE uint32_t FN(HashBytes)(const uint8_t* BROTLI_RESTRICT data, const uint64_t mask, const int shift) { const uint64_t h = (BROTLI_UNALIGNED_LOAD64LE(data) & mask) * kHashMul64Long; @@ -42,43 +42,43 @@ typedef struct HashLongestMatch { /* Mask for accessing entries in a block (in a ring-buffer manner). */ uint32_t block_mask_; + int block_bits_; + int num_last_distances_to_check_; + + /* Shortcuts. */ + HasherCommon* common_; + /* --- Dynamic size members --- */ /* Number of entries in a particular bucket. */ - /* uint16_t num[bucket_size]; */ + uint16_t* num_; /* uint16_t[bucket_size]; */ /* Buckets containing block_size_ of backward references. */ - /* uint32_t* buckets[bucket_size * block_size]; */ + uint32_t* buckets_; /* uint32_t[bucket_size * block_size]; */ } HashLongestMatch; -static BROTLI_INLINE HashLongestMatch* FN(Self)(HasherHandle handle) { - return (HashLongestMatch*)&(GetHasherCommon(handle)[1]); -} - -static BROTLI_INLINE uint16_t* FN(Num)(HashLongestMatch* self) { - return (uint16_t*)(&self[1]); -} - -static BROTLI_INLINE uint32_t* FN(Buckets)(HashLongestMatch* self) { - return (uint32_t*)(&FN(Num)(self)[self->bucket_size_]); -} - static void FN(Initialize)( - HasherHandle handle, const BrotliEncoderParams* params) { - HasherCommon* common = GetHasherCommon(handle); - HashLongestMatch* self = FN(Self)(handle); + HasherCommon* common, HashLongestMatch* BROTLI_RESTRICT self, + const BrotliEncoderParams* params) { + self->common_ = common; + BROTLI_UNUSED(params); self->hash_shift_ = 64 - common->params.bucket_bits; self->hash_mask_ = (~((uint64_t)0U)) >> (64 - 8 * common->params.hash_len); self->bucket_size_ = (size_t)1 << common->params.bucket_bits; + self->block_bits_ = common->params.block_bits; self->block_size_ = (size_t)1 << common->params.block_bits; self->block_mask_ = (uint32_t)(self->block_size_ - 1); + self->num_last_distances_to_check_ = + common->params.num_last_distances_to_check; + self->num_ = (uint16_t*)common->extra; + self->buckets_ = (uint32_t*)&self->num_[self->bucket_size_]; } -static void FN(Prepare)(HasherHandle handle, BROTLI_BOOL one_shot, - size_t input_size, const uint8_t* data) { - HashLongestMatch* self = FN(Self)(handle); - uint16_t* num = FN(Num)(self); +static void FN(Prepare)( + HashLongestMatch* BROTLI_RESTRICT self, BROTLI_BOOL one_shot, + size_t input_size, const uint8_t* BROTLI_RESTRICT data) { + uint16_t* BROTLI_RESTRICT num = self->num_; /* Partial preparation is 100 times slower (per socket). */ size_t partial_prepare_threshold = self->bucket_size_ >> 6; if (one_shot && input_size <= partial_prepare_threshold) { @@ -100,50 +100,52 @@ static BROTLI_INLINE size_t FN(HashMemAllocInBytes)( size_t block_size = (size_t)1 << params->hasher.block_bits; BROTLI_UNUSED(one_shot); BROTLI_UNUSED(input_size); - return sizeof(HashLongestMatch) + bucket_size * (2 + 4 * block_size); + return sizeof(uint16_t) * bucket_size + + sizeof(uint32_t) * bucket_size * block_size; } /* Look at 4 bytes at &data[ix & mask]. Compute a hash from these, and store the value of ix at that position. */ -static BROTLI_INLINE void FN(Store)(HasherHandle handle, const uint8_t* data, +static BROTLI_INLINE void FN(Store)( + HashLongestMatch* BROTLI_RESTRICT self, const uint8_t* BROTLI_RESTRICT data, const size_t mask, const size_t ix) { - HashLongestMatch* self = FN(Self)(handle); - uint16_t* num = FN(Num)(self); + uint16_t* BROTLI_RESTRICT num = self->num_; + uint32_t* BROTLI_RESTRICT buckets = self->buckets_; const uint32_t key = FN(HashBytes)(&data[ix & mask], self->hash_mask_, self->hash_shift_); const size_t minor_ix = num[key] & self->block_mask_; - const size_t offset = - minor_ix + (key << GetHasherCommon(handle)->params.block_bits); - FN(Buckets)(self)[offset] = (uint32_t)ix; + const size_t offset = minor_ix + (key << self->block_bits_); ++num[key]; + buckets[offset] = (uint32_t)ix; } -static BROTLI_INLINE void FN(StoreRange)(HasherHandle handle, - const uint8_t* data, const size_t mask, const size_t ix_start, - const size_t ix_end) { +static BROTLI_INLINE void FN(StoreRange)(HashLongestMatch* BROTLI_RESTRICT self, + const uint8_t* BROTLI_RESTRICT data, const size_t mask, + const size_t ix_start, const size_t ix_end) { size_t i; for (i = ix_start; i < ix_end; ++i) { - FN(Store)(handle, data, mask, i); + FN(Store)(self, data, mask, i); } } -static BROTLI_INLINE void FN(StitchToPreviousBlock)(HasherHandle handle, +static BROTLI_INLINE void FN(StitchToPreviousBlock)( + HashLongestMatch* BROTLI_RESTRICT self, size_t num_bytes, size_t position, const uint8_t* ringbuffer, size_t ringbuffer_mask) { if (num_bytes >= FN(HashTypeLength)() - 1 && position >= 3) { /* Prepare the hashes for three last bytes of the last write. These could not be calculated before, since they require knowledge of both the previous and the current block. */ - FN(Store)(handle, ringbuffer, ringbuffer_mask, position - 3); - FN(Store)(handle, ringbuffer, ringbuffer_mask, position - 2); - FN(Store)(handle, ringbuffer, ringbuffer_mask, position - 1); + FN(Store)(self, ringbuffer, ringbuffer_mask, position - 3); + FN(Store)(self, ringbuffer, ringbuffer_mask, position - 2); + FN(Store)(self, ringbuffer, ringbuffer_mask, position - 1); } } static BROTLI_INLINE void FN(PrepareDistanceCache)( - HasherHandle handle, int* BROTLI_RESTRICT distance_cache) { - PrepareDistanceCache(distance_cache, - GetHasherCommon(handle)->params.num_last_distances_to_check); + HashLongestMatch* BROTLI_RESTRICT self, + int* BROTLI_RESTRICT distance_cache) { + PrepareDistanceCache(distance_cache, self->num_last_distances_to_check_); } /* Find a longest backward match of &data[cur_ix] up to the length of @@ -157,17 +159,16 @@ static BROTLI_INLINE void FN(PrepareDistanceCache)( Does not look for matches further away than max_backward. Writes the best match into |out|. |out|->score is updated only if a better match is found. */ -static BROTLI_INLINE void FN(FindLongestMatch)(HasherHandle handle, +static BROTLI_INLINE void FN(FindLongestMatch)( + HashLongestMatch* BROTLI_RESTRICT self, const BrotliEncoderDictionary* dictionary, const uint8_t* BROTLI_RESTRICT data, const size_t ring_buffer_mask, const int* BROTLI_RESTRICT distance_cache, const size_t cur_ix, const size_t max_length, const size_t max_backward, - const size_t gap, const size_t max_distance, + const size_t dictionary_distance, const size_t max_distance, HasherSearchResult* BROTLI_RESTRICT out) { - HasherCommon* common = GetHasherCommon(handle); - HashLongestMatch* self = FN(Self)(handle); - uint16_t* num = FN(Num)(self); - uint32_t* buckets = FN(Buckets)(self); + uint16_t* BROTLI_RESTRICT num = self->num_; + uint32_t* BROTLI_RESTRICT buckets = self->buckets_; const size_t cur_ix_masked = cur_ix & ring_buffer_mask; /* Don't accept a short copy from far away. */ score_t min_score = out->score; @@ -177,7 +178,7 @@ static BROTLI_INLINE void FN(FindLongestMatch)(HasherHandle handle, out->len = 0; out->len_code_delta = 0; /* Try last distance first. */ - for (i = 0; i < (size_t)common->params.num_last_distances_to_check; ++i) { + for (i = 0; i < (size_t)self->num_last_distances_to_check_; ++i) { const size_t backward = (size_t)distance_cache[i]; size_t prev_ix = (size_t)(cur_ix - backward); if (prev_ix >= cur_ix) { @@ -218,8 +219,7 @@ static BROTLI_INLINE void FN(FindLongestMatch)(HasherHandle handle, { const uint32_t key = FN(HashBytes)( &data[cur_ix_masked], self->hash_mask_, self->hash_shift_); - uint32_t* BROTLI_RESTRICT bucket = - &buckets[key << common->params.block_bits]; + uint32_t* BROTLI_RESTRICT bucket = &buckets[key << self->block_bits_]; const size_t down = (num[key] > self->block_size_) ? (num[key] - self->block_size_) : 0u; @@ -259,7 +259,7 @@ static BROTLI_INLINE void FN(FindLongestMatch)(HasherHandle handle, } if (min_score == out->score) { SearchInStaticDictionary(dictionary, - handle, &data[cur_ix_masked], max_length, max_backward + gap, + self->common_, &data[cur_ix_masked], max_length, dictionary_distance, max_distance, out, BROTLI_FALSE); } } diff --git a/modules/brotli/enc/hash_longest_match_inc.h b/modules/brotli/enc/hash_longest_match_inc.h index 457f5a9ed2..27f4463d7f 100644 --- a/modules/brotli/enc/hash_longest_match_inc.h +++ b/modules/brotli/enc/hash_longest_match_inc.h @@ -20,7 +20,8 @@ static BROTLI_INLINE size_t FN(HashTypeLength)(void) { return 4; } static BROTLI_INLINE size_t FN(StoreLookahead)(void) { return 4; } /* HashBytes is the function that chooses the bucket to place the address in. */ -static uint32_t FN(HashBytes)(const uint8_t* data, const int shift) { +static uint32_t FN(HashBytes)( + const uint8_t* BROTLI_RESTRICT data, const int shift) { uint32_t h = BROTLI_UNALIGNED_LOAD32LE(data) * kHashMul32; /* The higher bits contain more mixture from the multiplication, so we take our results from there. */ @@ -38,42 +39,46 @@ typedef struct HashLongestMatch { /* Mask for accessing entries in a block (in a ring-buffer manner). */ uint32_t block_mask_; + int block_bits_; + int num_last_distances_to_check_; + + /* Shortcuts. */ + HasherCommon* common_; + /* --- Dynamic size members --- */ /* Number of entries in a particular bucket. */ - /* uint16_t num[bucket_size]; */ + uint16_t* num_; /* uint16_t[bucket_size]; */ /* Buckets containing block_size_ of backward references. */ - /* uint32_t* buckets[bucket_size * block_size]; */ + uint32_t* buckets_; /* uint32_t[bucket_size * block_size]; */ } HashLongestMatch; -static BROTLI_INLINE HashLongestMatch* FN(Self)(HasherHandle handle) { - return (HashLongestMatch*)&(GetHasherCommon(handle)[1]); -} - -static BROTLI_INLINE uint16_t* FN(Num)(HashLongestMatch* self) { - return (uint16_t*)(&self[1]); -} - -static BROTLI_INLINE uint32_t* FN(Buckets)(HashLongestMatch* self) { - return (uint32_t*)(&FN(Num)(self)[self->bucket_size_]); +static BROTLI_INLINE uint16_t* FN(Num)(void* extra) { + return (uint16_t*)extra; } static void FN(Initialize)( - HasherHandle handle, const BrotliEncoderParams* params) { - HasherCommon* common = GetHasherCommon(handle); - HashLongestMatch* self = FN(Self)(handle); + HasherCommon* common, HashLongestMatch* BROTLI_RESTRICT self, + const BrotliEncoderParams* params) { + self->common_ = common; + BROTLI_UNUSED(params); self->hash_shift_ = 32 - common->params.bucket_bits; self->bucket_size_ = (size_t)1 << common->params.bucket_bits; self->block_size_ = (size_t)1 << common->params.block_bits; self->block_mask_ = (uint32_t)(self->block_size_ - 1); + self->num_ = (uint16_t*)common->extra; + self->buckets_ = (uint32_t*)(&self->num_[self->bucket_size_]); + self->block_bits_ = common->params.block_bits; + self->num_last_distances_to_check_ = + common->params.num_last_distances_to_check; } -static void FN(Prepare)(HasherHandle handle, BROTLI_BOOL one_shot, - size_t input_size, const uint8_t* data) { - HashLongestMatch* self = FN(Self)(handle); - uint16_t* num = FN(Num)(self); +static void FN(Prepare)( + HashLongestMatch* BROTLI_RESTRICT self, BROTLI_BOOL one_shot, + size_t input_size, const uint8_t* BROTLI_RESTRICT data) { + uint16_t* BROTLI_RESTRICT num = self->num_; /* Partial preparation is 100 times slower (per socket). */ size_t partial_prepare_threshold = self->bucket_size_ >> 6; if (one_shot && input_size <= partial_prepare_threshold) { @@ -94,49 +99,49 @@ static BROTLI_INLINE size_t FN(HashMemAllocInBytes)( size_t block_size = (size_t)1 << params->hasher.block_bits; BROTLI_UNUSED(one_shot); BROTLI_UNUSED(input_size); - return sizeof(HashLongestMatch) + bucket_size * (2 + 4 * block_size); + return sizeof(uint16_t) * bucket_size + + sizeof(uint32_t) * bucket_size * block_size; } /* Look at 4 bytes at &data[ix & mask]. Compute a hash from these, and store the value of ix at that position. */ -static BROTLI_INLINE void FN(Store)(HasherHandle handle, const uint8_t* data, +static BROTLI_INLINE void FN(Store)( + HashLongestMatch* BROTLI_RESTRICT self, const uint8_t* BROTLI_RESTRICT data, const size_t mask, const size_t ix) { - HashLongestMatch* self = FN(Self)(handle); - uint16_t* num = FN(Num)(self); const uint32_t key = FN(HashBytes)(&data[ix & mask], self->hash_shift_); - const size_t minor_ix = num[key] & self->block_mask_; - const size_t offset = - minor_ix + (key << GetHasherCommon(handle)->params.block_bits); - FN(Buckets)(self)[offset] = (uint32_t)ix; - ++num[key]; + const size_t minor_ix = self->num_[key] & self->block_mask_; + const size_t offset = minor_ix + (key << self->block_bits_); + self->buckets_[offset] = (uint32_t)ix; + ++self->num_[key]; } -static BROTLI_INLINE void FN(StoreRange)(HasherHandle handle, - const uint8_t* data, const size_t mask, const size_t ix_start, - const size_t ix_end) { +static BROTLI_INLINE void FN(StoreRange)(HashLongestMatch* BROTLI_RESTRICT self, + const uint8_t* BROTLI_RESTRICT data, const size_t mask, + const size_t ix_start, const size_t ix_end) { size_t i; for (i = ix_start; i < ix_end; ++i) { - FN(Store)(handle, data, mask, i); + FN(Store)(self, data, mask, i); } } -static BROTLI_INLINE void FN(StitchToPreviousBlock)(HasherHandle handle, +static BROTLI_INLINE void FN(StitchToPreviousBlock)( + HashLongestMatch* BROTLI_RESTRICT self, size_t num_bytes, size_t position, const uint8_t* ringbuffer, size_t ringbuffer_mask) { if (num_bytes >= FN(HashTypeLength)() - 1 && position >= 3) { /* Prepare the hashes for three last bytes of the last write. These could not be calculated before, since they require knowledge of both the previous and the current block. */ - FN(Store)(handle, ringbuffer, ringbuffer_mask, position - 3); - FN(Store)(handle, ringbuffer, ringbuffer_mask, position - 2); - FN(Store)(handle, ringbuffer, ringbuffer_mask, position - 1); + FN(Store)(self, ringbuffer, ringbuffer_mask, position - 3); + FN(Store)(self, ringbuffer, ringbuffer_mask, position - 2); + FN(Store)(self, ringbuffer, ringbuffer_mask, position - 1); } } static BROTLI_INLINE void FN(PrepareDistanceCache)( - HasherHandle handle, int* BROTLI_RESTRICT distance_cache) { - PrepareDistanceCache(distance_cache, - GetHasherCommon(handle)->params.num_last_distances_to_check); + HashLongestMatch* BROTLI_RESTRICT self, + int* BROTLI_RESTRICT distance_cache) { + PrepareDistanceCache(distance_cache, self->num_last_distances_to_check_); } /* Find a longest backward match of &data[cur_ix] up to the length of @@ -150,17 +155,16 @@ static BROTLI_INLINE void FN(PrepareDistanceCache)( Does not look for matches further away than max_backward. Writes the best match into |out|. |out|->score is updated only if a better match is found. */ -static BROTLI_INLINE void FN(FindLongestMatch)(HasherHandle handle, +static BROTLI_INLINE void FN(FindLongestMatch)( + HashLongestMatch* BROTLI_RESTRICT self, const BrotliEncoderDictionary* dictionary, const uint8_t* BROTLI_RESTRICT data, const size_t ring_buffer_mask, const int* BROTLI_RESTRICT distance_cache, const size_t cur_ix, const size_t max_length, const size_t max_backward, - const size_t gap, const size_t max_distance, + const size_t dictionary_distance, const size_t max_distance, HasherSearchResult* BROTLI_RESTRICT out) { - HasherCommon* common = GetHasherCommon(handle); - HashLongestMatch* self = FN(Self)(handle); - uint16_t* num = FN(Num)(self); - uint32_t* buckets = FN(Buckets)(self); + uint16_t* BROTLI_RESTRICT num = self->num_; + uint32_t* BROTLI_RESTRICT buckets = self->buckets_; const size_t cur_ix_masked = cur_ix & ring_buffer_mask; /* Don't accept a short copy from far away. */ score_t min_score = out->score; @@ -170,7 +174,7 @@ static BROTLI_INLINE void FN(FindLongestMatch)(HasherHandle handle, out->len = 0; out->len_code_delta = 0; /* Try last distance first. */ - for (i = 0; i < (size_t)common->params.num_last_distances_to_check; ++i) { + for (i = 0; i < (size_t)self->num_last_distances_to_check_; ++i) { const size_t backward = (size_t)distance_cache[i]; size_t prev_ix = (size_t)(cur_ix - backward); if (prev_ix >= cur_ix) { @@ -211,8 +215,7 @@ static BROTLI_INLINE void FN(FindLongestMatch)(HasherHandle handle, { const uint32_t key = FN(HashBytes)(&data[cur_ix_masked], self->hash_shift_); - uint32_t* BROTLI_RESTRICT bucket = - &buckets[key << common->params.block_bits]; + uint32_t* BROTLI_RESTRICT bucket = &buckets[key << self->block_bits_]; const size_t down = (num[key] > self->block_size_) ? (num[key] - self->block_size_) : 0u; for (i = num[key]; i > down;) { @@ -251,7 +254,7 @@ static BROTLI_INLINE void FN(FindLongestMatch)(HasherHandle handle, } if (min_score == out->score) { SearchInStaticDictionary(dictionary, - handle, &data[cur_ix_masked], max_length, max_backward + gap, + self->common_, &data[cur_ix_masked], max_length, dictionary_distance, max_distance, out, BROTLI_FALSE); } } diff --git a/modules/brotli/enc/hash_longest_match_quickly_inc.h b/modules/brotli/enc/hash_longest_match_quickly_inc.h index a7b9639feb..e5ba840ab9 100644 --- a/modules/brotli/enc/hash_longest_match_quickly_inc.h +++ b/modules/brotli/enc/hash_longest_match_quickly_inc.h @@ -5,15 +5,16 @@ See file LICENSE for detail or copy at https://opensource.org/licenses/MIT */ -/* template parameters: FN, BUCKET_BITS, BUCKET_SWEEP, HASH_LEN, +/* template parameters: FN, BUCKET_BITS, BUCKET_SWEEP_BITS, HASH_LEN, USE_DICTIONARY */ #define HashLongestMatchQuickly HASHER() #define BUCKET_SIZE (1 << BUCKET_BITS) - -#define HASH_MAP_SIZE (4 << BUCKET_BITS) +#define BUCKET_MASK (BUCKET_SIZE - 1) +#define BUCKET_SWEEP (1 << BUCKET_SWEEP_BITS) +#define BUCKET_SWEEP_MASK ((BUCKET_SWEEP - 1) << 3) static BROTLI_INLINE size_t FN(HashTypeLength)(void) { return 8; } static BROTLI_INLINE size_t FN(StoreLookahead)(void) { return 8; } @@ -32,39 +33,50 @@ static uint32_t FN(HashBytes)(const uint8_t* data) { /* A (forgetful) hash table to the data seen by the compressor, to help create backward references to previous data. - This is a hash map of fixed size (BUCKET_SIZE). Starting from the - given index, BUCKET_SWEEP buckets are used to store values of a key. */ + This is a hash map of fixed size (BUCKET_SIZE). */ typedef struct HashLongestMatchQuickly { - uint32_t buckets_[BUCKET_SIZE + BUCKET_SWEEP]; + /* Shortcuts. */ + HasherCommon* common; + + /* --- Dynamic size members --- */ + + uint32_t* buckets_; /* uint32_t[BUCKET_SIZE]; */ } HashLongestMatchQuickly; -static BROTLI_INLINE HashLongestMatchQuickly* FN(Self)(HasherHandle handle) { - return (HashLongestMatchQuickly*)&(GetHasherCommon(handle)[1]); -} - static void FN(Initialize)( - HasherHandle handle, const BrotliEncoderParams* params) { - BROTLI_UNUSED(handle); + HasherCommon* common, HashLongestMatchQuickly* BROTLI_RESTRICT self, + const BrotliEncoderParams* params) { + self->common = common; + BROTLI_UNUSED(params); + self->buckets_ = (uint32_t*)common->extra; } -static void FN(Prepare)(HasherHandle handle, BROTLI_BOOL one_shot, - size_t input_size, const uint8_t* data) { - HashLongestMatchQuickly* self = FN(Self)(handle); +static void FN(Prepare)( + HashLongestMatchQuickly* BROTLI_RESTRICT self, BROTLI_BOOL one_shot, + size_t input_size, const uint8_t* BROTLI_RESTRICT data) { + uint32_t* BROTLI_RESTRICT buckets = self->buckets_; /* Partial preparation is 100 times slower (per socket). */ - size_t partial_prepare_threshold = HASH_MAP_SIZE >> 7; + size_t partial_prepare_threshold = BUCKET_SIZE >> 5; if (one_shot && input_size <= partial_prepare_threshold) { size_t i; for (i = 0; i < input_size; ++i) { const uint32_t key = FN(HashBytes)(&data[i]); - memset(&self->buckets_[key], 0, BUCKET_SWEEP * sizeof(self->buckets_[0])); + if (BUCKET_SWEEP == 1) { + buckets[key] = 0; + } else { + uint32_t j; + for (j = 0; j < BUCKET_SWEEP; ++j) { + buckets[(key + (j << 3)) & BUCKET_MASK] = 0; + } + } } } else { /* It is not strictly necessary to fill this buffer here, but not filling will make the results of the compression stochastic (but correct). This is because random data would cause the system to find accidentally good backward references here and there. */ - memset(&self->buckets_[0], 0, sizeof(self->buckets_)); + memset(buckets, 0, sizeof(uint32_t) * BUCKET_SIZE); } } @@ -74,45 +86,53 @@ static BROTLI_INLINE size_t FN(HashMemAllocInBytes)( BROTLI_UNUSED(params); BROTLI_UNUSED(one_shot); BROTLI_UNUSED(input_size); - return sizeof(HashLongestMatchQuickly); + return sizeof(uint32_t) * BUCKET_SIZE; } /* Look at 5 bytes at &data[ix & mask]. Compute a hash from these, and store the value somewhere within [ix .. ix+3]. */ -static BROTLI_INLINE void FN(Store)(HasherHandle handle, - const uint8_t* data, const size_t mask, const size_t ix) { +static BROTLI_INLINE void FN(Store)( + HashLongestMatchQuickly* BROTLI_RESTRICT self, + const uint8_t* BROTLI_RESTRICT data, const size_t mask, const size_t ix) { const uint32_t key = FN(HashBytes)(&data[ix & mask]); - /* Wiggle the value with the bucket sweep range. */ - const uint32_t off = (ix >> 3) % BUCKET_SWEEP; - FN(Self)(handle)->buckets_[key + off] = (uint32_t)ix; + if (BUCKET_SWEEP == 1) { + self->buckets_[key] = (uint32_t)ix; + } else { + /* Wiggle the value with the bucket sweep range. */ + const uint32_t off = ix & BUCKET_SWEEP_MASK; + self->buckets_[(key + off) & BUCKET_MASK] = (uint32_t)ix; + } } -static BROTLI_INLINE void FN(StoreRange)(HasherHandle handle, - const uint8_t* data, const size_t mask, const size_t ix_start, - const size_t ix_end) { +static BROTLI_INLINE void FN(StoreRange)( + HashLongestMatchQuickly* BROTLI_RESTRICT self, + const uint8_t* BROTLI_RESTRICT data, const size_t mask, + const size_t ix_start, const size_t ix_end) { size_t i; for (i = ix_start; i < ix_end; ++i) { - FN(Store)(handle, data, mask, i); + FN(Store)(self, data, mask, i); } } static BROTLI_INLINE void FN(StitchToPreviousBlock)( - HasherHandle handle, size_t num_bytes, size_t position, + HashLongestMatchQuickly* BROTLI_RESTRICT self, + size_t num_bytes, size_t position, const uint8_t* ringbuffer, size_t ringbuffer_mask) { if (num_bytes >= FN(HashTypeLength)() - 1 && position >= 3) { /* Prepare the hashes for three last bytes of the last write. These could not be calculated before, since they require knowledge of both the previous and the current block. */ - FN(Store)(handle, ringbuffer, ringbuffer_mask, position - 3); - FN(Store)(handle, ringbuffer, ringbuffer_mask, position - 2); - FN(Store)(handle, ringbuffer, ringbuffer_mask, position - 1); + FN(Store)(self, ringbuffer, ringbuffer_mask, position - 3); + FN(Store)(self, ringbuffer, ringbuffer_mask, position - 2); + FN(Store)(self, ringbuffer, ringbuffer_mask, position - 1); } } static BROTLI_INLINE void FN(PrepareDistanceCache)( - HasherHandle handle, int* BROTLI_RESTRICT distance_cache) { - BROTLI_UNUSED(handle); + HashLongestMatchQuickly* BROTLI_RESTRICT self, + int* BROTLI_RESTRICT distance_cache) { + BROTLI_UNUSED(self); BROTLI_UNUSED(distance_cache); } @@ -125,17 +145,19 @@ static BROTLI_INLINE void FN(PrepareDistanceCache)( Writes the best match into |out|. |out|->score is updated only if a better match is found. */ static BROTLI_INLINE void FN(FindLongestMatch)( - HasherHandle handle, const BrotliEncoderDictionary* dictionary, + HashLongestMatchQuickly* BROTLI_RESTRICT self, + const BrotliEncoderDictionary* dictionary, const uint8_t* BROTLI_RESTRICT data, const size_t ring_buffer_mask, const int* BROTLI_RESTRICT distance_cache, const size_t cur_ix, const size_t max_length, const size_t max_backward, - const size_t gap, const size_t max_distance, + const size_t dictionary_distance, const size_t max_distance, HasherSearchResult* BROTLI_RESTRICT out) { - HashLongestMatchQuickly* self = FN(Self)(handle); + uint32_t* BROTLI_RESTRICT buckets = self->buckets_; const size_t best_len_in = out->len; const size_t cur_ix_masked = cur_ix & ring_buffer_mask; - const uint32_t key = FN(HashBytes)(&data[cur_ix_masked]); int compare_char = data[cur_ix_masked + best_len_in]; + size_t key = FN(HashBytes)(&data[cur_ix_masked]); + size_t key_out; score_t min_score = out->score; score_t best_score = out->score; size_t best_len = best_len_in; @@ -145,21 +167,21 @@ static BROTLI_INLINE void FN(FindLongestMatch)( if (prev_ix < cur_ix) { prev_ix &= (uint32_t)ring_buffer_mask; if (compare_char == data[prev_ix + best_len]) { - size_t len = FindMatchLengthWithLimit(&data[prev_ix], - &data[cur_ix_masked], - max_length); + const size_t len = FindMatchLengthWithLimit( + &data[prev_ix], &data[cur_ix_masked], max_length); if (len >= 4) { const score_t score = BackwardReferenceScoreUsingLastDistance(len); if (best_score < score) { - best_score = score; - best_len = len; out->len = len; out->distance = cached_backward; - out->score = best_score; - compare_char = data[cur_ix_masked + best_len]; + out->score = score; if (BUCKET_SWEEP == 1) { - self->buckets_[key] = (uint32_t)cur_ix; + buckets[key] = (uint32_t)cur_ix; return; + } else { + best_len = len; + best_score = score; + compare_char = data[cur_ix_masked + len]; } } } @@ -169,8 +191,8 @@ static BROTLI_INLINE void FN(FindLongestMatch)( size_t backward; size_t len; /* Only one to look for, don't bother to prepare for a loop. */ - prev_ix = self->buckets_[key]; - self->buckets_[key] = (uint32_t)cur_ix; + prev_ix = buckets[key]; + buckets[key] = (uint32_t)cur_ix; backward = cur_ix - prev_ix; prev_ix &= (uint32_t)ring_buffer_mask; if (compare_char != data[prev_ix + best_len_in]) { @@ -192,12 +214,17 @@ static BROTLI_INLINE void FN(FindLongestMatch)( } } } else { - uint32_t* bucket = self->buckets_ + key; - int i; - prev_ix = *bucket++; - for (i = 0; i < BUCKET_SWEEP; ++i, prev_ix = *bucket++) { - const size_t backward = cur_ix - prev_ix; + size_t keys[BUCKET_SWEEP]; + size_t i; + for (i = 0; i < BUCKET_SWEEP; ++i) { + keys[i] = (key + (i << 3)) & BUCKET_MASK; + } + key_out = keys[(cur_ix & BUCKET_SWEEP_MASK) >> 3]; + for (i = 0; i < BUCKET_SWEEP; ++i) { size_t len; + size_t backward; + prev_ix = buckets[keys[i]]; + backward = cur_ix - prev_ix; prev_ix &= (uint32_t)ring_buffer_mask; if (compare_char != data[prev_ix + best_len]) { continue; @@ -211,25 +238,29 @@ static BROTLI_INLINE void FN(FindLongestMatch)( if (len >= 4) { const score_t score = BackwardReferenceScore(len, backward); if (best_score < score) { - best_score = score; best_len = len; - out->len = best_len; - out->distance = backward; + out->len = len; + compare_char = data[cur_ix_masked + len]; + best_score = score; out->score = score; - compare_char = data[cur_ix_masked + best_len]; + out->distance = backward; } } } } if (USE_DICTIONARY && min_score == out->score) { SearchInStaticDictionary(dictionary, - handle, &data[cur_ix_masked], max_length, max_backward + gap, + self->common, &data[cur_ix_masked], max_length, dictionary_distance, max_distance, out, BROTLI_TRUE); } - self->buckets_[key + ((cur_ix >> 3) % BUCKET_SWEEP)] = (uint32_t)cur_ix; + if (BUCKET_SWEEP != 1) { + buckets[key_out] = (uint32_t)cur_ix; + } } -#undef HASH_MAP_SIZE +#undef BUCKET_SWEEP_MASK +#undef BUCKET_SWEEP +#undef BUCKET_MASK #undef BUCKET_SIZE #undef HashLongestMatchQuickly diff --git a/modules/brotli/enc/hash_rolling_inc.h b/modules/brotli/enc/hash_rolling_inc.h index 17f8a408e2..586ae73859 100644 --- a/modules/brotli/enc/hash_rolling_inc.h +++ b/modules/brotli/enc/hash_rolling_inc.h @@ -51,13 +51,9 @@ typedef struct HashRolling { uint32_t factor_remove; } HashRolling; -static BROTLI_INLINE HashRolling* FN(Self)(HasherHandle handle) { - return (HashRolling*)&(GetHasherCommon(handle)[1]); -} - static void FN(Initialize)( - HasherHandle handle, const BrotliEncoderParams* params) { - HashRolling* self = FN(Self)(handle); + HasherCommon* common, HashRolling* BROTLI_RESTRICT self, + const BrotliEncoderParams* params) { size_t i; self->state = 0; self->next_ix = 0; @@ -71,7 +67,7 @@ static void FN(Initialize)( self->factor_remove *= self->factor; } - self->table = (uint32_t*)((HasherHandle)self + sizeof(HashRolling)); + self->table = (uint32_t*)common->extra; for (i = 0; i < NUMBUCKETS; i++) { self->table[i] = FN(kInvalidPos); } @@ -79,9 +75,8 @@ static void FN(Initialize)( BROTLI_UNUSED(params); } -static void FN(Prepare)(HasherHandle handle, BROTLI_BOOL one_shot, - size_t input_size, const uint8_t* data) { - HashRolling* self = FN(Self)(handle); +static void FN(Prepare)(HashRolling* BROTLI_RESTRICT self, BROTLI_BOOL one_shot, + size_t input_size, const uint8_t* BROTLI_RESTRICT data) { size_t i; /* Too small size, cannot use this hasher. */ if (input_size < CHUNKLEN) return; @@ -96,36 +91,36 @@ static void FN(Prepare)(HasherHandle handle, BROTLI_BOOL one_shot, static BROTLI_INLINE size_t FN(HashMemAllocInBytes)( const BrotliEncoderParams* params, BROTLI_BOOL one_shot, size_t input_size) { - return sizeof(HashRolling) + NUMBUCKETS * sizeof(uint32_t); + return NUMBUCKETS * sizeof(uint32_t); BROTLI_UNUSED(params); BROTLI_UNUSED(one_shot); BROTLI_UNUSED(input_size); } -static BROTLI_INLINE void FN(Store)(HasherHandle BROTLI_RESTRICT handle, +static BROTLI_INLINE void FN(Store)(HashRolling* BROTLI_RESTRICT self, const uint8_t* BROTLI_RESTRICT data, const size_t mask, const size_t ix) { - BROTLI_UNUSED(handle); + BROTLI_UNUSED(self); BROTLI_UNUSED(data); BROTLI_UNUSED(mask); BROTLI_UNUSED(ix); } -static BROTLI_INLINE void FN(StoreRange)(HasherHandle handle, - const uint8_t* data, const size_t mask, const size_t ix_start, - const size_t ix_end) { - BROTLI_UNUSED(handle); +static BROTLI_INLINE void FN(StoreRange)(HashRolling* BROTLI_RESTRICT self, + const uint8_t* BROTLI_RESTRICT data, const size_t mask, + const size_t ix_start, const size_t ix_end) { + BROTLI_UNUSED(self); BROTLI_UNUSED(data); BROTLI_UNUSED(mask); BROTLI_UNUSED(ix_start); BROTLI_UNUSED(ix_end); } -static BROTLI_INLINE void FN(StitchToPreviousBlock)(HasherHandle handle, +static BROTLI_INLINE void FN(StitchToPreviousBlock)( + HashRolling* BROTLI_RESTRICT self, size_t num_bytes, size_t position, const uint8_t* ringbuffer, size_t ring_buffer_mask) { /* In this case we must re-initialize the hasher from scratch from the current position. */ - HashRolling* self = FN(Self)(handle); size_t position_masked; size_t available = num_bytes; if ((position & (JUMP - 1)) != 0) { @@ -139,28 +134,29 @@ static BROTLI_INLINE void FN(StitchToPreviousBlock)(HasherHandle handle, available = ring_buffer_mask - position_masked; } - FN(Prepare)(handle, BROTLI_FALSE, available, + FN(Prepare)(self, BROTLI_FALSE, available, ringbuffer + (position & ring_buffer_mask)); self->next_ix = position; BROTLI_UNUSED(num_bytes); } static BROTLI_INLINE void FN(PrepareDistanceCache)( - HasherHandle handle, int* BROTLI_RESTRICT distance_cache) { - BROTLI_UNUSED(handle); + HashRolling* BROTLI_RESTRICT self, + int* BROTLI_RESTRICT distance_cache) { + BROTLI_UNUSED(self); BROTLI_UNUSED(distance_cache); } -static BROTLI_INLINE void FN(FindLongestMatch)(HasherHandle handle, +static BROTLI_INLINE void FN(FindLongestMatch)( + HashRolling* BROTLI_RESTRICT self, const BrotliEncoderDictionary* dictionary, const uint8_t* BROTLI_RESTRICT data, const size_t ring_buffer_mask, const int* BROTLI_RESTRICT distance_cache, const size_t cur_ix, const size_t max_length, const size_t max_backward, - const size_t gap, const size_t max_distance, + const size_t dictionary_distance, const size_t max_distance, HasherSearchResult* BROTLI_RESTRICT out) { - HashRolling* self = FN(Self)(handle); const size_t cur_ix_masked = cur_ix & ring_buffer_mask; - size_t pos = self->next_ix; + size_t pos; if ((cur_ix & (JUMP - 1)) != 0) return; @@ -209,7 +205,7 @@ static BROTLI_INLINE void FN(FindLongestMatch)(HasherHandle handle, backup-hasher, the main hasher already searches in it. */ BROTLI_UNUSED(dictionary); BROTLI_UNUSED(distance_cache); - BROTLI_UNUSED(gap); + BROTLI_UNUSED(dictionary_distance); BROTLI_UNUSED(max_distance); } diff --git a/modules/brotli/enc/hash_to_binary_tree_inc.h b/modules/brotli/enc/hash_to_binary_tree_inc.h index 7fb0356f55..9880e0aef6 100644 --- a/modules/brotli/enc/hash_to_binary_tree_inc.h +++ b/modules/brotli/enc/hash_to_binary_tree_inc.h @@ -24,7 +24,7 @@ static BROTLI_INLINE size_t FN(StoreLookahead)(void) { return MAX_TREE_COMP_LENGTH; } -static uint32_t FN(HashBytes)(const uint8_t* data) { +static uint32_t FN(HashBytes)(const uint8_t* BROTLI_RESTRICT data) { uint32_t h = BROTLI_UNALIGNED_LOAD32LE(data) * kHashMul32; /* The higher bits contain more mixture from the multiplication, so we take our results from there. */ @@ -38,7 +38,7 @@ typedef struct HashToBinaryTree { /* Hash table that maps the 4-byte hashes of the sequence to the last position where this hash was found, which is the root of the binary tree of sequences that share this hash bucket. */ - uint32_t buckets_[BUCKET_SIZE]; + uint32_t* buckets_; /* uint32_t[BUCKET_SIZE]; */ /* A position used to mark a non-existent sequence, i.e. a tree is empty if its root is at invalid_pos_ and a node is a leaf if both its children @@ -51,34 +51,30 @@ typedef struct HashToBinaryTree { corresponding to a hash is a sequence starting at buckets_[hash] and the left and right children of a sequence starting at pos are forest_[2 * pos] and forest_[2 * pos + 1]. */ - /* uint32_t forest[2 * num_nodes] */ + uint32_t* forest_; /* uint32_t[2 * num_nodes] */ } HashToBinaryTree; -static BROTLI_INLINE HashToBinaryTree* FN(Self)(HasherHandle handle) { - return (HashToBinaryTree*)&(GetHasherCommon(handle)[1]); -} - -static BROTLI_INLINE uint32_t* FN(Forest)(HashToBinaryTree* self) { - return (uint32_t*)(&self[1]); -} - static void FN(Initialize)( - HasherHandle handle, const BrotliEncoderParams* params) { - HashToBinaryTree* self = FN(Self)(handle); + HasherCommon* common, HashToBinaryTree* BROTLI_RESTRICT self, + const BrotliEncoderParams* params) { + self->buckets_ = (uint32_t*)common->extra; + self->forest_ = &self->buckets_[BUCKET_SIZE]; + self->window_mask_ = (1u << params->lgwin) - 1u; self->invalid_pos_ = (uint32_t)(0 - self->window_mask_); } -static void FN(Prepare)(HasherHandle handle, BROTLI_BOOL one_shot, - size_t input_size, const uint8_t* data) { - HashToBinaryTree* self = FN(Self)(handle); +static void FN(Prepare) + (HashToBinaryTree* BROTLI_RESTRICT self, BROTLI_BOOL one_shot, + size_t input_size, const uint8_t* BROTLI_RESTRICT data) { uint32_t invalid_pos = self->invalid_pos_; uint32_t i; + uint32_t* BROTLI_RESTRICT buckets = self->buckets_; BROTLI_UNUSED(data); BROTLI_UNUSED(one_shot); BROTLI_UNUSED(input_size); for (i = 0; i < BUCKET_SIZE; i++) { - self->buckets_[i] = invalid_pos; + buckets[i] = invalid_pos; } } @@ -89,15 +85,17 @@ static BROTLI_INLINE size_t FN(HashMemAllocInBytes)( if (one_shot && input_size < num_nodes) { num_nodes = input_size; } - return sizeof(HashToBinaryTree) + 2 * sizeof(uint32_t) * num_nodes; + return sizeof(uint32_t) * BUCKET_SIZE + 2 * sizeof(uint32_t) * num_nodes; } -static BROTLI_INLINE size_t FN(LeftChildIndex)(HashToBinaryTree* self, +static BROTLI_INLINE size_t FN(LeftChildIndex)( + HashToBinaryTree* BROTLI_RESTRICT self, const size_t pos) { return 2 * (pos & self->window_mask_); } -static BROTLI_INLINE size_t FN(RightChildIndex)(HashToBinaryTree* self, +static BROTLI_INLINE size_t FN(RightChildIndex)( + HashToBinaryTree* BROTLI_RESTRICT self, const size_t pos) { return 2 * (pos & self->window_mask_) + 1; } @@ -113,7 +111,7 @@ static BROTLI_INLINE size_t FN(RightChildIndex)(HashToBinaryTree* self, This function must be called with increasing cur_ix positions. */ static BROTLI_INLINE BackwardMatch* FN(StoreAndFindMatches)( - HashToBinaryTree* self, const uint8_t* const BROTLI_RESTRICT data, + HashToBinaryTree* BROTLI_RESTRICT self, const uint8_t* BROTLI_RESTRICT data, const size_t cur_ix, const size_t ring_buffer_mask, const size_t max_length, const size_t max_backward, size_t* const BROTLI_RESTRICT best_len, BackwardMatch* BROTLI_RESTRICT matches) { @@ -123,8 +121,9 @@ static BROTLI_INLINE BackwardMatch* FN(StoreAndFindMatches)( const BROTLI_BOOL should_reroot_tree = TO_BROTLI_BOOL(max_length >= MAX_TREE_COMP_LENGTH); const uint32_t key = FN(HashBytes)(&data[cur_ix_masked]); - uint32_t* forest = FN(Forest)(self); - size_t prev_ix = self->buckets_[key]; + uint32_t* BROTLI_RESTRICT buckets = self->buckets_; + uint32_t* BROTLI_RESTRICT forest = self->forest_; + size_t prev_ix = buckets[key]; /* The forest index of the rightmost node of the left subtree of the new root, updated as we traverse and re-root the tree of the hash bucket. */ size_t node_left = FN(LeftChildIndex)(self, cur_ix); @@ -139,7 +138,7 @@ static BROTLI_INLINE BackwardMatch* FN(StoreAndFindMatches)( size_t best_len_right = 0; size_t depth_remaining; if (should_reroot_tree) { - self->buckets_[key] = (uint32_t)cur_ix; + buckets[key] = (uint32_t)cur_ix; } for (depth_remaining = MAX_TREE_SEARCH_DEPTH; ; --depth_remaining) { const size_t backward = cur_ix - prev_ix; @@ -199,11 +198,13 @@ static BROTLI_INLINE BackwardMatch* FN(StoreAndFindMatches)( matches in matches[0] to matches[*num_matches - 1]. The matches will be sorted by strictly increasing length and (non-strictly) increasing distance. */ -static BROTLI_INLINE size_t FN(FindAllMatches)(HasherHandle handle, - const BrotliEncoderDictionary* dictionary, const uint8_t* data, +static BROTLI_INLINE size_t FN(FindAllMatches)( + HashToBinaryTree* BROTLI_RESTRICT self, + const BrotliEncoderDictionary* dictionary, + const uint8_t* BROTLI_RESTRICT data, const size_t ring_buffer_mask, const size_t cur_ix, const size_t max_length, const size_t max_backward, - const size_t gap, const BrotliEncoderParams* params, + const size_t dictionary_distance, const BrotliEncoderParams* params, BackwardMatch* matches) { BackwardMatch* const orig_matches = matches; const size_t cur_ix_masked = cur_ix & ring_buffer_mask; @@ -236,7 +237,7 @@ static BROTLI_INLINE size_t FN(FindAllMatches)(HasherHandle handle, } } if (best_len < max_length) { - matches = FN(StoreAndFindMatches)(FN(Self)(handle), data, cur_ix, + matches = FN(StoreAndFindMatches)(self, data, cur_ix, ring_buffer_mask, max_length, max_backward, &best_len, matches); } for (i = 0; i <= BROTLI_MAX_STATIC_DICTIONARY_MATCH_LEN; ++i) { @@ -252,7 +253,7 @@ static BROTLI_INLINE size_t FN(FindAllMatches)(HasherHandle handle, for (l = minlen; l <= maxlen; ++l) { uint32_t dict_id = dict_matches[l]; if (dict_id < kInvalidMatch) { - size_t distance = max_backward + gap + (dict_id >> 5) + 1; + size_t distance = dictionary_distance + (dict_id >> 5) + 1; if (distance <= params->dist.max_distance) { InitDictionaryBackwardMatch(matches++, distance, l, dict_id & 31); } @@ -266,18 +267,18 @@ static BROTLI_INLINE size_t FN(FindAllMatches)(HasherHandle handle, /* Stores the hash of the next 4 bytes and re-roots the binary tree at the current sequence, without returning any matches. REQUIRES: ix + MAX_TREE_COMP_LENGTH <= end-of-current-block */ -static BROTLI_INLINE void FN(Store)(HasherHandle handle, const uint8_t* data, +static BROTLI_INLINE void FN(Store)(HashToBinaryTree* BROTLI_RESTRICT self, + const uint8_t* BROTLI_RESTRICT data, const size_t mask, const size_t ix) { - HashToBinaryTree* self = FN(Self)(handle); /* Maximum distance is window size - 16, see section 9.1. of the spec. */ const size_t max_backward = self->window_mask_ - BROTLI_WINDOW_GAP + 1; FN(StoreAndFindMatches)(self, data, ix, mask, MAX_TREE_COMP_LENGTH, max_backward, NULL, NULL); } -static BROTLI_INLINE void FN(StoreRange)(HasherHandle handle, - const uint8_t* data, const size_t mask, const size_t ix_start, - const size_t ix_end) { +static BROTLI_INLINE void FN(StoreRange)(HashToBinaryTree* BROTLI_RESTRICT self, + const uint8_t* BROTLI_RESTRICT data, const size_t mask, + const size_t ix_start, const size_t ix_end) { size_t i = ix_start; size_t j = ix_start; if (ix_start + 63 <= ix_end) { @@ -285,18 +286,18 @@ static BROTLI_INLINE void FN(StoreRange)(HasherHandle handle, } if (ix_start + 512 <= i) { for (; j < i; j += 8) { - FN(Store)(handle, data, mask, j); + FN(Store)(self, data, mask, j); } } for (; i < ix_end; ++i) { - FN(Store)(handle, data, mask, i); + FN(Store)(self, data, mask, i); } } -static BROTLI_INLINE void FN(StitchToPreviousBlock)(HasherHandle handle, +static BROTLI_INLINE void FN(StitchToPreviousBlock)( + HashToBinaryTree* BROTLI_RESTRICT self, size_t num_bytes, size_t position, const uint8_t* ringbuffer, size_t ringbuffer_mask) { - HashToBinaryTree* self = FN(Self)(handle); if (num_bytes >= FN(HashTypeLength)() - 1 && position >= MAX_TREE_COMP_LENGTH) { /* Store the last `MAX_TREE_COMP_LENGTH - 1` positions in the hasher. diff --git a/modules/brotli/enc/memory.h b/modules/brotli/enc/memory.h index ab928d019b..832e7b2b6e 100644 --- a/modules/brotli/enc/memory.h +++ b/modules/brotli/enc/memory.h @@ -56,6 +56,18 @@ BROTLI_INTERNAL void BrotliFree(MemoryManager* m, void* p); #define BROTLI_IS_OOM(M) (!!(M)->is_oom) #endif /* BROTLI_ENCODER_EXIT_ON_OOM */ +/* +BROTLI_IS_NULL is a fake check, BROTLI_IS_OOM does the heavy lifting. +The only purpose of it is to explain static analyzers the state of things. +NB: use ONLY together with BROTLI_IS_OOM + AND ONLY for allocations in the current scope. + */ +#if defined(__clang_analyzer__) && !defined(BROTLI_ENCODER_EXIT_ON_OOM) +#define BROTLI_IS_NULL(A) ((A) == nullptr) +#else /* defined(__clang_analyzer__) */ +#define BROTLI_IS_NULL(A) (!!0) +#endif /* defined(__clang_analyzer__) */ + BROTLI_INTERNAL void BrotliWipeOutMemoryManager(MemoryManager* m); /* @@ -66,18 +78,18 @@ A: array C: capacity R: requested size */ -#define BROTLI_ENSURE_CAPACITY(M, T, A, C, R) { \ - if (C < (R)) { \ - size_t _new_size = (C == 0) ? (R) : C; \ - T* new_array; \ - while (_new_size < (R)) _new_size *= 2; \ - new_array = BROTLI_ALLOC((M), T, _new_size); \ - if (!BROTLI_IS_OOM(M) && C != 0) \ - memcpy(new_array, A, C * sizeof(T)); \ - BROTLI_FREE((M), A); \ - A = new_array; \ - C = _new_size; \ - } \ +#define BROTLI_ENSURE_CAPACITY(M, T, A, C, R) { \ + if (C < (R)) { \ + size_t _new_size = (C == 0) ? (R) : C; \ + T* new_array; \ + while (_new_size < (R)) _new_size *= 2; \ + new_array = BROTLI_ALLOC((M), T, _new_size); \ + if (!BROTLI_IS_OOM(M) && !BROTLI_IS_NULL(new_array) && C != 0) \ + memcpy(new_array, A, C * sizeof(T)); \ + BROTLI_FREE((M), A); \ + A = new_array; \ + C = _new_size; \ + } \ } /* diff --git a/modules/brotli/enc/metablock.c b/modules/brotli/enc/metablock.c index 4e80044f31..5aa4d4f17c 100644 --- a/modules/brotli/enc/metablock.c +++ b/modules/brotli/enc/metablock.c @@ -28,34 +28,30 @@ extern "C" { void BrotliInitDistanceParams(BrotliEncoderParams* params, uint32_t npostfix, uint32_t ndirect) { BrotliDistanceParams* dist_params = ¶ms->dist; - uint32_t alphabet_size, max_distance; + uint32_t alphabet_size_max; + uint32_t alphabet_size_limit; + uint32_t max_distance; dist_params->distance_postfix_bits = npostfix; dist_params->num_direct_distance_codes = ndirect; - alphabet_size = BROTLI_DISTANCE_ALPHABET_SIZE( + alphabet_size_max = BROTLI_DISTANCE_ALPHABET_SIZE( npostfix, ndirect, BROTLI_MAX_DISTANCE_BITS); + alphabet_size_limit = alphabet_size_max; max_distance = ndirect + (1U << (BROTLI_MAX_DISTANCE_BITS + npostfix + 2)) - (1U << (npostfix + 2)); if (params->large_window) { - static const uint32_t bound[BROTLI_MAX_NPOSTFIX + 1] = {0, 4, 12, 28}; - uint32_t postfix = 1U << npostfix; - alphabet_size = BROTLI_DISTANCE_ALPHABET_SIZE( + BrotliDistanceCodeLimit limit = BrotliCalculateDistanceCodeLimit( + BROTLI_MAX_ALLOWED_DISTANCE, npostfix, ndirect); + alphabet_size_max = BROTLI_DISTANCE_ALPHABET_SIZE( npostfix, ndirect, BROTLI_LARGE_MAX_DISTANCE_BITS); - /* The maximum distance is set so that no distance symbol used can encode - a distance larger than BROTLI_MAX_ALLOWED_DISTANCE with all - its extra bits set. */ - if (ndirect < bound[npostfix]) { - max_distance = BROTLI_MAX_ALLOWED_DISTANCE - (bound[npostfix] - ndirect); - } else if (ndirect >= bound[npostfix] + postfix) { - max_distance = (3U << 29) - 4 + (ndirect - bound[npostfix]); - } else { - max_distance = BROTLI_MAX_ALLOWED_DISTANCE; - } + alphabet_size_limit = limit.max_alphabet_size; + max_distance = limit.max_distance; } - dist_params->alphabet_size = alphabet_size; + dist_params->alphabet_size_max = alphabet_size_max; + dist_params->alphabet_size_limit = alphabet_size_limit; dist_params->max_distance = max_distance; } @@ -200,7 +196,7 @@ void BrotliBuildMetaBlock(MemoryManager* m, literal_context_multiplier = 1 << BROTLI_LITERAL_CONTEXT_BITS; literal_context_modes = BROTLI_ALLOC(m, ContextType, mb->literal_split.num_types); - if (BROTLI_IS_OOM(m)) return; + if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(literal_context_modes)) return; for (i = 0; i < mb->literal_split.num_types; ++i) { literal_context_modes[i] = literal_context_mode; } @@ -210,21 +206,21 @@ void BrotliBuildMetaBlock(MemoryManager* m, mb->literal_split.num_types * literal_context_multiplier; literal_histograms = BROTLI_ALLOC(m, HistogramLiteral, literal_histograms_size); - if (BROTLI_IS_OOM(m)) return; + if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(literal_histograms)) return; ClearHistogramsLiteral(literal_histograms, literal_histograms_size); distance_histograms_size = mb->distance_split.num_types << BROTLI_DISTANCE_CONTEXT_BITS; distance_histograms = BROTLI_ALLOC(m, HistogramDistance, distance_histograms_size); - if (BROTLI_IS_OOM(m)) return; + if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(distance_histograms)) return; ClearHistogramsDistance(distance_histograms, distance_histograms_size); BROTLI_DCHECK(mb->command_histograms == 0); mb->command_histograms_size = mb->command_split.num_types; mb->command_histograms = BROTLI_ALLOC(m, HistogramCommand, mb->command_histograms_size); - if (BROTLI_IS_OOM(m)) return; + if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(mb->command_histograms)) return; ClearHistogramsCommand(mb->command_histograms, mb->command_histograms_size); BrotliBuildHistogramsWithContext(cmds, num_commands, @@ -238,13 +234,13 @@ void BrotliBuildMetaBlock(MemoryManager* m, mb->literal_split.num_types << BROTLI_LITERAL_CONTEXT_BITS; mb->literal_context_map = BROTLI_ALLOC(m, uint32_t, mb->literal_context_map_size); - if (BROTLI_IS_OOM(m)) return; + if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(mb->literal_context_map)) return; BROTLI_DCHECK(mb->literal_histograms == 0); mb->literal_histograms_size = mb->literal_context_map_size; mb->literal_histograms = BROTLI_ALLOC(m, HistogramLiteral, mb->literal_histograms_size); - if (BROTLI_IS_OOM(m)) return; + if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(mb->literal_histograms)) return; BrotliClusterHistogramsLiteral(m, literal_histograms, literal_histograms_size, kMaxNumberOfHistograms, mb->literal_histograms, @@ -269,13 +265,13 @@ void BrotliBuildMetaBlock(MemoryManager* m, mb->distance_split.num_types << BROTLI_DISTANCE_CONTEXT_BITS; mb->distance_context_map = BROTLI_ALLOC(m, uint32_t, mb->distance_context_map_size); - if (BROTLI_IS_OOM(m)) return; + if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(mb->distance_context_map)) return; BROTLI_DCHECK(mb->distance_histograms == 0); mb->distance_histograms_size = mb->distance_context_map_size; mb->distance_histograms = BROTLI_ALLOC(m, HistogramDistance, mb->distance_histograms_size); - if (BROTLI_IS_OOM(m)) return; + if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(mb->distance_histograms)) return; BrotliClusterHistogramsDistance(m, distance_histograms, mb->distance_context_map_size, @@ -373,7 +369,7 @@ static void InitContextBlockSplitter( *histograms_size = max_num_types * num_contexts; *histograms = BROTLI_ALLOC(m, HistogramLiteral, *histograms_size); self->histograms_ = *histograms; - if (BROTLI_IS_OOM(m)) return; + if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(*histograms)) return; /* Clear only current histogram. */ ClearHistogramsLiteral(&self->histograms_[0], num_contexts); self->last_histogram_ix_[0] = self->last_histogram_ix_[1] = 0; @@ -423,7 +419,7 @@ static void ContextBlockSplitterFinishBlock( double combined_entropy[2 * BROTLI_MAX_STATIC_CONTEXTS]; double diff[2] = { 0.0 }; size_t i; - if (BROTLI_IS_OOM(m)) return; + if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(combined_histo)) return; for (i = 0; i < num_contexts; ++i) { size_t curr_histo_ix = self->curr_histogram_ix_ + i; size_t j; @@ -527,7 +523,7 @@ static void MapStaticContexts(MemoryManager* m, mb->literal_split.num_types << BROTLI_LITERAL_CONTEXT_BITS; mb->literal_context_map = BROTLI_ALLOC(m, uint32_t, mb->literal_context_map_size); - if (BROTLI_IS_OOM(m)) return; + if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(mb->literal_context_map)) return; for (i = 0; i < mb->literal_split.num_types; ++i) { uint32_t offset = (uint32_t)(i * num_contexts); diff --git a/modules/brotli/enc/metablock_inc.h b/modules/brotli/enc/metablock_inc.h index dcc9d3c4a6..ed507ef5ef 100644 --- a/modules/brotli/enc/metablock_inc.h +++ b/modules/brotli/enc/metablock_inc.h @@ -71,7 +71,7 @@ static void FN(InitBlockSplitter)( *histograms_size = max_num_types; *histograms = BROTLI_ALLOC(m, HistogramType, *histograms_size); self->histograms_ = *histograms; - if (BROTLI_IS_OOM(m)) return; + if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(*histograms)) return; /* Clear only current histogram. */ FN(HistogramClear)(&self->histograms_[0]); self->last_histogram_ix_[0] = self->last_histogram_ix_[1] = 0; diff --git a/modules/brotli/enc/params.h b/modules/brotli/enc/params.h index 6ecf1d3f99..54a7f00736 100644 --- a/modules/brotli/enc/params.h +++ b/modules/brotli/enc/params.h @@ -23,7 +23,8 @@ typedef struct BrotliHasherParams { typedef struct BrotliDistanceParams { uint32_t distance_postfix_bits; uint32_t num_direct_distance_codes; - uint32_t alphabet_size; + uint32_t alphabet_size_max; + uint32_t alphabet_size_limit; size_t max_distance; } BrotliDistanceParams; @@ -33,6 +34,7 @@ typedef struct BrotliEncoderParams { int quality; int lgwin; int lgblock; + size_t stream_offset; size_t size_hint; BROTLI_BOOL disable_literal_context_modeling; BROTLI_BOOL large_window; diff --git a/modules/brotli/enc/ringbuffer.h b/modules/brotli/enc/ringbuffer.h index 86079a89d3..8dce148039 100644 --- a/modules/brotli/enc/ringbuffer.h +++ b/modules/brotli/enc/ringbuffer.h @@ -75,7 +75,7 @@ static BROTLI_INLINE void RingBufferInitBuffer( uint8_t* new_data = BROTLI_ALLOC( m, uint8_t, 2 + buflen + kSlackForEightByteHashingEverywhere); size_t i; - if (BROTLI_IS_OOM(m)) return; + if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(new_data)) return; if (rb->data_) { memcpy(new_data, rb->data_, 2 + rb->cur_size_ + kSlackForEightByteHashingEverywhere); @@ -125,6 +125,9 @@ static BROTLI_INLINE void RingBufferWrite( later when we copy the last two bytes to the first two positions. */ rb->buffer_[rb->size_ - 2] = 0; rb->buffer_[rb->size_ - 1] = 0; + /* Initialize tail; might be touched by "best_len++" optimization when + ring buffer is "full". */ + rb->buffer_[rb->size_] = 241; } { const size_t masked_pos = rb->pos_ & rb->mask_; diff --git a/modules/brotli/enc/utf8_util.c b/modules/brotli/enc/utf8_util.c index 04a7805161..e802b6a751 100644 --- a/modules/brotli/enc/utf8_util.c +++ b/modules/brotli/enc/utf8_util.c @@ -77,7 +77,7 @@ BROTLI_BOOL BrotliIsMostlyUTF8( i += bytes_read; if (symbol < 0x110000) size_utf8 += bytes_read; } - return TO_BROTLI_BOOL(size_utf8 > min_fraction * (double)length); + return TO_BROTLI_BOOL((double)size_utf8 > min_fraction * (double)length); } #if defined(__cplusplus) || defined(c_plusplus) diff --git a/modules/brotli/enc/write_bits.h b/modules/brotli/enc/write_bits.h index 36515a6893..f6f88b45be 100644 --- a/modules/brotli/enc/write_bits.h +++ b/modules/brotli/enc/write_bits.h @@ -16,8 +16,6 @@ extern "C" { #endif -/*#define BIT_WRITER_DEBUG */ - /* This function writes bits into bytes in increasing addresses, and within a byte least-significant-bit first. @@ -28,7 +26,7 @@ extern "C" { 0000 0RRR 0000 0000 0000 0000 - Now, we could write 5 or less bits in MSB by just sifting by 3 + Now, we could write 5 or less bits in MSB by just shifting by 3 and OR'ing to BYTE-0. For n bits, we take the last 5 bits, OR that with high bits in BYTE-0, @@ -37,37 +35,41 @@ static BROTLI_INLINE void BrotliWriteBits(size_t n_bits, uint64_t bits, size_t* BROTLI_RESTRICT pos, uint8_t* BROTLI_RESTRICT array) { + BROTLI_LOG(("WriteBits %2d 0x%08x%08x %10d\n", (int)n_bits, + (uint32_t)(bits >> 32), (uint32_t)(bits & 0xFFFFFFFF), + (int)*pos)); + BROTLI_DCHECK((bits >> n_bits) == 0); + BROTLI_DCHECK(n_bits <= 56); #if defined(BROTLI_LITTLE_ENDIAN) /* This branch of the code can write up to 56 bits at a time, 7 bits are lost by being perhaps already in *p and at least 1 bit is needed to initialize the bit-stream ahead (i.e. if 7 bits are in *p and we write 57 bits, then the next write will access a byte that was never initialized). */ - uint8_t* p = &array[*pos >> 3]; - uint64_t v = (uint64_t)(*p); /* Zero-extend 8 to 64 bits. */ - BROTLI_LOG(("WriteBits %2d 0x%08x%08x %10d\n", (int)n_bits, - (uint32_t)(bits >> 32), (uint32_t)(bits & 0xFFFFFFFF), - (int)*pos)); - BROTLI_DCHECK((bits >> n_bits) == 0); - BROTLI_DCHECK(n_bits <= 56); - v |= bits << (*pos & 7); - BROTLI_UNALIGNED_STORE64LE(p, v); /* Set some bits. */ - *pos += n_bits; + { + uint8_t* p = &array[*pos >> 3]; + uint64_t v = (uint64_t)(*p); /* Zero-extend 8 to 64 bits. */ + v |= bits << (*pos & 7); + BROTLI_UNALIGNED_STORE64LE(p, v); /* Set some bits. */ + *pos += n_bits; + } #else /* implicit & 0xFF is assumed for uint8_t arithmetics */ - uint8_t* array_pos = &array[*pos >> 3]; - const size_t bits_reserved_in_first_byte = (*pos & 7); - size_t bits_left_to_write; - bits <<= bits_reserved_in_first_byte; - *array_pos++ |= (uint8_t)bits; - for (bits_left_to_write = n_bits + bits_reserved_in_first_byte; - bits_left_to_write >= 9; - bits_left_to_write -= 8) { - bits >>= 8; - *array_pos++ = (uint8_t)bits; + { + uint8_t* array_pos = &array[*pos >> 3]; + const size_t bits_reserved_in_first_byte = (*pos & 7); + size_t bits_left_to_write; + bits <<= bits_reserved_in_first_byte; + *array_pos++ |= (uint8_t)bits; + for (bits_left_to_write = n_bits + bits_reserved_in_first_byte; + bits_left_to_write >= 9; + bits_left_to_write -= 8) { + bits >>= 8; + *array_pos++ = (uint8_t)bits; + } + *array_pos = 0; + *pos += n_bits; } - *array_pos = 0; - *pos += n_bits; #endif } diff --git a/modules/brotli/include/brotli/encode.h b/modules/brotli/include/brotli/encode.h index 0ced7e55be..b2774cb631 100644 --- a/modules/brotli/include/brotli/encode.h +++ b/modules/brotli/include/brotli/encode.h @@ -201,7 +201,23 @@ typedef enum BrotliEncoderParameter { * * Range is from 0 to (15 << NPOSTFIX) in steps of (1 << NPOSTFIX). */ - BROTLI_PARAM_NDIRECT = 8 + BROTLI_PARAM_NDIRECT = 8, + /** + * Number of bytes of input stream already processed by a different instance. + * + * @note It is important to configure all the encoder instances with same + * parameters (except this one) in order to allow all the encoded parts + * obey the same restrictions implied by header. + * + * If offset is not 0, then stream header is omitted. + * In any case output start is byte aligned, so for proper streams stitching + * "predecessor" stream must be flushed. + * + * Range is not artificially limited, but all the values greater or equal to + * maximal window size have the same effect. Values greater than 2**30 are not + * allowed. + */ + BROTLI_PARAM_STREAM_OFFSET = 9 } BrotliEncoderParameter; /** @@ -274,6 +290,11 @@ BROTLI_ENC_API size_t BrotliEncoderMaxCompressedSize(size_t input_size); * @note If ::BrotliEncoderMaxCompressedSize(@p input_size) returns non-zero * value, then output is guaranteed to be no longer than that. * + * @note If @p lgwin is greater than ::BROTLI_MAX_WINDOW_BITS then resulting + * stream might be incompatible with RFC 7932; to decode such streams, + * decoder should be configured with + * ::BROTLI_DECODER_PARAM_LARGE_WINDOW = @c 1 + * * @param quality quality parameter value, e.g. ::BROTLI_DEFAULT_QUALITY * @param lgwin lgwin parameter value, e.g. ::BROTLI_DEFAULT_WINDOW * @param mode mode parameter value, e.g. ::BROTLI_DEFAULT_MODE diff --git a/modules/brotli/include/brotli/port.h b/modules/brotli/include/brotli/port.h index 20dc2314d8..825237a335 100644 --- a/modules/brotli/include/brotli/port.h +++ b/modules/brotli/include/brotli/port.h @@ -218,6 +218,20 @@ BROTLI_GNUC_VERSION_CHECK(major, minor, patch) #endif +#if defined(__has_feature) +#define BROTLI_HAS_FEATURE(feature) __has_feature(feature) +#else +#define BROTLI_HAS_FEATURE(feature) (0) +#endif + +#if defined(ADDRESS_SANITIZER) || BROTLI_HAS_FEATURE(address_sanitizer) || \ + defined(THREAD_SANITIZER) || BROTLI_HAS_FEATURE(thread_sanitizer) || \ + defined(MEMORY_SANITIZER) || BROTLI_HAS_FEATURE(memory_sanitizer) +#define BROTLI_SANITIZED 1 +#else +#define BROTLI_SANITIZED 0 +#endif + #if defined(_WIN32) || defined(__CYGWIN__) #define BROTLI_PUBLIC #elif BROTLI_GNUC_VERSION_CHECK(3, 3, 0) || \ diff --git a/modules/brotli/moz.build b/modules/brotli/moz.build index 8e4177f418..95445ce5b7 100644 --- a/modules/brotli/moz.build +++ b/modules/brotli/moz.build @@ -14,7 +14,10 @@ EXPORTS.brotli += [ ] SOURCES += [ + 'common/constants.c', + 'common/context.c', 'common/dictionary.c', + 'common/platform.c', 'common/transform.c', 'dec/bit_reader.c', 'dec/decode.c', @@ -44,12 +47,14 @@ HOST_SOURCES += [ 'enc/block_splitter.c', 'enc/brotli_bit_stream.c', 'enc/cluster.c', + 'enc/command.c', 'enc/compress_fragment.c', 'enc/compress_fragment_two_pass.c', 'enc/dictionary_hash.c', 'enc/encode.c', 'enc/encoder_dict.c', 'enc/entropy_encode.c', + 'enc/fast_log.c', 'enc/histogram.c', 'enc/literal_cost.c', 'enc/memory.c', diff --git a/modules/brotli/tools/brotli.c b/modules/brotli/tools/brotli.c index ce05b641b2..7c678d3d8f 100644 --- a/modules/brotli/tools/brotli.c +++ b/modules/brotli/tools/brotli.c @@ -6,6 +6,11 @@ /* Command line interface for Brotli library. */ +/* Mute strerror/strcpy warnings. */ +#if !defined(_CRT_SECURE_NO_WARNINGS) +#define _CRT_SECURE_NO_WARNINGS +#endif + #include #include #include @@ -86,10 +91,10 @@ typedef struct { /* Parameters */ int quality; int lgwin; + int verbosity; BROTLI_BOOL force_overwrite; BROTLI_BOOL junk_source; BROTLI_BOOL copy_stat; - BROTLI_BOOL verbose; BROTLI_BOOL write_to_stdout; BROTLI_BOOL test_integrity; BROTLI_BOOL decompress; @@ -121,6 +126,12 @@ typedef struct { const uint8_t* next_in; size_t available_out; uint8_t* next_out; + + /* Reporting */ + /* size_t would be large enough, + until 4GiB+ files are compressed / decompressed on 32-bit CPUs. */ + size_t total_in; + size_t total_out; } Context; /* Parse up to 5 decimal digits. */ @@ -257,7 +268,7 @@ static Command ParseParams(Context* params) { return COMMAND_HELP; } else if (c == 'j' || c == 'k') { if (keep_set) { - fprintf(stderr, "argument --rm / -j or --keep / -n already set\n"); + fprintf(stderr, "argument --rm / -j or --keep / -k already set\n"); return COMMAND_INVALID; } keep_set = BROTLI_TRUE; @@ -279,11 +290,11 @@ static Command ParseParams(Context* params) { command = COMMAND_TEST_INTEGRITY; continue; } else if (c == 'v') { - if (params->verbose) { + if (params->verbosity > 0) { fprintf(stderr, "argument --verbose / -v already set\n"); return COMMAND_INVALID; } - params->verbose = BROTLI_TRUE; + params->verbosity = 1; continue; } else if (c == 'V') { /* Don't parse further. */ @@ -382,7 +393,7 @@ static Command ParseParams(Context* params) { return COMMAND_HELP; } else if (strcmp("keep", arg) == 0) { if (keep_set) { - fprintf(stderr, "argument --rm / -j or --keep / -n already set\n"); + fprintf(stderr, "argument --rm / -j or --keep / -k already set\n"); return COMMAND_INVALID; } keep_set = BROTLI_TRUE; @@ -395,7 +406,7 @@ static Command ParseParams(Context* params) { params->copy_stat = BROTLI_FALSE; } else if (strcmp("rm", arg) == 0) { if (keep_set) { - fprintf(stderr, "argument --rm / -j or --keep / -n already set\n"); + fprintf(stderr, "argument --rm / -j or --keep / -k already set\n"); return COMMAND_INVALID; } keep_set = BROTLI_TRUE; @@ -415,11 +426,11 @@ static Command ParseParams(Context* params) { command_set = BROTLI_TRUE; command = COMMAND_TEST_INTEGRITY; } else if (strcmp("verbose", arg) == 0) { - if (params->verbose) { + if (params->verbosity > 0) { fprintf(stderr, "argument --verbose / -v already set\n"); return COMMAND_INVALID; } - params->verbose = BROTLI_TRUE; + params->verbosity = 1; } else if (strcmp("version", arg) == 0) { /* Don't parse further. */ return COMMAND_VERSION; @@ -550,11 +561,17 @@ static void PrintHelp(const char* name, BROTLI_BOOL error) { " -t, --test test compressed file integrity\n" " -v, --verbose verbose mode\n"); fprintf(media, -" -w NUM, --lgwin=NUM set LZ77 window size (0, %d-%d)\n", +" -w NUM, --lgwin=NUM set LZ77 window size (0, %d-%d)\n" +" window size = 2**NUM - 16\n" +" 0 lets compressor choose the optimal value\n", BROTLI_MIN_WINDOW_BITS, BROTLI_MAX_WINDOW_BITS); fprintf(media, -" window size = 2**NUM - 16\n" -" 0 lets compressor choose the optimal value\n"); +" --large_window=NUM use incompatible large-window brotli\n" +" bitstream with window size (0, %d-%d)\n" +" WARNING: this format is not compatible\n" +" with brotli RFC 7932 and may not be\n" +" decodable with regular brotli decoders\n", + BROTLI_MIN_WINDOW_BITS, BROTLI_LARGE_MAX_WINDOW_BITS); fprintf(media, " -S SUF, --suffix=SUF output file suffix (default:'%s')\n", DEFAULT_SUFFIX); @@ -787,8 +804,12 @@ static void InitializeBuffers(Context* context) { context->next_in = NULL; context->available_out = kFileBufferSize; context->next_out = context->output; + context->total_in = 0; + context->total_out = 0; } +/* This method might give the false-negative result. + However, after an empty / incomplete read it should tell the truth. */ static BROTLI_BOOL HasMoreInput(Context* context) { return feof(context->fin) ? BROTLI_FALSE : BROTLI_TRUE; } @@ -796,6 +817,7 @@ static BROTLI_BOOL HasMoreInput(Context* context) { static BROTLI_BOOL ProvideInput(Context* context) { context->available_in = fread(context->input, 1, kFileBufferSize, context->fin); + context->total_in += context->available_in; context->next_in = context->input; if (ferror(context->fin)) { fprintf(stderr, "failed to read input [%s]: %s\n", @@ -808,6 +830,7 @@ static BROTLI_BOOL ProvideInput(Context* context) { /* Internal: should be used only in Provide-/Flush-Output. */ static BROTLI_BOOL WriteOutput(Context* context) { size_t out_size = (size_t)(context->next_out - context->output); + context->total_out += out_size; if (out_size == 0) return BROTLI_TRUE; if (context->test_integrity) return BROTLI_TRUE; @@ -833,6 +856,25 @@ static BROTLI_BOOL FlushOutput(Context* context) { return BROTLI_TRUE; } +static void PrintBytes(size_t value) { + if (value < 1024) { + fprintf(stderr, "%d B", (int)value); + } else if (value < 1048576) { + fprintf(stderr, "%0.3f KiB", (double)value / 1024.0); + } else if (value < 1073741824) { + fprintf(stderr, "%0.3f MiB", (double)value / 1048576.0); + } else { + fprintf(stderr, "%0.3f GiB", (double)value / 1073741824.0); + } +} + +static void PrintFileProcessingProgress(Context* context) { + fprintf(stderr, "[%s]: ", PrintablePath(context->current_input_path)); + PrintBytes(context->total_in); + fprintf(stderr, " -> "); + PrintBytes(context->total_out); +} + static BROTLI_BOOL DecompressFile(Context* context, BrotliDecoderState* s) { BrotliDecoderResult result = BROTLI_DECODER_RESULT_NEEDS_MORE_INPUT; InitializeBuffers(context); @@ -848,11 +890,18 @@ static BROTLI_BOOL DecompressFile(Context* context, BrotliDecoderState* s) { if (!ProvideOutput(context)) return BROTLI_FALSE; } else if (result == BROTLI_DECODER_RESULT_SUCCESS) { if (!FlushOutput(context)) return BROTLI_FALSE; - if (context->available_in != 0 || HasMoreInput(context)) { + int has_more_input = + (context->available_in != 0) || (fgetc(context->fin) != EOF); + if (has_more_input) { fprintf(stderr, "corrupt input [%s]\n", PrintablePath(context->current_input_path)); return BROTLI_FALSE; } + if (context->verbosity > 0) { + fprintf(stderr, "Decompressed "); + PrintFileProcessingProgress(context); + fprintf(stderr, "\n"); + } return BROTLI_TRUE; } else { fprintf(stderr, "corrupt input [%s]\n", @@ -915,7 +964,13 @@ static BROTLI_BOOL CompressFile(Context* context, BrotliEncoderState* s) { } if (BrotliEncoderIsFinished(s)) { - return FlushOutput(context); + if (!FlushOutput(context)) return BROTLI_FALSE; + if (context->verbosity > 0) { + fprintf(stderr, "Compressed "); + PrintFileProcessingProgress(context); + fprintf(stderr, "\n"); + } + return BROTLI_TRUE; } } } @@ -979,11 +1034,11 @@ int main(int argc, char** argv) { context.quality = 11; context.lgwin = -1; + context.verbosity = 0; context.force_overwrite = BROTLI_FALSE; context.junk_source = BROTLI_FALSE; context.copy_stat = BROTLI_TRUE; context.test_integrity = BROTLI_FALSE; - context.verbose = BROTLI_FALSE; context.write_to_stdout = BROTLI_FALSE; context.decompress = BROTLI_FALSE; context.large_window = BROTLI_FALSE; diff --git a/modules/brotli/update.sh b/modules/brotli/update.sh index 4a98ce6a76..72717c9986 100644 --- a/modules/brotli/update.sh +++ b/modules/brotli/update.sh @@ -6,7 +6,7 @@ MY_TEMP_DIR=`mktemp -d -t brotli_update.XXXXXX` || exit 1 git clone https://github.com/google/brotli ${MY_TEMP_DIR}/brotli -git -C ${MY_TEMP_DIR}/brotli checkout v1.0.7 +git -C ${MY_TEMP_DIR}/brotli checkout v1.0.9 COMMIT=$(git -C ${MY_TEMP_DIR}/brotli rev-parse HEAD) perl -p -i -e "s/\[commit [0-9a-f]{40}\]/[commit ${COMMIT}]/" README.mozilla; From 48a4d205923e3b97022eac68e2985772db1443fb Mon Sep 17 00:00:00 2001 From: Moonchild Date: Fri, 13 Nov 2020 16:00:06 +0000 Subject: [PATCH 5/7] Issue #1683 - Update libjar module. --- modules/libjar/nsJARInputStream.cpp | 55 +++++++++++++++++++++++++---- modules/libjar/nsJARInputStream.h | 16 +++++++-- modules/libjar/nsZipArchive.cpp | 38 ++++++++++++++++++-- modules/libjar/nsZipArchive.h | 2 ++ modules/libjar/zipstruct.h | 3 +- 5 files changed, 101 insertions(+), 13 deletions(-) diff --git a/modules/libjar/nsJARInputStream.cpp b/modules/libjar/nsJARInputStream.cpp index 086c21ab4f..a1f6c1d560 100644 --- a/modules/libjar/nsJARInputStream.cpp +++ b/modules/libjar/nsJARInputStream.cpp @@ -7,6 +7,7 @@ #include "nsJARInputStream.h" #include "zipstruct.h" // defines ZIP compression codes +#include "brotli/decode.h" #include "nsZipArchive.h" #include "nsEscape.h" @@ -51,6 +52,13 @@ nsJARInputStream::InitFile(nsJAR *aJar, nsZipItem *item) mOutCrc = crc32(0L, Z_NULL, 0); break; + case MOZ_JAR_BROTLI: + mBrotliState = BrotliDecoderCreateInstance(nullptr, nullptr, nullptr); + mMode = MODE_BROTLI; + mInCrc = item->CRC32(); + mOutCrc = crc32(0L, Z_NULL, 0); + break; + default: return NS_ERROR_NOT_IMPLEMENTED; } @@ -166,6 +174,7 @@ nsJARInputStream::Available(uint64_t *_retval) break; case MODE_INFLATE: + case MODE_BROTLI: case MODE_COPY: *_retval = mOutSize - mZs.total_out; break; @@ -195,6 +204,7 @@ MOZ_WIN_MEM_TRY_BEGIN return ReadDirectory(aBuffer, aCount, aBytesRead); case MODE_INFLATE: + case MODE_BROTLI: if (mZs.total_out < mOutSize) { rv = ContinueInflate(aBuffer, aCount, aBytesRead); } @@ -246,6 +256,9 @@ nsJARInputStream::Close() if (mMode == MODE_INFLATE) { inflateEnd(&mZs); } + if (mMode == MODE_BROTLI) { + BrotliDecoderDestroyInstance(mBrotliState); + } mMode = MODE_CLOSED; mFd = nullptr; return NS_OK; @@ -255,6 +268,8 @@ nsresult nsJARInputStream::ContinueInflate(char* aBuffer, uint32_t aCount, uint32_t* aBytesRead) { + bool finished = false; + // No need to check the args, ::Read did that, but assert them at least NS_ASSERTION(aBuffer,"aBuffer parameter must not be null"); NS_ASSERTION(aBytesRead,"aBytesRead parameter must not be null"); @@ -266,11 +281,35 @@ nsJARInputStream::ContinueInflate(char* aBuffer, uint32_t aCount, mZs.avail_out = std::min(aCount, (mOutSize-oldTotalOut)); mZs.next_out = (unsigned char*)aBuffer; - // now inflate - int zerr = inflate(&mZs, Z_SYNC_FLUSH); - if ((zerr != Z_OK) && (zerr != Z_STREAM_END)) { - nsZipArchive::sFileCorruptedReason = "nsJARInputStream: error while inflating"; - return NS_ERROR_FILE_CORRUPTED; + if (mMode == MODE_INFLATE) { + // now inflate + int zerr = inflate(&mZs, Z_SYNC_FLUSH); + if ((zerr != Z_OK) && (zerr != Z_STREAM_END)) { + nsZipArchive::sFileCorruptedReason = "nsJARInputStream: error while inflating"; + return NS_ERROR_FILE_CORRUPTED; + } + finished = (zerr == Z_STREAM_END); + } else { + MOZ_ASSERT(mMode == MODE_BROTLI); + /* The brotli library wants size_t, but z_stream only contains + * unsigned int for avail_* and unsigned long for total_*. + * So use temporary stack values. */ + size_t avail_in = mZs.avail_in; + size_t avail_out = mZs.avail_out; + size_t total_out = mZs.total_out; + BrotliDecoderResult result = BrotliDecoderDecompressStream( + mBrotliState, + &avail_in, const_cast(&mZs.next_in), + &avail_out, &mZs.next_out, &total_out); + /* We don't need to update avail_out, it's not used outside this + * function. */ + mZs.total_out = total_out; + mZs.avail_in = avail_in; + if (result == BROTLI_DECODER_RESULT_ERROR) { + nsZipArchive::sFileCorruptedReason = "nsJARInputStream: brotli decompression error"; + return NS_ERROR_FILE_CORRUPTED; + } + finished = (result == BROTLI_DECODER_RESULT_SUCCESS); } *aBytesRead = (mZs.total_out - oldTotalOut); @@ -280,8 +319,10 @@ nsJARInputStream::ContinueInflate(char* aBuffer, uint32_t aCount, // be aggressive about ending the inflation // for some reason we don't always get Z_STREAM_END - if (zerr == Z_STREAM_END || mZs.total_out == mOutSize) { - inflateEnd(&mZs); + if (finished || mZs.total_out == mOutSize) { + if (mMode == MODE_INFLATE) { + inflateEnd(&mZs); + } // stop returning valid data as soon as we know we have a bad CRC if (mOutCrc != mInCrc) { diff --git a/modules/libjar/nsJARInputStream.h b/modules/libjar/nsJARInputStream.h index 1c396aa102..60c3d763ee 100644 --- a/modules/libjar/nsJARInputStream.h +++ b/modules/libjar/nsJARInputStream.h @@ -12,6 +12,8 @@ #include "nsTArray.h" #include "mozilla/Attributes.h" +struct BrotliDecoderStateStruct; + /*------------------------------------------------------------------------- * Class nsJARInputStream declaration. This class defines the type of the * object returned by calls to nsJAR::GetInputStream(filename) for the @@ -20,9 +22,15 @@ class nsJARInputStream final : public nsIInputStream { public: - nsJARInputStream() : - mOutSize(0), mInCrc(0), mOutCrc(0), mNameLen(0), - mCurPos(0), mArrPos(0), mMode(MODE_NOTINITED) + nsJARInputStream() + : mOutSize(0) + , mInCrc(0) + , mOutCrc(0) + , mBrotliState(nullptr) + , mNameLen(0) + , mCurPos(0) + , mArrPos(0) + , mMode(MODE_NOTINITED) { memset(&mZs, 0, sizeof(z_stream)); } @@ -45,6 +53,7 @@ class nsJARInputStream final : public nsIInputStream uint32_t mInCrc; // CRC as provided by the zipentry uint32_t mOutCrc; // CRC as calculated by me z_stream mZs; // zip data structure + BrotliDecoderStateStruct* mBrotliState; // Brotli decoder state /* For directory reading */ RefPtr mJar; // string reference to zipreader @@ -59,6 +68,7 @@ class nsJARInputStream final : public nsIInputStream MODE_CLOSED, MODE_DIRECTORY, MODE_INFLATE, + MODE_BROTLI, MODE_COPY } JISMode; diff --git a/modules/libjar/nsZipArchive.cpp b/modules/libjar/nsZipArchive.cpp index 2f12af5f0c..b28fddc181 100644 --- a/modules/libjar/nsZipArchive.cpp +++ b/modules/libjar/nsZipArchive.cpp @@ -4,7 +4,7 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ /* - * This module implements a simple archive extractor for the PKZIP format. + * This module implements a simple archive extractor. * * The underlying nsZipArchive is NOT thread-safe. Do not pass references * or pointers to it across thread boundaries. @@ -17,6 +17,7 @@ #define READTYPE int32_t #include "zlib.h" +#include "brotli/decode.h" #include "nsISupportsUtils.h" #include "prio.h" #include "plstr.h" @@ -1186,6 +1187,7 @@ nsZipCursor::nsZipCursor(nsZipItem *item, nsZipArchive *aZip, uint8_t* aBuf, : mItem(item) , mBuf(aBuf) , mBufSize(aBufSize) + , mBrotliState(nullptr) , mCRC(0) , mDoCRC(doCRC) { @@ -1200,6 +1202,10 @@ nsZipCursor::nsZipCursor(nsZipItem *item, nsZipArchive *aZip, uint8_t* aBuf, mZs.avail_in = item->Size(); mZs.next_in = (Bytef*)aZip->GetData(item); + + if (mItem->Compression() == MOZ_JAR_BROTLI) { + mBrotliState = BrotliDecoderCreateInstance(nullptr, nullptr, nullptr); + } if (doCRC) mCRC = crc32(0L, Z_NULL, 0); @@ -1210,6 +1216,9 @@ nsZipCursor::~nsZipCursor() if (mItem->Compression() == DEFLATED) { inflateEnd(&mZs); } + if (mItem->Compression() == MOZ_JAR_BROTLI) { + BrotliDecoderDestroyInstance(mBrotliState); + } } uint8_t* nsZipCursor::ReadOrCopy(uint32_t *aBytesRead, bool aCopy) { @@ -1246,6 +1255,29 @@ MOZ_WIN_MEM_TRY_BEGIN *aBytesRead = mZs.next_out - buf; verifyCRC = (zerr == Z_STREAM_END); break; + case MOZ_JAR_BROTLI: { + buf = mBuf; + mZs.next_out = buf; + /* The brotli library wants size_t, but z_stream only contains + * unsigned int for avail_*. So use temporary stack values. */ + size_t avail_out = mBufSize; + size_t avail_in = mZs.avail_in; + BrotliDecoderResult result = BrotliDecoderDecompressStream( + mBrotliState, + &avail_in, const_cast(&mZs.next_in), + &avail_out, &mZs.next_out, nullptr); + /* We don't need to update avail_out, it's not used outside this + * function. */ + mZs.avail_in = avail_in; + + if (result == BROTLI_DECODER_RESULT_ERROR) { + return nullptr; + } + + *aBytesRead = mZs.next_out - buf; + verifyCRC = (result == BROTLI_DECODER_RESULT_SUCCESS); + break; + } default: return nullptr; } @@ -1272,7 +1304,9 @@ nsZipItemPtr_base::nsZipItemPtr_base(nsZipArchive *aZip, return; uint32_t size = 0; - if (item->Compression() == DEFLATED) { + bool compressed = (item->Compression() == DEFLATED) || + (item->Compression() == MOZ_JAR_BROTLI); + if (compressed) { size = item->RealSize(); mAutoBuf = MakeUniqueFallible(size); if (!mAutoBuf) { diff --git a/modules/libjar/nsZipArchive.h b/modules/libjar/nsZipArchive.h index 2de6790327..6b758c9fd8 100644 --- a/modules/libjar/nsZipArchive.h +++ b/modules/libjar/nsZipArchive.h @@ -37,6 +37,7 @@ class nsZipFind; struct PRFileDesc; +struct BrotliDecoderStateStruct; /** * This file defines some of the basic structures used by libjar to @@ -314,6 +315,7 @@ private: uint8_t *mBuf; uint32_t mBufSize; z_stream mZs; + BrotliDecoderStateStruct* mBrotliState; uint32_t mCRC; bool mDoCRC; }; diff --git a/modules/libjar/zipstruct.h b/modules/libjar/zipstruct.h index f06afe14ea..f7393128a3 100644 --- a/modules/libjar/zipstruct.h +++ b/modules/libjar/zipstruct.h @@ -102,6 +102,7 @@ typedef struct ZipEnd_ #define TOKENIZED 7 #define DEFLATED 8 #define UNSUPPORTED 0xFF - +/* non-standard extension */ +#define MOZ_JAR_BROTLI 0x81 #endif /* _zipstruct_h */ From d0dbdf4e8b01f52ca53337b9d6a889352fc70aa2 Mon Sep 17 00:00:00 2001 From: Moonchild Date: Sat, 14 Nov 2020 01:03:27 +0000 Subject: [PATCH 6/7] [packager] Optimize archive accesses. --- python/mozbuild/mozpack/copier.py | 2 +- python/mozbuild/mozpack/mozjar.py | 103 +++++++++++++++++---- python/mozbuild/mozpack/packager/l10n.py | 6 +- python/mozbuild/mozpack/packager/unpack.py | 5 +- toolkit/mozapps/installer/packager.mk | 2 +- toolkit/mozapps/installer/packager.py | 17 +++- toolkit/mozapps/installer/upload-files.mk | 2 +- 7 files changed, 107 insertions(+), 30 deletions(-) diff --git a/python/mozbuild/mozpack/copier.py b/python/mozbuild/mozpack/copier.py index 386930fe72..15c550e7ba 100644 --- a/python/mozbuild/mozpack/copier.py +++ b/python/mozbuild/mozpack/copier.py @@ -535,7 +535,7 @@ class Jarrer(FileRegistry, BaseFile): dest = Dest(dest) assert isinstance(dest, Dest) - from mozpack.mozjar import JarWriter, JarReader + from mozpack.mozjar import JarWriter, JarReader, JAR_BROTLI try: old_jar = JarReader(fileobj=dest) except Exception: diff --git a/python/mozbuild/mozpack/mozjar.py b/python/mozbuild/mozpack/mozjar.py index a1ada85946..2010a7f135 100644 --- a/python/mozbuild/mozpack/mozjar.py +++ b/python/mozbuild/mozpack/mozjar.py @@ -6,6 +6,7 @@ from __future__ import absolute_import from io import BytesIO import struct +import subprocess import zlib import os from zipfile import ( @@ -15,9 +16,11 @@ from zipfile import ( from collections import OrderedDict from urlparse import urlparse, ParseResult import mozpack.path as mozpath +from mozbuild.util import memoize JAR_STORED = ZIP_STORED JAR_DEFLATED = ZIP_DEFLATED +JAR_BROTLI = 0x81 MAX_WBITS = 15 @@ -262,13 +265,14 @@ class JarFileReader(object): corresponding to the file in the jar archive, data a buffer containing the file data. ''' - assert header['compression'] in [JAR_DEFLATED, JAR_STORED] + assert header['compression'] in [JAR_DEFLATED, JAR_STORED, JAR_BROTLI] self._data = data # Copy some local file header fields. for name in ['filename', 'compressed_size', 'uncompressed_size', 'crc32']: setattr(self, name, header[name]) - self.compressed = header['compression'] == JAR_DEFLATED + self.compressed = header['compression'] != JAR_STORED + self.compress = header['compression'] def read(self, length=-1): ''' @@ -317,7 +321,11 @@ class JarFileReader(object): if hasattr(self, '_uncompressed_data'): return self._uncompressed_data data = self.compressed_data - if self.compressed: + if self.compress == JAR_STORED: + data = data.tobytes() + elif self.compress == JAR_BROTLI: + data = Brotli.decompress(data.tobytes()) + elif self.compress == JAR_DEFLATED: data = zlib.decompress(data.tobytes(), -MAX_WBITS) else: data = data.tobytes() @@ -360,6 +368,13 @@ class JarReader(object): ''' del self._data + @property + def compression(self): + entries = self.entries + if not entries: + return JAR_STORED + return max(f['compression'] for f in entries.itervalues()) + @property def entries(self): ''' @@ -473,6 +488,8 @@ class JarWriter(object): self._data = fileobj else: self._data = open(file, 'wb') + if compress is True: + compress = JAR_DEFLATED self._compress = compress self._compress_level = compress_level self._contents = OrderedDict() @@ -574,12 +591,13 @@ class JarWriter(object): ''' Add a new member to the jar archive, with the given name and the given data. - The compress option indicates if the given data should be compressed - (True), not compressed (False), or compressed according to the default - defined when creating the JarWriter (None). - When the data should be compressed (True or None with self.compress == - True), it is only really compressed if the compressed size is smaller - than the uncompressed size. + The compress option indicates how the given data should be compressed + (one of JAR_STORED, JAR_DEFLATE or JAR_BROTLI), or compressed according + to the default defined when creating the JarWriter (None). True and + False are allowed values for backwards compatibility, mapping, + respectively, to JAR_DEFLATE and JAR_STORED. + When the data should be compressed, it is only really compressed if + the compressed size is smaller than the uncompressed size. The mode option gives the unix permissions that should be stored for the jar entry. If a duplicated member is found skip_duplicates will prevent raising @@ -594,8 +612,12 @@ class JarWriter(object): raise JarWriterError("File %s already in JarWriter" % name) if compress is None: compress = self._compress - if (isinstance(data, JarFileReader) and data.compressed == compress) \ - or (isinstance(data, Deflater) and data.compress == compress): + if compress is True: + compress = JAR_DEFLATED + if compress is False: + compress = JAR_STORED + if (isinstance(data, (JarFileReader, Deflater)) and \ + data.compress == compress): deflater = data else: deflater = Deflater(compress, compress_level=self._compress_level) @@ -619,7 +641,7 @@ class JarWriter(object): if deflater.compressed: entry['min_version'] = 20 # Version 2.0 supports deflated streams entry['general_flag'] = 2 # Max compression - entry['compression'] = JAR_DEFLATED + entry['compression'] = deflater.compress else: entry['min_version'] = 10 # Version 1.0 for stored streams entry['general_flag'] = 0 @@ -659,14 +681,21 @@ class Deflater(object): ''' def __init__(self, compress=True, compress_level=9): ''' - Initialize a Deflater. The compress argument determines whether to - try to compress at all. + Initialize a Deflater. The compress argument determines how to + compress. ''' self._data = BytesIO() + if compress is True: + compress = JAR_DEFLATED + elif compress is False: + compress = JAR_STORED self.compress = compress - if compress: - self._deflater = zlib.compressobj(compress_level, zlib.DEFLATED, - -MAX_WBITS) + if compress in (JAR_DEFLATED, JAR_BROTLI): + if compress == JAR_DEFLATED: + self._deflater = zlib.compressobj( + compress_level, zlib.DEFLATED, -MAX_WBITS) + else: + self._deflater = BrotliCompress() self._deflated = BytesIO() else: self._deflater = None @@ -759,6 +788,46 @@ class Deflater(object): return self._data.getvalue() +class Brotli(object): + @staticmethod + @memoize + def brotli_tool(): + from buildconfig import topobjdir, substs + return os.path.join(topobjdir, 'dist', 'host', 'bin', + 'brotli' + substs.get('BIN_SUFFIX', '')) + + @staticmethod + def run_brotli_tool(args, input): + proc = subprocess.Popen([Brotli.brotli_tool()] + args, + stdin=subprocess.PIPE, + stdout=subprocess.PIPE) + (stdout, _) = proc.communicate(input) + ret = proc.wait() + if ret != 0: + raise Exception("Brotli compression failed") + return stdout + + @staticmethod + def compress(data): + return Brotli.run_brotli_tool(['--lgwin=17'], data) + + @staticmethod + def decompress(data): + return Brotli.run_brotli_tool(['--decompress'], data) + + +class BrotliCompress(object): + def __init__(self): + self._buf = BytesIO() + + def compress(self, data): + self._buf.write(data) + return b'' + + def flush(self): + return Brotli.compress(self._buf.getvalue()) + + class JarLog(dict): ''' Helper to read the file Gecko generates when setting MOZ_JAR_LOG_FILE. diff --git a/python/mozbuild/mozpack/packager/l10n.py b/python/mozbuild/mozpack/packager/l10n.py index 758064f59f..e3e05fc894 100644 --- a/python/mozbuild/mozpack/packager/l10n.py +++ b/python/mozbuild/mozpack/packager/l10n.py @@ -37,6 +37,7 @@ from mozpack.chrome.manifest import ( Manifest, ) from mozpack.errors import errors +from mozpack.mozjar import JAR_DEFLATED from mozpack.packager.unpack import UnpackFinder from createprecomplete import generate_precomplete @@ -241,16 +242,17 @@ def repack(source, l10n, extra_l10n={}, non_resources=[], non_chrome=set()): finders[base] = UnpackFinder(path) l10n_finder = ComposedFinder(finders) copier = FileCopier() + compress = min(app_finder.compressed, JAR_DEFLATED) if app_finder.kind == 'flat': formatter = FlatFormatter(copier) elif app_finder.kind == 'jar': formatter = JarFormatter(copier, optimize=app_finder.optimizedjars, - compress=app_finder.compressed) + compress=compress) elif app_finder.kind == 'omni': formatter = OmniJarFormatter(copier, app_finder.omnijar, optimize=app_finder.optimizedjars, - compress=app_finder.compressed, + compress=compress, non_resources=non_resources) with errors.accumulate(): diff --git a/python/mozbuild/mozpack/packager/unpack.py b/python/mozbuild/mozpack/packager/unpack.py index fa2b474e71..515705c0d7 100644 --- a/python/mozbuild/mozpack/packager/unpack.py +++ b/python/mozbuild/mozpack/packager/unpack.py @@ -54,7 +54,7 @@ class UnpackFinder(BaseFinder): self.omnijar = None self.jarlogs = {} self.optimizedjars = False - self.compressed = True + self.compressed = False jars = set() @@ -146,8 +146,7 @@ class UnpackFinder(BaseFinder): jar = JarReader(fileobj=file.open()) if jar.is_optimized: self.optimizedjars = True - if not any(f.compressed for f in jar): - self.compressed = False + self.compressed = max(self.compressed, jar.compression) if jar.last_preloaded: jarlog = jar.entries.keys() self.jarlogs[path] = jarlog[:jarlog.index(jar.last_preloaded) + 1] diff --git a/toolkit/mozapps/installer/packager.mk b/toolkit/mozapps/installer/packager.mk index e700b51620..6cae156580 100644 --- a/toolkit/mozapps/installer/packager.mk +++ b/toolkit/mozapps/installer/packager.mk @@ -50,7 +50,7 @@ stage-package: $(MOZ_PKG_MANIFEST) $(MOZ_PKG_MANIFEST_DEPS) ) \ $(if $(JARLOG_DIR),$(addprefix --jarlog ,$(wildcard $(JARLOG_FILE_AB_CD)))) \ $(if $(OPTIMIZEJARS),--optimizejars) \ - $(if $(DISABLE_JAR_COMPRESSION),--disable-compression) \ + $(addprefix --compress ,$(JAR_COMPRESSION)) \ $(addprefix --unify ,$(UNIFY_DIST)) \ $(MOZ_PKG_MANIFEST) '$(DIST)' '$(DIST)'/$(STAGEPATH)$(MOZ_PKG_DIR)$(if $(MOZ_PKG_MANIFEST),,$(_BINPATH)) \ $(if $(filter omni,$(MOZ_PACKAGER_FORMAT)),$(if $(NON_OMNIJAR_FILES),--non-resource $(NON_OMNIJAR_FILES))) diff --git a/toolkit/mozapps/installer/packager.py b/toolkit/mozapps/installer/packager.py index 1a144823ca..3b90e97c25 100644 --- a/toolkit/mozapps/installer/packager.py +++ b/toolkit/mozapps/installer/packager.py @@ -23,6 +23,7 @@ from mozpack.copier import ( Jarrer, ) from mozpack.errors import errors +from mozpack.mozjar import JAR_BROTLI from mozpack.unify import UnifiedBuildFinder import mozpack.path as mozpath import buildconfig @@ -270,9 +271,9 @@ def main(): help='Enable jar optimizations') parser.add_argument('--unify', default='', help='Base directory of another build to unify with') - parser.add_argument('--disable-compression', action='store_false', - dest='compress', default=True, - help='Disable jar compression') + parser.add_argument('--compress', choices=('none', 'deflate', 'brotli'), + default='deflate', + help='Use given jar compression (default: deflate)') parser.add_argument('manifest', default=None, nargs='?', help='Manifest file name') parser.add_argument('source', help='Source directory') @@ -290,15 +291,21 @@ def main(): for name, value in [split_define(d) for d in args.defines]: defines[name] = value + compress = { + 'none': False, + 'deflate': True, + 'brotli': JAR_BROTLI, + }[args.compress] + copier = FileCopier() if args.format == 'flat': formatter = FlatFormatter(copier) elif args.format == 'jar': - formatter = JarFormatter(copier, compress=args.compress, optimize=args.optimizejars) + formatter = JarFormatter(copier, compress=compress, optimize=args.optimizejars) elif args.format == 'omni': formatter = OmniJarFormatter(copier, buildconfig.substs['OMNIJAR_NAME'], - compress=args.compress, + compress=compress, optimize=args.optimizejars, non_resources=args.non_resource) else: diff --git a/toolkit/mozapps/installer/upload-files.mk b/toolkit/mozapps/installer/upload-files.mk index 82b550fb4d..865d2cf6a6 100644 --- a/toolkit/mozapps/installer/upload-files.mk +++ b/toolkit/mozapps/installer/upload-files.mk @@ -385,7 +385,7 @@ ifneq (android,$(MOZ_WIDGET_TOOLKIT)) OPTIMIZEJARS = 1 ifneq (gonk,$(MOZ_WIDGET_TOOLKIT)) ifdef NIGHTLY_BUILD - DISABLE_JAR_COMPRESSION = 1 + JAR_COMPRESSION ?= none endif endif endif From aa16c6c7ee69e0a03c3f1b9a2cd527db1313713a Mon Sep 17 00:00:00 2001 From: Moonchild Date: Mon, 16 Nov 2020 11:38:02 +0000 Subject: [PATCH 7/7] [UA] Change default compatibility mode version to 68.0 Since several entities have started to ban .9 versions, even if they are valid ESR versions. --- modules/libpref/init/all.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/libpref/init/all.js b/modules/libpref/init/all.js index 8665dc7849..a48f8526fa 100644 --- a/modules/libpref/init/all.js +++ b/modules/libpref/init/all.js @@ -23,7 +23,7 @@ pref("keyword.enabled", false); pref("general.useragent.locale", "chrome://global/locale/intl.properties"); pref("general.useragent.compatMode.gecko", false); pref("general.useragent.compatMode.firefox", false); -pref("general.useragent.compatMode.version", "68.9"); +pref("general.useragent.compatMode.version", "68.0"); pref("general.useragent.appVersionIsBuildID", false); // This pref exists only for testing purposes. In order to disable all