[vlc-devel] [PATCH 2/2] vout: vulkan: add a variety of built-in shaders
Rémi Denis-Courmont
remi at remlab.net
Sat Jun 20 14:31:09 CEST 2020
Hi,
Does not look like (L)GPL compliant sources to me, and beyond that, it's a rather questionable to hard code.
Le 20 juin 2020 12:41:55 GMT+02:00, Niklas Haas <vlc at haasn.xyz> a écrit :
>From: Niklas Haas <git at haasn.xyz>
>
>j-b wants users to be able to more easily enable the fancy meme
>scaling,
>so we hard-code some common/popular shaders for user convenience.
>
>I decided to include FSRCNNX, KrigBilateral, RAVU r3, SSimDownscaler
>and
>SSimSuperRes as these seem to be the most popular shaders in use.
>---
> modules/video_output/placebo_utils.h | 15 +
> modules/video_output/vulkan/Makefile.am | 7 +-
> modules/video_output/vulkan/display.c | 56 +-
> .../vulkan/shaders/fsrcnnx_8_0_4_1.c | 444 ++++++++++++++++
> .../vulkan/shaders/krig_bilateral.c | 234 +++++++++
> .../vulkan/shaders/ravu_r3_compute.c | 479 ++++++++++++++++++
> modules/video_output/vulkan/shaders/shaders.h | 39 ++
> .../vulkan/shaders/ssim_downscaler.c | 307 +++++++++++
> .../vulkan/shaders/ssim_super_res.c | 276 ++++++++++
> 9 files changed, 1845 insertions(+), 12 deletions(-)
>create mode 100644
>modules/video_output/vulkan/shaders/fsrcnnx_8_0_4_1.c
>create mode 100644 modules/video_output/vulkan/shaders/krig_bilateral.c
>create mode 100644
>modules/video_output/vulkan/shaders/ravu_r3_compute.c
> create mode 100644 modules/video_output/vulkan/shaders/shaders.h
>create mode 100644
>modules/video_output/vulkan/shaders/ssim_downscaler.c
>create mode 100644 modules/video_output/vulkan/shaders/ssim_super_res.c
>
>diff --git a/modules/video_output/placebo_utils.h
>b/modules/video_output/placebo_utils.h
>index 7e460093a2..a90457328b 100644
>--- a/modules/video_output/placebo_utils.h
>+++ b/modules/video_output/placebo_utils.h
>@@ -499,4 +499,19 @@ static const struct pl_filter_function *const
>filter_fun[] = {
> #define USER_SHADER_FILE_TEXT N_("Custom shader")
>#define USER_SHADER_FILE_LONGTEXT N_("Path to a file containing a
>custom user shader, in mpv .hook format.")
>
>+#define FSRCNNX_TEXT N_("FSRCNNX x2 8-0-4-1")
>+#define FSRCNNX_LONGTEXT N_("Neural network-based upscaler. Good at
>eliminating compression artifacts and sharpening lines, but fairly
>expensive and prone to ringing.")
>+
>+#define KRIG_BILATERAL_TEXT N_("KrigBilateral chroma scaler")
>+#define KRIG_BILATERAL_LONGTEXT N_("Scales chroma by using the luma
>plane as a reference. Fairly cheap.")
>+
>+#define RAVU_R3_TEXT N_("RAVU r3")
>+#define RAVU_R3_LONGTEXT N_("Raid and Accurate Video Upscaling (RAVU),
>inspired by RAISR. Edge-directed upscaler using weights trained on a
>database of anime files. Fairly cheap and good at avoiding ringing.")
>+
>+#define SSIM_DOWNSCALER_TEXT N_("SSimDownscaler")
>+#define SSIM_DOWNSCALER_LONGTEXT N_("Tuned sharpening downscaler. It's
>recommended to use this with the \"Mitchell-Netravali\" downscaler and
>the \"Don't linearize before scaling\" option enabled.")
>+
>+#define SSIM_SUPER_RES_TEXT N_("SSimSuperRes")
>+#define SSIM_SUPER_RES_LONGTEXT N_("Fast image sharpener, but prone to
>ringing.")
>+
> #endif // VLC_PLACEBO_UTILS_H
>diff --git a/modules/video_output/vulkan/Makefile.am
>b/modules/video_output/vulkan/Makefile.am
>index 5ab6eb6ee6..b902901977 100644
>--- a/modules/video_output/vulkan/Makefile.am
>+++ b/modules/video_output/vulkan/Makefile.am
>@@ -13,7 +13,12 @@ VULKAN_COMMONSOURCES += dummy.cpp
> VULKAN_COMMONCFLAGS = $(VULKAN_CFLAGS) $(LIBPLACEBO_CFLAGS)
> VULKAN_COMMONLIBS = $(VULKAN_LIBS) $(LIBPLACEBO_LIBS)
>
>-libvk_plugin_la_SOURCES = $(VULKAN_COMMONSOURCES)
>video_output/vulkan/display.c
>+libvk_plugin_la_SOURCES = $(VULKAN_COMMONSOURCES)
>video_output/vulkan/display.c \
>+ video_output/vulkan/shaders/fsrcnnx_8_0_4_1.c \
>+ video_output/vulkan/shaders/krig_bilateral.c \
>+ video_output/vulkan/shaders/ravu_r3_compute.c \
>+ video_output/vulkan/shaders/ssim_downscaler.c \
>+ video_output/vulkan/shaders/ssim_super_res.c
> libvk_plugin_la_CFLAGS = $(AM_CFLAGS) $(VULKAN_COMMONCFLAGS)
> libvk_plugin_la_LIBADD = $(VULKAN_COMMONLIBS)
>
>diff --git a/modules/video_output/vulkan/display.c
>b/modules/video_output/vulkan/display.c
>index a3c928f6d5..0f90b7619c 100644
>--- a/modules/video_output/vulkan/display.c
>+++ b/modules/video_output/vulkan/display.c
>@@ -34,6 +34,7 @@
>
> #include "../placebo_utils.h"
> #include "instance.h"
>+#include "shaders/shaders.h"
>
> #include <libplacebo/renderer.h>
> #include <libplacebo/utils/upload.h>
>@@ -68,7 +69,13 @@ struct vout_display_sys_t
> struct pl_peak_detect_params peak_detect;
> #endif
> #if PL_API_VER >= 58
>- const struct pl_hook *hook;
>+ const struct pl_hook *enabled_hooks[8]; // storage for
>`params.hooks`
>+ const struct pl_hook *fsrcnnx_hook;
>+ const struct pl_hook *krig_bilateral_hook;
>+ const struct pl_hook *ravu_r3_hook;
>+ const struct pl_hook *ssim_downscaler_hook;
>+ const struct pl_hook *ssim_super_res_hook;
>+ const struct pl_hook *user_hook;
> char *hook_path;
> #endif
> enum pl_chroma_location yuv_chroma_loc;
>@@ -149,6 +156,15 @@ static int Open(vout_display_t *vd, const
>vout_display_cfg_t *cfg,
> vd->control = Control;
> vd->close = Close;
>
>+#if PL_API_VER >= 58
>+ // Load all the shaders built in to VLC
>+ sys->fsrcnnx_hook = pl_mpv_user_shader_parse(gpu, fsrcnnx_8_0_4_1,
>fsrcnnx_8_0_4_1_len);
>+ sys->krig_bilateral_hook = pl_mpv_user_shader_parse(gpu,
>krig_bilateral, krig_bilateral_len);
>+ sys->ravu_r3_hook = pl_mpv_user_shader_parse(gpu, ravu_r3_compute,
>ravu_r3_compute_len);
>+ sys->ssim_downscaler_hook = pl_mpv_user_shader_parse(gpu,
>ssim_downscaler, ssim_downscaler_len);
>+ sys->ssim_super_res_hook = pl_mpv_user_shader_parse(gpu,
>ssim_super_res, ssim_super_res_len);
>+#endif
>+
> UpdateParams(vd);
> (void) cfg; (void) context;
> return VLC_SUCCESS;
>@@ -176,7 +192,12 @@ static void Close(vout_display_t *vd)
> }
>
> #if PL_API_VER >= 58
>- pl_mpv_user_shader_destroy(&sys->hook);
>+ pl_mpv_user_shader_destroy(&sys->fsrcnnx_hook);
>+ pl_mpv_user_shader_destroy(&sys->krig_bilateral_hook);
>+ pl_mpv_user_shader_destroy(&sys->ravu_r3_hook);
>+ pl_mpv_user_shader_destroy(&sys->ssim_downscaler_hook);
>+ pl_mpv_user_shader_destroy(&sys->ssim_super_res_hook);
>+ pl_mpv_user_shader_destroy(&sys->user_hook);
> free(sys->hook_path);
> #endif
>
>@@ -374,7 +395,7 @@ static int Control(vout_display_t *vd, int query,
>va_list ap)
>static void load_user_shader(vout_display_sys_t *sys, const char
>*filepath)
> {
> if (!filepath || !*filepath) {
>- pl_mpv_user_shader_destroy(&sys->hook);
>+ pl_mpv_user_shader_destroy(&sys->user_hook);
> return;
> }
>
>@@ -403,8 +424,8 @@ static void load_user_shader(vout_display_sys_t
>*sys, const char *filepath)
> ret = fread(shader_str, length, 1, fs);
> if (ret != 1)
> goto error;
>- sys->hook = pl_mpv_user_shader_parse(gpu, shader_str, length);
>- if (!sys->hook)
>+ sys->user_hook = pl_mpv_user_shader_parse(gpu, shader_str,
>length);
>+ if (!sys->user_hook)
> goto error;
>
> fclose(fs);
>@@ -440,6 +461,11 @@ vlc_module_begin ()
>
> #if PL_API_VER >= 58
> set_section("Custom shaders", NULL)
>+ add_bool("fsrcnnx", false, FSRCNNX_TEXT, FSRCNNX_LONGTEXT, false)
>+ add_bool("krig-bilateral", false, KRIG_BILATERAL_TEXT,
>KRIG_BILATERAL_LONGTEXT, false)
>+ add_bool("ravu-r3", false, RAVU_R3_TEXT, RAVU_R3_LONGTEXT, false)
>+ add_bool("ssim-downscaler", false, SSIM_DOWNSCALER_TEXT,
>SSIM_DOWNSCALER_LONGTEXT, false)
>+ add_bool("ssim-super-res", false, SSIM_SUPER_RES_TEXT,
>SSIM_SUPER_RES_LONGTEXT, false)
>add_loadfile("user-shader-file", NULL, USER_SHADER_FILE_TEXT,
>USER_SHADER_FILE_LONGTEXT)
> #endif
>
>@@ -694,12 +720,20 @@ static void UpdateParams(vout_display_t *vd)
> };
>
> #if PL_API_VER >= 58
>+ sys->params.hooks = sys->enabled_hooks;
>+ sys->params.num_hooks = 0;
>+ if (var_InheritBool(vd, "fsrcnnx"))
>+ sys->enabled_hooks[sys->params.num_hooks++] =
>sys->fsrcnnx_hook;
>+ if (var_InheritBool(vd, "krig-bilateral"))
>+ sys->enabled_hooks[sys->params.num_hooks++] =
>sys->krig_bilateral_hook;
>+ if (var_InheritBool(vd, "ravu-r3"))
>+ sys->enabled_hooks[sys->params.num_hooks++] =
>sys->ravu_r3_hook;
>+ if (var_InheritBool(vd, "ssim-downscaler"))
>+ sys->enabled_hooks[sys->params.num_hooks++] =
>sys->ssim_downscaler_hook;
>+ if (var_InheritBool(vd, "ssim-super-res"))
>+ sys->enabled_hooks[sys->params.num_hooks++] =
>sys->ssim_super_res_hook;
> load_user_shader(sys, var_InheritString(vd, "user-shader-file"));
>- if (sys->hook) {
>- sys->params.hooks = &sys->hook;
>- sys->params.num_hooks = 1;
>- } else {
>- sys->params.num_hooks = 0;
>- }
>+ if (sys->user_hook)
>+ sys->enabled_hooks[sys->params.num_hooks++] = sys->user_hook;
> #endif
> }
>diff --git a/modules/video_output/vulkan/shaders/fsrcnnx_8_0_4_1.c
>b/modules/video_output/vulkan/shaders/fsrcnnx_8_0_4_1.c
>new file mode 100644
>index 0000000000..c341052c42
>--- /dev/null
>+++ b/modules/video_output/vulkan/shaders/fsrcnnx_8_0_4_1.c
>@@ -0,0 +1,444 @@
>+/*****************************************************************************
>+ * FSRCNN-X, based on FSRCNN-TensorFlow
>+
>*****************************************************************************
>+ * Copyright (c) 2016 Drake Levy
>+ * Copyright (c) 2017 Niklas Haas
>+ * Copyright (c) 2017 igv
>+ *
>+ * Permission is hereby granted, free of charge, to any person
>obtaining a copy
>+ * of this software and associated documentation files (the
>"Software"), to
>+ * deal in the Software without restriction, including without
>limitation the
>+ * rights to use, copy, modify, merge, publish, distribute,
>sublicense, and/or
>+ * sell copies of the Software, and to permit persons to whom the
>Software is
>+ * furnished to do so, subject to the following conditions:
>+ *
>+ * The above copyright notice and this permission notice shall be
>included in
>+ * all copies or substantial portions of the Software.
>+ *
>+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
>EXPRESS OR
>+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
>MERCHANTABILITY,
>+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
>SHALL THE
>+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
>OTHER
>+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
>ARISING
>+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
>DEALINGS
>+ * IN THE SOFTWARE.
>+
>*****************************************************************************/
>+
>+#include <stddef.h>
>+#include "shaders.h"
>+
>+const char fsrcnnx_8_0_4_1[] =
>+"//!HOOK LUMA\n"
>+"//!WHEN OUTPUT.w LUMA.w / 1.400 > OUTPUT.h LUMA.h / 1.400 > *\n"
>+"//!DESC feature map 1\n"
>+"//!BIND LUMA\n"
>+"//!SAVE FEATURE1\n"
>+"//!COMPONENTS 4\n"
>+"vec4 hook()\n"
>+"{\n"
>+"vec4 res =
>vec4(-0.1509746015071869,-0.0135558079928160,0.0067616454325616,-0.2848519682884216);\n"
>+"res +=
>vec4(-0.0037598882336169,0.0614504106342793,-0.0002959038829431,0.0036728407721967)
>* float(LUMA_texOff(vec2(-2,-2)));\n"
>+"res +=
>vec4(0.0071421819739044,-0.0254413057118654,-0.0068537630140781,-0.0069990768097341)
>* float(LUMA_texOff(vec2(-2,-1)));\n"
>+"res +=
>vec4(0.0568017549812794,0.1957543939352036,-0.0222231913357973,-0.0549908876419067)
>* float(LUMA_texOff(vec2(-2,0)));\n"
>+"res +=
>vec4(-0.0012381756678224,-0.0187490638345480,0.0206905454397202,0.0035073466133326)
>* float(LUMA_texOff(vec2(-2,1)));\n"
>+"res +=
>vec4(0.0098362052813172,0.0057854773476720,-0.0041487300768495,-0.0152947865426540)
>* float(LUMA_texOff(vec2(-2,2)));\n"
>+"res +=
>vec4(-0.0189282279461622,-0.0807115808129311,-0.0299318879842758,0.0287063755095005)
>* float(LUMA_texOff(vec2(-1,-2)));\n"
>+"res +=
>vec4(0.0249533280730247,0.1917327642440796,0.0229102019220591,-0.0328125134110451)
>* float(LUMA_texOff(vec2(-1,-1)));\n"
>+"res +=
>vec4(0.0036545787006617,-0.0931302905082703,-0.0035518202930689,-0.0716555491089821)
>* float(LUMA_texOff(vec2(-1,0)));\n"
>+"res +=
>vec4(0.0312809608876705,-0.1189801245927811,-0.0282735470682383,-0.0536981821060181)
>* float(LUMA_texOff(vec2(-1,1)));\n"
>+"res +=
>vec4(-0.0323902070522308,0.0716715604066849,0.0152344889938831,0.0438132621347904)
>* float(LUMA_texOff(vec2(-1,2)));\n"
>+"res +=
>vec4(-0.0277053173631430,0.1135088726878166,0.1162345707416534,0.0978962406516075)
>* float(LUMA_texOff(vec2(0,-2)));\n"
>+"res +=
>vec4(-0.1162458062171936,-0.0401261895895004,-0.4834267795085907,0.1004458293318748)
>* float(LUMA_texOff(vec2(0,-1)));\n"
>+"res +=
>vec4(1.1068447828292847,0.0626810044050217,0.0089028999209404,0.8890707492828369)
>* float(LUMA_texOff(vec2(0,0)));\n"
>+"res +=
>vec4(0.1201625615358353,0.1673810482025146,0.5650558471679688,-0.1634792387485504)
>* float(LUMA_texOff(vec2(0,1)));\n"
>+"res +=
>vec4(-0.0128123862668872,-0.3098227679729462,-0.1615206897258759,0.0421420000493526)
>* float(LUMA_texOff(vec2(0,2)));\n"
>+"res +=
>vec4(0.0039666970260441,-0.1251176893711090,0.0052549242973328,-0.0006292918697000)
>* float(LUMA_texOff(vec2(1,-2)));\n"
>+"res +=
>vec4(-0.0960166230797768,-0.0515756346285343,-0.0100744133815169,0.1348678767681122)
>* float(LUMA_texOff(vec2(1,-1)));\n"
>+"res +=
>vec4(0.0043543158099055,-0.1486229300498962,0.0065605705603957,0.0219576414674520)
>* float(LUMA_texOff(vec2(1,0)));\n"
>+"res +=
>vec4(0.0288588572293520,0.1939568966627121,-0.0258098207414150,-0.0573631897568703)
>* float(LUMA_texOff(vec2(1,1)));\n"
>+"res +=
>vec4(0.0070200306363404,0.0631003975868225,0.0442556552588940,-0.0129602896049619)
>* float(LUMA_texOff(vec2(1,2)));\n"
>+"res +=
>vec4(-0.0175674892961979,-0.0087839104235172,-0.0001106700074160,0.0325451157987118)
>* float(LUMA_texOff(vec2(2,-2)));\n"
>+"res +=
>vec4(-0.0057956059463322,0.0926996394991875,-0.0150334453210235,-0.0065397387370467)
>* float(LUMA_texOff(vec2(2,-1)));\n"
>+"res +=
>vec4(-0.0939300730824471,-0.0326769575476646,-0.0057285595685244,0.1896656304597855)
>* float(LUMA_texOff(vec2(2,0)));\n"
>+"res +=
>vec4(-0.0203150436282158,-0.1911219060420990,0.0051789507269859,0.0267475824803114)
>* float(LUMA_texOff(vec2(2,1)));\n"
>+"res +=
>vec4(-0.0036441595293581,0.0591833665966988,-0.0090797655284405,0.0110706342384219)
>* float(LUMA_texOff(vec2(2,2)));\n"
>+"return res;\n"
>+"}\n"
>+"\n"
>+"//!HOOK LUMA\n"
>+"//!WHEN OUTPUT.w LUMA.w / 1.400 > OUTPUT.h LUMA.h / 1.400 > *\n"
>+"//!DESC feature map 2\n"
>+"//!BIND LUMA\n"
>+"//!SAVE FEATURE2\n"
>+"//!COMPONENTS 4\n"
>+"vec4 hook()\n"
>+"{\n"
>+"vec4 res =
>vec4(0.0541787967085838,0.0120136886835098,-0.0096567748114467,-0.0094489278271794);\n"
>+"res +=
>vec4(0.0184792112559080,0.0136690614745021,0.0058442442677915,-0.0099522806704044)
>* float(LUMA_texOff(vec2(-2,-2)));\n"
>+"res +=
>vec4(0.0219498351216316,-0.0216886978596449,0.0320411846041679,0.0948653221130371)
>* float(LUMA_texOff(vec2(-2,-1)));\n"
>+"res +=
>vec4(-0.1750338971614838,0.1136583536863327,-0.2008614242076874,-0.0499890074133873)
>* float(LUMA_texOff(vec2(-2,0)));\n"
>+"res +=
>vec4(0.0266360323876143,-0.0303857438266277,0.0121428770944476,-0.0020902391988784)
>* float(LUMA_texOff(vec2(-2,1)));\n"
>+"res +=
>vec4(0.0081525733694434,-0.0125904576852918,0.0093008270487189,-0.0021994127891958)
>* float(LUMA_texOff(vec2(-2,2)));\n"
>+"res +=
>vec4(0.0205022636801004,0.0325898118317127,0.0110427504405379,0.1037379875779152)
>* float(LUMA_texOff(vec2(-1,-2)));\n"
>+"res +=
>vec4(0.1099926233291626,-0.0823785662651062,-0.0107855703681707,0.0055436980910599)
>* float(LUMA_texOff(vec2(-1,-1)));\n"
>+"res +=
>vec4(0.4112021923065186,0.1359078884124756,0.6936535835266113,0.0914536863565445)
>* float(LUMA_texOff(vec2(-1,0)));\n"
>+"res +=
>vec4(0.1075170710682869,-0.0304633509367704,-0.0206621568650007,-0.1588809192180634)
>* float(LUMA_texOff(vec2(-1,1)));\n"
>+"res +=
>vec4(0.0254670437425375,0.0036090235225856,0.0238041263073683,0.0449189729988575)
>* float(LUMA_texOff(vec2(-1,2)));\n"
>+"res +=
>vec4(-0.1222435683012009,0.0890526250004768,-0.0151765551418066,-0.2669847011566162)
>* float(LUMA_texOff(vec2(0,-2)));\n"
>+"res +=
>vec4(0.4851113557815552,0.0263010896742344,0.0277495700865984,-0.1271323114633560)
>* float(LUMA_texOff(vec2(0,-1)));\n"
>+"res +=
>vec4(-1.9192758798599243,-0.2477061748504639,0.0274293571710587,-0.3749051988124847)
>* float(LUMA_texOff(vec2(0,0)));\n"
>+"res +=
>vec4(0.6472831368446350,-0.0755768343806267,-0.0517080873250961,0.4422555267810822)
>* float(LUMA_texOff(vec2(0,1)));\n"
>+"res +=
>vec4(-0.2022986412048340,-0.0590564534068108,0.0131811536848545,0.0504300333559513)
>* float(LUMA_texOff(vec2(0,2)));\n"
>+"res +=
>vec4(0.0105082271620631,-0.0040961871854961,-0.0362351462244987,-0.0504910945892334)
>* float(LUMA_texOff(vec2(1,-2)));\n"
>+"res +=
>vec4(0.1012665480375290,0.2559980750083923,0.0301113147288561,-0.0152765307575464)
>* float(LUMA_texOff(vec2(1,-1)));\n"
>+"res +=
>vec4(0.2848424017429352,-0.4166705012321472,-0.7385643124580383,0.2595581114292145)
>* float(LUMA_texOff(vec2(1,0)));\n"
>+"res +=
>vec4(0.0907168462872505,-0.0188500117510557,0.0305166300386190,-0.1908629387617111)
>* float(LUMA_texOff(vec2(1,1)));\n"
>+"res +=
>vec4(0.0538988150656223,-0.0034666310530156,0.0004272823862266,-0.0216222237795591)
>* float(LUMA_texOff(vec2(1,2)));\n"
>+"res +=
>vec4(0.0185288917273283,0.0345742516219616,0.0000267560826614,0.0097738523036242)
>* float(LUMA_texOff(vec2(2,-2)));\n"
>+"res +=
>vec4(0.0525976382195950,0.0446186028420925,0.0097536100074649,0.0514103621244431)
>* float(LUMA_texOff(vec2(2,-1)));\n"
>+"res +=
>vec4(-0.1153732314705849,0.2050881534814835,0.1450416445732117,0.1768003553152084)
>* float(LUMA_texOff(vec2(2,0)));\n"
>+"res +=
>vec4(0.0016675911610946,0.1342236995697021,-0.0333153307437897,-0.0940694212913513)
>* float(LUMA_texOff(vec2(2,1)));\n"
>+"res +=
>vec4(0.0151546653360128,-0.0330587327480316,0.0042342385277152,0.0297497119754553)
>* float(LUMA_texOff(vec2(2,2)));\n"
>+"return res;\n"
>+"}\n"
>+"\n"
>+"//!HOOK LUMA\n"
>+"//!WHEN OUTPUT.w LUMA.w / 1.400 > OUTPUT.h LUMA.h / 1.400 > *\n"
>+"//!DESC mapping 1_1\n"
>+"//!BIND FEATURE1\n"
>+"//!BIND FEATURE2\n"
>+"//!SAVE MODEL21\n"
>+"//!COMPONENTS 4\n"
>+"vec4 hook()\n"
>+"{\n"
>+"vec4 res =
>vec4(-0.0452743545174599,-0.7737042903900146,-0.0043352008797228,-0.2513844668865204);\n"
>+"res +=
>mat4(0.1589078158140182,-0.0467162430286407,0.2073607295751572,0.2234642654657364,-0.0834981352090836,-0.0070660104975104,-0.1287210732698441,0.0809417366981506,-0.0796080529689789,-0.0753151029348373,-0.1091800481081009,0.3848945796489716,-0.1664465218782425,-0.0439221411943436,0.0914947092533112,-0.0781081467866898)
>* FEATURE1_texOff(vec2(-1,-1));\n"
>+"res +=
>mat4(-0.0689597502350807,0.0539563558995724,0.3200047016143799,0.0981027036905289,-0.3445762097835541,-0.1214470788836479,0.0288346856832504,0.0562641806900501,0.0052195386961102,0.1030749604105949,0.0598287545144558,-0.2350935041904449,-0.0293557122349739,-0.1810972094535828,-0.1621305495500565,-0.1864541620016098)
>* FEATURE2_texOff(vec2(-1,-1));\n"
>+"res +=
>mat4(0.0933479964733124,-0.0172324012964964,0.3026179969310760,0.0564954876899719,0.5954855680465698,-0.1879310905933380,-0.5111328363418579,-0.0598416514694691,0.6147844791412354,-0.0428325720131397,-0.8502849340438843,-0.1915386915206909,-0.0582077242434025,-0.0349113009870052,-0.1353366971015930,-0.0330252572894096)
>* FEATURE1_texOff(vec2(-1,0));\n"
>+"res +=
>mat4(-0.2540763914585114,0.1325411498546600,0.8136953115463257,-0.2215363681316376,0.1766147017478943,0.5234133601188660,0.1001175791025162,-0.1731569916009903,-0.1253602504730225,-0.4737440645694733,-1.2733485698699951,0.0450870580971241,-0.2801612317562103,0.0910555273294449,0.2545292377471924,-0.0309695433825254)
>* FEATURE2_texOff(vec2(-1,0));\n"
>+"res +=
>mat4(0.0122816842049360,-0.2234273999929428,0.0195859111845493,0.3529818654060364,0.2605769038200378,0.3399239480495453,0.4733481407165527,-0.2559757232666016,-0.0748921558260918,0.1091625988483429,-0.6069173812866211,-0.2188397347927094,-0.0625736489892006,0.2759097218513489,-0.1617750972509384,-0.2809991538524628)
>* FEATURE1_texOff(vec2(-1,1));\n"
>+"res +=
>mat4(-0.0201505720615387,0.0821481719613075,0.2021976560354233,-0.0328934714198112,0.2181531041860580,-0.5061808228492737,-1.0750364065170288,-0.0066138142719865,0.5227681398391724,0.0878994986414909,0.0389457345008850,-0.0255476050078869,0.1582612246274948,-0.0155039010569453,-0.0662331134080887,-0.1568329185247421)
>* FEATURE2_texOff(vec2(-1,1));\n"
>+"res +=
>mat4(0.0293578393757343,0.2162541151046753,-0.1011446565389633,-0.1825613230466843,-0.1876162737607956,0.0413508452475071,0.0420276634395123,0.2295992970466614,0.1307498067617416,0.7205982208251953,0.0965216308832169,-0.0042030825279653,-0.0044212667271495,-0.0115328812971711,0.0461373217403889,0.0421709902584553)
>* FEATURE1_texOff(vec2(0,-1));\n"
>+"res +=
>mat4(0.1305582225322723,0.0240202024579048,-0.2705288827419281,-0.1829632818698883,-0.0006808443577029,-0.3648712635040283,-0.8378824591636658,-0.0509168840944767,-0.2520502805709839,-0.7483316659927368,0.3777253925800323,-0.0533601380884647,0.0576758459210396,0.3025455772876740,-0.0032723147887737,-0.2953406572341919)
>* FEATURE2_texOff(vec2(0,-1));\n"
>+"res +=
>mat4(-0.5132640600204468,0.5542367100715637,0.0787968933582306,-0.8264530301094055,-0.3231813907623291,-0.2137864828109741,-0.0671812072396278,0.4974828362464905,1.2674243450164795,-0.7385908365249634,1.4834556579589844,-0.3905152976512909,0.1086511462926865,0.6852389574050903,-0.3045935928821564,-0.3111937344074249)
>* FEATURE1_texOff(vec2(0,0));\n"
>+"res +=
>mat4(0.7705498337745667,-0.0381696410477161,-0.0951596051454544,1.6320108175277710,0.1905073225498199,-0.0947012603282928,1.5937736034393311,0.1758241951465607,0.0784776359796524,-0.3702231049537659,1.0724834203720093,-0.2784453928470612,0.1904574930667877,-0.3195404708385468,-0.1795736253261566,0.5995727181434631)
>* FEATURE2_texOff(vec2(0,0));\n"
>+"res +=
>mat4(-0.5385479331016541,-0.1875318735837936,0.2716562151908875,-0.1477950215339661,-0.3925490081310272,0.1834059953689575,-0.2801915109157562,-0.1366681754589081,0.0118164690211415,-0.4390906989574432,-0.3368979096412659,0.1315898448228836,0.3428115844726562,0.1215748861432076,0.1494996994733810,-0.1410061120986938)
>* FEATURE1_texOff(vec2(0,1));\n"
>+"res +=
>mat4(-0.0710507705807686,0.2156861126422882,0.4100387096405029,-0.1931686550378799,-0.3886110782623291,0.5996405482292175,0.1684583276510239,-0.0297941360622644,-0.4478571116924286,-0.4062708020210266,-0.3983869850635529,0.1279487311840057,0.2150515466928482,0.0020545844454318,0.0465856343507767,0.2574361860752106)
>* FEATURE2_texOff(vec2(0,1));\n"
>+"res +=
>mat4(0.1931444704532623,-0.2348867952823639,-2.6289799213409424,-0.1872940510511398,0.2246735841035843,-0.1978641450405121,-0.3906482458114624,-0.1101277172565460,0.1574941724538803,0.2592659890651703,0.5765943527221680,0.2494676113128662,-0.2056511342525482,-0.0004532634629868,1.3538817167282104,0.0350535102188587)
>* FEATURE1_texOff(vec2(1,-1));\n"
>+"res +=
>mat4(-0.0262365117669106,0.0298269763588905,-0.6972071528434753,-0.0970231071114540,0.3845966756343842,0.2413074225187302,-1.8877784013748169,0.0475531332194805,-0.2164962589740753,0.0108927991241217,0.4250757992267609,0.2008266597986221,0.1340677738189697,0.1458901166915894,0.0432816557586193,0.0527057498693466)
>* FEATURE2_texOff(vec2(1,-1));\n"
>+"res +=
>mat4(0.1774498373270035,0.0910393148660660,-0.0739985778927803,-0.3056291043758392,0.2493161261081696,0.0327782109379768,-0.3446145355701447,-0.0407629720866680,0.3177764415740967,0.0436120517551899,0.5451704859733582,0.0332397893071175,-0.0479518137872219,0.1812400668859482,-0.2539929449558258,-0.0047620139084756)
>* FEATURE1_texOff(vec2(1,0));\n"
>+"res +=
>mat4(0.5052930116653442,0.0961866974830627,-1.1356906890869141,-0.3774253427982330,0.1404987275600433,0.0431307442486286,-0.0994259268045425,-0.0832455456256866,-0.0651258975267410,0.7372122406959534,-0.0353675261139870,0.0542434938251972,-0.4436488449573517,-0.4416591227054596,-0.1309857368469238,-0.3337882459163666)
>* FEATURE2_texOff(vec2(1,0));\n"
>+"res +=
>mat4(0.1666868925094604,-0.1615426987409592,0.1336248070001602,-0.0370919369161129,-0.2176368087530136,0.1897179931402206,0.0345338135957718,-0.0323585197329521,-0.3513357937335968,-0.3251895606517792,0.0181038584560156,-0.0796460881829262,0.0585270710289478,0.1208555847406387,-0.0673353970050812,0.2433563768863678)
>* FEATURE1_texOff(vec2(1,1));\n"
>+"res +=
>mat4(0.7108100056648254,0.1390120387077332,0.0817940980195999,-0.1629430204629898,-0.1061920300126076,-0.3055068552494049,0.1638684719800949,-0.1071514934301376,0.2484579682350159,0.3708961009979248,-0.3470214307308197,0.2594919204711914,0.1205633953213692,0.2482945919036865,-0.2095223367214203,-0.1047516167163849)
>* FEATURE2_texOff(vec2(1,1));\n"
>+"res = max(res, vec4(0.0)) +
>vec4(1.0408123731613159,0.1023607999086380,0.0886593610048294,0.0472911037504673)
>* min(res, vec4(0.0));\n"
>+"return res;\n"
>+"}\n"
>+"\n"
>+"//!HOOK LUMA\n"
>+"//!WHEN OUTPUT.w LUMA.w / 1.400 > OUTPUT.h LUMA.h / 1.400 > *\n"
>+"//!DESC mapping 1_2\n"
>+"//!BIND FEATURE1\n"
>+"//!BIND FEATURE2\n"
>+"//!SAVE MODEL22\n"
>+"//!COMPONENTS 4\n"
>+"vec4 hook()\n"
>+"{\n"
>+"vec4 res =
>vec4(0.0768956169486046,-0.1460417658090591,-0.0062406626529992,0.0235804524272680);\n"
>+"res +=
>mat4(-0.0872487872838974,-0.1298694312572479,-0.0698781162500381,0.0549505129456520,0.0059861177578568,0.1220942437648773,-0.2900528609752655,-0.4822047650814056,0.1288974434137344,-0.0027072769589722,-0.0693329423666000,-0.3169730007648468,0.0078697996214032,0.0501138269901276,-0.0185764692723751,-0.0591485016047955)
>* FEATURE1_texOff(vec2(-1,-1));\n"
>+"res +=
>mat4(0.1555106043815613,-0.0083466339856386,0.1024751961231232,0.0946626663208008,0.0510551407933235,-0.3695095181465149,0.2315458357334137,-0.1145460009574890,-0.0128550035879016,-0.0186438988894224,-0.2012758851051331,0.1454962641000748,-0.1439885795116425,0.1474403291940689,-0.0426309518516064,-0.0510785803198814)
>* FEATURE2_texOff(vec2(-1,-1));\n"
>+"res +=
>mat4(-0.0423544161021709,0.2172163724899292,0.0563768111169338,0.1128659844398499,-0.0870366618037224,0.3808702826499939,0.4603576064109802,0.2344146221876144,-0.3489927649497986,0.0516141541302204,0.2467864751815796,-0.1020329073071480,0.1418838202953339,0.0597412101924419,0.0061432654038072,-0.1183865144848824)
>* FEATURE1_texOff(vec2(-1,0));\n"
>+"res +=
>mat4(0.3013050258159637,0.4316013455390930,0.0487066954374313,0.0620453096926212,0.4538179337978363,-0.0163833443075418,0.1053267270326614,0.3347252309322357,-0.1972877085208893,-0.0408539213240147,0.0808979496359825,-0.2371507287025452,0.4654107391834259,-0.2988391220569611,-0.1857631653547287,0.3485815525054932)
>* FEATURE2_texOff(vec2(-1,0));\n"
>+"res +=
>mat4(-0.0528658032417297,-0.1358958929777145,-0.2465055882930756,0.0719801932573318,-0.0296913739293814,0.0847417488694191,-0.0840649008750916,-0.0790594816207886,-0.1837938725948334,-0.2219027280807495,0.3485139012336731,-0.1552775949239731,0.0310121476650238,-0.1079743131995201,0.1548121571540833,-0.0252014473080635)
>* FEATURE1_texOff(vec2(-1,1));\n"
>+"res +=
>mat4(0.1290702074766159,0.0220040064305067,0.0247040521353483,-0.0333725735545158,0.1147301867604256,0.0765398442745209,0.3412538170814514,-0.2192483395338058,-0.4409129321575165,-0.0566915869712830,-0.0083323949947953,-0.1033551916480064,-0.0006615837919526,0.4846527278423309,-0.0796155557036400,0.3711148798465729)
>* FEATURE2_texOff(vec2(-1,1));\n"
>+"res +=
>mat4(-0.2485114336013794,0.0504177436232567,0.3105762004852295,-0.0268028136342764,0.0498577244579792,0.1702960431575775,-0.3471982777118683,-0.3560937643051147,0.4919846355915070,-0.1506134122610092,0.1742928326129913,0.7121704220771790,0.2521021664142609,-0.0725562721490860,-0.3548195362091064,-0.0064909690991044)
>* FEATURE1_texOff(vec2(0,-1));\n"
>+"res +=
>mat4(0.0700112506747246,0.0757739469408989,0.2237766832113266,0.2135815173387527,-0.1471729874610901,0.4211229085922241,0.0244796052575111,-0.3369590640068054,-0.0978589355945587,-0.2040650397539139,0.2179063409566879,-0.2687382400035858,-0.0639133453369141,0.1011230275034904,0.2787832021713257,-0.3398675918579102)
>* FEATURE2_texOff(vec2(0,-1));\n"
>+"res +=
>mat4(-0.1827321201562881,-0.4613777697086334,0.4138762950897217,0.1056525260210037,0.0108041986823082,-0.5957619547843933,0.2938109040260315,0.1136276349425316,-0.6728047132492065,-0.8402149677276611,0.6289898157119751,-1.4222831726074219,0.0892316773533821,-0.4140413999557495,-0.1067809239029884,0.2490266710519791)
>* FEATURE1_texOff(vec2(0,0));\n"
>+"res +=
>mat4(2.1550047397613525,0.3389005362987518,-0.7138993740081787,-0.4919975399971008,-0.2986942529678345,0.8358812928199768,-0.7589544057846069,0.4503022134304047,0.1842116862535477,1.1278806924819946,1.1338578462600708,1.4383541345596313,-0.3711380958557129,-0.7056380510330200,-0.1706199645996094,-0.6620675325393677)
>* FEATURE2_texOff(vec2(0,0));\n"
>+"res +=
>mat4(-0.1091756448149681,0.1478075534105301,0.2514287233352661,-0.2073339819908142,-0.2044165432453156,0.1138084158301353,-0.1741017401218414,0.5192852616310120,-0.0074753193184733,-0.0312587358057499,-0.0253719352185726,0.4232962131500244,0.3019977211952209,-0.3143487870693207,-0.2479774802923203,-0.1207192093133926)
>* FEATURE1_texOff(vec2(0,1));\n"
>+"res +=
>mat4(0.0315413773059845,0.3575184047222137,0.1308461278676987,-0.2180818617343903,0.3164284229278564,0.2018950283527374,-0.0247195046395063,-0.0624660067260265,0.1268971115350723,0.8093144297599792,0.1316860169172287,-0.1253946125507355,0.3411116302013397,0.0838127732276917,0.0886839106678963,-0.2002663016319275)
>* FEATURE2_texOff(vec2(0,1));\n"
>+"res +=
>mat4(-0.1923704743385315,-0.1050108820199966,0.0598437525331974,-0.2413118630647659,-0.0889708846807480,0.2103639692068100,0.4331704676151276,0.3487502932548523,-0.2006836980581284,0.1304136216640472,-0.0304283294826746,0.0206174869090319,0.1527952700853348,0.0544542260468006,0.1180009320378304,0.2499498873949051)
>* FEATURE1_texOff(vec2(1,-1));\n"
>+"res +=
>mat4(-0.0284705460071564,0.0029818087350577,0.0721286237239838,0.0560192652046680,-0.0467523075640202,0.1690399050712585,-0.1048235744237900,0.0216949936002493,-0.1276771128177643,0.3630679845809937,0.0378565900027752,-0.1320662647485733,-0.1650677025318146,0.1172833964228630,0.0003059599548578,0.3721223473548889)
>* FEATURE2_texOff(vec2(1,-1));\n"
>+"res +=
>mat4(-0.0238619782030582,-0.2455882132053375,0.0190900266170502,0.0713610127568245,0.1525544077157974,-0.3566334247589111,-0.0479829646646976,-0.1825138330459595,-0.1183577105402946,-0.6739791631698608,0.2822116911411285,-0.0524367764592171,0.0092617031186819,-0.0129339182749391,-0.1394946277141571,-0.3225293457508087)
>* FEATURE1_texOff(vec2(1,0));\n"
>+"res +=
>mat4(-0.7468954324722290,0.1317645460367203,0.2565933763980865,0.0111176706850529,0.2047275155782700,-0.3252566158771515,0.1201066151261330,-0.3213990032672882,-0.2975398898124695,-0.2445526123046875,0.1418895125389099,0.2306181788444519,0.0533845201134682,-0.3423732221126556,0.2776606678962708,-0.2265405803918839)
>* FEATURE2_texOff(vec2(1,0));\n"
>+"res +=
>mat4(-0.2043980807065964,0.1931100338697433,-0.1295392960309982,0.1670256555080414,0.1645681709051132,0.0958901047706604,-0.1415763944387436,-0.0852059647440910,0.0435185469686985,-0.0328792855143547,-0.0462588928639889,0.0999711975455284,0.0152863729745150,0.2642010450363159,0.1177629753947258,0.0948430374264717)
>* FEATURE1_texOff(vec2(1,1));\n"
>+"res +=
>mat4(-0.0587063059210777,0.1132131591439247,0.0881500467658043,-0.0138335032388568,-0.1663987785577774,-0.3364221751689911,-0.0538316071033478,0.1316082775592804,-0.1181058958172798,0.3363447487354279,-0.2434223592281342,-0.3212656676769257,-0.0843391865491867,-0.0916209593415260,-0.0028905302751809,-0.0193154178559780)
>* FEATURE2_texOff(vec2(1,1));\n"
>+"res = max(res, vec4(0.0)) +
>vec4(0.7098640203475952,0.0766931846737862,0.3637206256389618,-1.0320047140121460)
>* min(res, vec4(0.0));\n"
>+"return res;\n"
>+"}\n"
>+"\n"
>+"//!HOOK LUMA\n"
>+"//!WHEN OUTPUT.w LUMA.w / 1.400 > OUTPUT.h LUMA.h / 1.400 > *\n"
>+"//!DESC mapping 2_1\n"
>+"//!BIND MODEL21\n"
>+"//!BIND MODEL22\n"
>+"//!SAVE MODEL1\n"
>+"//!COMPONENTS 4\n"
>+"vec4 hook()\n"
>+"{\n"
>+"vec4 res =
>vec4(0.0170852672308683,0.1754768192768097,-0.0627137199044228,0.0302415024489164);\n"
>+"res +=
>mat4(-0.0931400209665298,-0.0237767789512873,0.0855837464332581,-0.1704553067684174,0.0129925645887852,-0.0822458118200302,-0.1219799220561981,-0.0601306557655334,-0.0594861879944801,-0.0183524042367935,0.0934688523411751,-0.2627011835575104,-0.0636424720287323,-0.1815307885408401,-0.0725213587284088,0.2355831414461136)
>* MODEL21_texOff(vec2(-1,-1));\n"
>+"res +=
>mat4(0.1586687117815018,0.0477125458419323,0.1191117987036705,0.0885237306356430,-0.0693194717168808,-0.3822860717773438,-0.3097383081912994,-0.1164323017001152,-0.0672268941998482,-0.0349455587565899,0.1080945730209351,0.0402903184294701,0.0970795527100563,-0.0055673788301647,0.1673126667737961,0.0011124406009912)
>* MODEL22_texOff(vec2(-1,-1));\n"
>+"res +=
>mat4(0.1263304799795151,0.3918160498142242,-0.0310626626014709,0.2236307859420776,-0.1696615517139435,0.0825140103697777,0.0123340934514999,-0.0439517907798290,-0.5731655359268188,0.1721436530351639,0.4841386973857880,0.1342666149139404,-0.4224555492401123,-0.3453077971935272,0.1269877254962921,-0.0241462811827660)
>* MODEL21_texOff(vec2(-1,0));\n"
>+"res +=
>mat4(0.0936025679111481,0.3407166004180908,0.1189747974276543,0.1681626886129379,-0.0740653425455093,-0.0269140899181366,-0.2643758356571198,-0.4025750458240509,-1.2157027721405029,0.0141306081786752,0.1667129397392273,0.0317809544503689,-0.0372435189783573,-0.1464998275041580,-0.1486196666955948,0.2854102849960327)
>* MODEL22_texOff(vec2(-1,0));\n"
>+"res +=
>mat4(0.2344607859849930,-0.0437070950865746,0.1104629784822464,0.0181616060435772,-0.0374027714133263,0.0843154937028885,0.1492912769317627,0.0290796123445034,0.2762812674045563,-0.3372839093208313,-0.7284433841705322,0.1208302751183510,-0.0275538712739944,-0.1273225545883179,0.0373889580368996,-0.1029275581240654)
>* MODEL21_texOff(vec2(-1,1));\n"
>+"res +=
>mat4(-0.0658589303493500,-0.0235890019685030,-0.1662779599428177,0.0337554998695850,-0.0301105044782162,-0.0232451315969229,0.1063458472490311,-0.0921287536621094,-0.1864383369684219,-0.1079948619008064,-0.1556737273931503,-0.0972463414072990,-0.0956818684935570,-0.0370033904910088,-0.1714497506618500,0.0671783015131950)
>* MODEL22_texOff(vec2(-1,1));\n"
>+"res +=
>mat4(0.5518049597740173,0.3054741621017456,0.4884301424026489,0.2052321583032608,0.0554423928260803,-0.2306884229183197,-0.3487419784069061,0.1733721196651459,0.2059731036424637,-0.0815041884779930,0.0157276317477226,-0.1844915151596069,0.0940944850444794,-0.0187225975096226,-0.6224091649055481,0.2105529755353928)
>* MODEL21_texOff(vec2(0,-1));\n"
>+"res +=
>mat4(-0.3309973180294037,0.1998492777347565,0.4053513705730438,0.1465968340635300,-0.5744234323501587,-0.1534476727247238,-0.1628714352846146,-0.1142760068178177,-0.1416776478290558,-0.2358237057924271,0.0357218384742737,-0.2465225011110306,0.0415220148861408,-0.0204985402524471,0.1452716737985611,0.2796818614006042)
>* MODEL22_texOff(vec2(0,-1));\n"
>+"res +=
>mat4(-0.2862755060195923,-0.2560610771179199,-0.1548099368810654,-0.0013100239448249,0.0446441359817982,0.3339889049530029,-0.0998727530241013,-0.3175982236862183,0.4485007822513580,0.6848791837692261,0.7224821448326111,0.2956418693065643,-0.1925158649682999,-0.0955462753772736,-0.6139006614685059,-0.2369281500577927)
>* MODEL21_texOff(vec2(0,0));\n"
>+"res +=
>mat4(-0.2898988127708435,-1.6114324331283569,-0.6497008800506592,-0.9161678552627563,-0.1294765472412109,0.2167941927909851,0.0852003544569016,-1.1330174207687378,-0.0520029030740261,0.3535615503787994,0.4347914457321167,-0.1785785406827927,-0.0162681266665459,-0.3837141692638397,-0.2281536757946014,0.5625996589660645)
>* MODEL22_texOff(vec2(0,0));\n"
>+"res +=
>mat4(0.0016091616125777,0.1848176270723343,0.0971201434731483,0.0476905778050423,0.0907942056655884,0.0670004040002823,0.4161639213562012,0.0226902849972248,-0.0815638229250908,0.0852723494172096,-0.1269616484642029,0.1503992378711700,-0.0042979470454156,-0.1023452207446098,0.4321777522563934,-0.1758938729763031)
>* MODEL21_texOff(vec2(0,1));\n"
>+"res +=
>mat4(-0.0263243932276964,-0.0069954907521605,-0.0154204443097115,-0.1056053787469864,-0.0933614373207092,-0.0158285237848759,0.1006969884037971,0.2852162122726440,-0.2413168698549271,-0.2138358950614929,-0.0675798058509827,-0.0901125967502594,0.0245993416756392,-0.1903851926326752,-0.1932047605514526,0.0820922628045082)
>* MODEL22_texOff(vec2(0,1));\n"
>+"res +=
>mat4(-0.0577091686427593,-0.0598438680171967,0.0697890818119049,0.1319416314363480,-0.0054704342037439,-0.0452299080789089,-0.0168627519160509,0.0805051326751709,-0.0391492284834385,0.0598545372486115,0.0536216758191586,0.0556527078151703,0.0907164514064789,0.0427277833223343,-0.1744621098041534,0.0604149885475636)
>* MODEL21_texOff(vec2(1,-1));\n"
>+"res +=
>mat4(0.1369765251874924,0.0725676268339157,0.0216140300035477,-0.0474567748606205,0.1260448843240738,-0.0171130504459143,0.0028061545453966,-0.0481070056557655,0.1716193258762360,0.0221426580101252,0.0267592072486877,-0.1099357903003693,-0.0535003803670406,-0.0689668506383896,0.0656930506229401,0.0978998914361000)
>* MODEL22_texOff(vec2(1,-1));\n"
>+"res +=
>mat4(-0.1035909578204155,-0.2226496487855911,-0.1903141438961029,0.0017070659669116,0.0793713405728340,-0.0010820962488651,-0.0107912234961987,0.0693624392151833,-0.0736127495765686,-0.1524748355150223,0.1226568073034286,0.0990220680832863,0.2857215106487274,0.1066748276352882,-0.1393123418092728,-0.1454365849494934)
>* MODEL21_texOff(vec2(1,0));\n"
>+"res +=
>mat4(0.1245167329907417,-0.0028252182528377,-0.0940304324030876,-0.3640029132366180,0.0347177311778069,-0.0187527481466532,-0.0822448283433914,0.1278963088989258,0.1492267847061157,0.1060213446617126,0.1648002862930298,-0.0813168436288834,-0.0807213038206100,-0.2454172372817993,-0.1133850738406181,0.1994516551494598)
>* MODEL22_texOff(vec2(1,0));\n"
>+"res +=
>mat4(0.0289496872574091,-0.0847750827670097,-0.0586284920573235,-0.1127424016594887,0.0581536702811718,-0.0530946478247643,0.0264044813811779,0.0131464423611760,-0.1284686177968979,-0.2353171259164810,-0.2685572504997253,-0.0976479724049568,0.0581594705581665,-0.0104323895648122,0.1011395603418350,-0.0416379123926163)
>* MODEL21_texOff(vec2(1,1));\n"
>+"res +=
>mat4(0.0621624402701855,0.1550001055002213,0.0538265220820904,0.1827560365200043,-0.0107104340568185,-0.1418752521276474,-0.0798636451363564,-0.0977272018790245,0.0990920141339302,-0.2121141552925110,-0.1391585767269135,-0.1540260761976242,-0.0604653060436249,-0.0552443675696850,-0.0668276846408844,-0.0156545545905828)
>* MODEL22_texOff(vec2(1,1));\n"
>+"res = max(res, vec4(0.0)) +
>vec4(-0.2318671345710754,0.7420083284378052,-0.0778856053948402,-0.0301342587918043)
>* min(res, vec4(0.0));\n"
>+"return res;\n"
>+"}\n"
>+"\n"
>+"//!HOOK LUMA\n"
>+"//!WHEN OUTPUT.w LUMA.w / 1.400 > OUTPUT.h LUMA.h / 1.400 > *\n"
>+"//!DESC mapping 2_2\n"
>+"//!BIND MODEL21\n"
>+"//!BIND MODEL22\n"
>+"//!SAVE MODEL2\n"
>+"//!COMPONENTS 4\n"
>+"vec4 hook()\n"
>+"{\n"
>+"vec4 res =
>vec4(-0.0277962964028120,-0.1985717415809631,-0.1073290854692459,0.0024779480881989);\n"
>+"res +=
>mat4(0.0811279267072678,0.0074660247191787,-0.1123609691858292,-0.1698360890150070,0.0887257382273674,0.0695393756031990,-0.0230618994683027,0.0425623953342438,-0.0402214825153351,-0.0494129322469234,0.0075045302510262,-0.1391221880912781,0.0254898946732283,0.4202036559581757,0.0169367715716362,0.1162970736622810)
>* MODEL21_texOff(vec2(-1,-1));\n"
>+"res +=
>mat4(-0.0802845284342766,0.1618342101573944,0.0214038863778114,-0.2994922995567322,0.0226798132061958,0.2954163253307343,-0.0215967521071434,-0.5252735614776611,0.0696822255849838,0.2052475959062576,-0.0265055596828461,-0.3944848477840424,-0.0293094571679831,-0.1143697351217270,-0.2332055270671844,0.0820663794875145)
>* MODEL22_texOff(vec2(-1,-1));\n"
>+"res +=
>mat4(-0.1305592358112335,0.1524927467107773,-0.1609038710594177,0.0517596006393433,-0.1367315053939819,-2.1721241474151611,-0.0425806902348995,-0.5179468393325806,-0.3222553730010986,-0.0723694413900375,-0.1671267896890640,-0.1768694370985031,0.0145429829135537,1.2765067815780640,0.0857309028506279,-0.1213190108537674)
>* MODEL21_texOff(vec2(-1,0));\n"
>+"res +=
>mat4(-0.0878979638218880,-0.1144944056868553,-0.0365805886685848,-0.1373428404331207,-0.5292419195175171,0.2898582518100739,0.4178947806358337,-0.3772258162498474,0.1027076691389084,-1.1238411664962769,-0.0285698007792234,-0.2039057314395905,-0.0069273989647627,-0.2929974794387817,-0.1790267378091812,-0.1915181130170822)
>* MODEL22_texOff(vec2(-1,0));\n"
>+"res +=
>mat4(-0.0027788090519607,0.1994122415781021,-0.0658224076032639,-0.0885038822889328,0.0192358922213316,-0.3080857992172241,0.0648125559091568,-0.0109508289024234,0.4696615040302277,0.8840224146842957,0.4751364588737488,0.4315017461776733,-0.0338732637465000,0.1475903391838074,0.0496989339590073,0.3155167400836945)
>* MODEL21_texOff(vec2(-1,1));\n"
>+"res +=
>mat4(0.2046297043561935,-0.0113510843366385,-0.1336063444614410,0.0946211144328117,0.2006236314773560,-0.6351781487464905,-0.0755926892161369,-0.1520015448331833,-0.0999751240015030,0.2593304514884949,0.0965519472956657,0.2498497962951660,-0.0299775637686253,0.1339000463485718,0.0341237075626850,-0.1136132776737213)
>* MODEL22_texOff(vec2(-1,1));\n"
>+"res +=
>mat4(0.2127998173236847,-0.0665372312068939,-0.0486807338893414,-0.1437880396842957,0.0497845709323883,0.0425300449132919,0.3046301007270813,-0.4497503638267517,-0.0195727851241827,0.0320491380989552,0.0940830633044243,-0.3503444790840149,0.1265476793050766,0.0284851286560297,0.1494453102350235,-0.1369292140007019)
>* MODEL21_texOff(vec2(0,-1));\n"
>+"res +=
>mat4(0.0193372890353203,-0.0583674572408199,0.0966557711362839,-0.0055422247387469,-0.2081770449876785,-0.2165530174970627,-0.2706160545349121,-0.2146805375814438,-0.0813463777303696,-0.0948553904891014,0.2122844904661179,-0.1930102258920670,-0.0226625949144363,0.0802941769361496,-0.0844247564673424,-0.2097038626670837)
>* MODEL22_texOff(vec2(0,-1));\n"
>+"res +=
>mat4(0.3460392951965332,0.1599349826574326,0.6250801682472229,0.3714946210384369,-0.2429305166006088,-0.3126616179943085,-0.2521853744983673,0.6393439173698425,0.8533813357353210,-0.0008887434378266,-0.1081943884491920,0.0141481142491102,-0.2327625900506973,0.5992668271064758,0.1654740422964096,0.2001186907291412)
>* MODEL21_texOff(vec2(0,0));\n"
>+"res +=
>mat4(-0.3201945126056671,0.2158686816692352,0.4808782339096069,0.3057269752025604,-0.0329684093594551,-0.1631115376949310,-0.2552576959133148,0.9101773500442505,0.3970953226089478,0.1502509266138077,-1.0378246307373047,0.5801510214805603,-0.0599720627069473,0.3526532053947449,-0.1161249279975891,-1.0023722648620605)
>* MODEL22_texOff(vec2(0,0));\n"
>+"res +=
>mat4(-0.2168209403753281,0.0998821482062340,-0.1336549669504166,-0.0789565145969391,-0.0151122109964490,-0.0596244931221008,-0.1091464981436729,-0.4192503094673157,-0.6139240860939026,0.1908052265644073,0.2090514600276947,-0.9000411033630371,-0.0499179288744926,0.0016722747823223,0.0995322465896606,-0.0792622715234756)
>* MODEL21_texOff(vec2(0,1));\n"
>+"res +=
>mat4(0.1512538343667984,-0.2905358672142029,0.2784178853034973,0.1258104890584946,0.0470921844244003,-0.2929796874523163,-0.1228972077369690,-0.2208275347948074,0.1874402612447739,-0.2628239393234253,-0.2582434415817261,0.1609193980693817,-0.0752650573849678,0.3131484985351562,0.0215509850531816,-0.3643134832382202)
>* MODEL22_texOff(vec2(0,1));\n"
>+"res +=
>mat4(-0.5330864787101746,0.0843170583248138,0.1725275665521622,-0.1399286836385727,0.0505804196000099,0.1321723610162735,0.0438907966017723,-0.0251032691448927,-0.1317399144172668,0.0904046818614006,0.0580981522798538,0.2780447900295258,0.2909097969532013,-0.2710727155208588,0.1846283972263336,0.2557875812053680)
>* MODEL21_texOff(vec2(1,-1));\n"
>+"res +=
>mat4(0.1052682772278786,0.0152548532932997,-0.0724217891693115,-0.1686895936727524,0.0116551164537668,-0.0006738404044881,-0.1962697654962540,-0.1504792273044586,-0.2718438506126404,0.1645846813917160,-0.0128216696903110,-0.2176218032836914,-0.0822013542056084,0.1193229258060455,0.0228683147579432,-0.5918979048728943)
>* MODEL22_texOff(vec2(1,-1));\n"
>+"res +=
>mat4(0.5001649260520935,0.1525778472423553,-0.2781682014465332,0.3029212355613708,-0.0253654718399048,0.1450597494840622,-0.1043521687388420,0.1034010127186775,-0.3055011928081512,0.1234659999608994,0.0118490746244788,-0.2236849963665009,-0.1850311309099197,-0.2264277487993240,0.0382909364998341,0.3111994862556458)
>* MODEL21_texOff(vec2(1,0));\n"
>+"res +=
>mat4(-0.0652613714337349,-0.0636309683322906,0.0623881965875626,-0.4115606546401978,-0.0362407267093658,-0.0758407562971115,-0.0237175114452839,-0.1603217720985413,-0.0034343234729022,-0.0568042472004890,0.1311943382024765,-0.0911655426025391,-0.0415358208119869,0.1019693464040756,0.0110998479649425,-0.8333273530006409)
>* MODEL22_texOff(vec2(1,0));\n"
>+"res +=
>mat4(-0.1385643035173416,0.0797013565897942,0.0755145698785782,-0.1554726809263229,0.0761961191892624,0.0178027655929327,-0.0201916396617889,-0.0088773984462023,0.2822583615779877,0.1116631478071213,-0.1677276343107224,0.1308263391256332,-0.0420431457459927,-0.1551911383867264,-0.0575244240462780,-0.0716035813093185)
>* MODEL21_texOff(vec2(1,1));\n"
>+"res +=
>mat4(-0.0768667981028557,-0.0895799547433853,0.0320499837398529,0.0852961093187332,-0.0108671924099326,0.0238100197166204,0.1119633167982101,-0.1320123374462128,-0.0117039503529668,-0.0743943154811859,0.2794823646545410,-0.3045157492160797,-0.0511143058538437,0.1158826500177383,-0.0150672988966107,-0.1828779727220535)
>* MODEL22_texOff(vec2(1,1));\n"
>+"res = max(res, vec4(0.0)) +
>vec4(-0.6132344007492065,-0.1048434227705002,0.2299597710371017,0.3570503592491150)
>* min(res, vec4(0.0));\n"
>+"return res;\n"
>+"}\n"
>+"\n"
>+"//!HOOK LUMA\n"
>+"//!WHEN OUTPUT.w LUMA.w / 1.400 > OUTPUT.h LUMA.h / 1.400 > *\n"
>+"//!DESC mapping 3_1\n"
>+"//!BIND MODEL1\n"
>+"//!BIND MODEL2\n"
>+"//!SAVE MODEL21\n"
>+"//!COMPONENTS 4\n"
>+"vec4 hook()\n"
>+"{\n"
>+"vec4 res =
>vec4(-0.0223876163363457,-0.1060141399502754,-0.0375914238393307,-0.0862116292119026);\n"
>+"res +=
>mat4(0.1013671904802322,-0.0008966500754468,-0.0194363538175821,0.0293231215327978,-0.2108464688062668,0.1387624591588974,0.2029845416545868,0.2638971507549286,0.0770234093070030,-0.0712974220514297,-0.1913846135139465,-0.1378045678138733,0.0712766721844673,-0.1582399159669876,-0.1504500806331635,-0.2732931673526764)
>* MODEL1_texOff(vec2(-1,-1));\n"
>+"res +=
>mat4(-0.0748330578207970,0.1360757201910019,0.1096481382846832,0.2175049185752869,-0.0683394894003868,-0.0237707924097776,-0.0299128498882055,-0.0306253079324961,-0.1490836739540100,0.0788012593984604,0.3392792344093323,0.2738935053348541,-0.0176930949091911,-0.1533411741256714,0.0104268807917833,-0.0417343936860561)
>* MODEL2_texOff(vec2(-1,-1));\n"
>+"res +=
>mat4(0.1430606544017792,-0.0952415987849236,-0.0850753188133240,0.1663968563079834,-0.5190618634223938,0.1381558626890182,-0.0927182435989380,0.0211467109620571,-0.0103359837085009,-0.2416747361421585,0.1547979712486267,0.0550021231174469,0.6593996882438660,-0.0052760266698897,0.1669664382934570,-0.1481335610151291)
>* MODEL1_texOff(vec2(-1,0));\n"
>+"res +=
>mat4(-0.1292387545108795,0.0806952938437462,0.1296790540218353,0.1629347801208496,0.0034854845143855,0.0114065753296018,-0.0582312010228634,0.1158575117588043,-0.0298857595771551,0.1987122148275375,0.0519650056958199,0.0971973165869713,-0.0489671379327774,0.0091792531311512,-0.0470198020339012,0.5538328886032104)
>* MODEL2_texOff(vec2(-1,0));\n"
>+"res +=
>mat4(0.1522281914949417,-0.0830676928162575,-0.0427808649837971,0.1645870953798294,-0.1834830194711685,0.1507919579744339,-0.0869903713464737,0.2409375011920929,0.3105009198188782,-0.0797038674354553,0.0481293871998787,0.1739223003387451,0.2889033854007721,-0.0481913201510906,0.0193167831748724,-0.2335342168807983)
>* MODEL1_texOff(vec2(-1,1));\n"
>+"res +=
>mat4(-0.1339087784290314,0.0135729340836406,0.0017057523364201,0.1232617646455765,0.0936431288719177,-0.0061019957065582,0.0483435392379761,0.0358846895396709,0.0329014733433723,0.0080857872962952,0.0264126416295767,0.1091407164931297,0.0051449947059155,0.0459520667791367,0.2559313178062439,0.0254027042537928)
>* MODEL2_texOff(vec2(-1,1));\n"
>+"res +=
>mat4(0.2763945162296295,-0.1671462655067444,-0.4170847535133362,-0.0646260008215904,0.0370063446462154,0.2403483241796494,0.3464761972427368,0.4420733153820038,0.1046821698546410,-0.1590311229228973,-0.3228488266468048,-0.3738996684551239,-0.1320944428443909,0.0989339128136635,0.2841468453407288,0.0361787155270576)
>* MODEL1_texOff(vec2(0,-1));\n"
>+"res +=
>mat4(-0.1898700892925262,-0.1074944883584976,0.1685077250003815,0.1985697895288467,0.0775568783283234,0.0569792352616787,0.0296473111957312,0.1420489847660065,0.1281145811080933,-0.0312079358845949,-0.0475365631282330,0.2561178207397461,0.0888698995113373,0.2041971385478973,0.0536539517343044,0.1834559142589569)
>* MODEL2_texOff(vec2(0,-1));\n"
>+"res +=
>mat4(0.8149192333221436,-0.1549599319696426,-0.0398781448602676,0.1907377243041992,0.5374071598052979,0.3798620700836182,-0.8058248162269592,-0.4151621460914612,-0.1357343643903732,0.1275762319564819,0.1624598950147629,0.1195950731635094,0.0608592294156551,-0.1190541386604309,0.3604308366775513,-0.1245594546198845)
>* MODEL1_texOff(vec2(0,0));\n"
>+"res +=
>mat4(0.0132273323833942,-0.0871523097157478,0.2945240736007690,0.3798495829105377,-0.3759584724903107,0.1892248541116714,-0.1873332411050797,-0.1617792844772339,0.3424457609653473,-0.6391636133193970,0.1942865252494812,-0.1862158477306366,0.1946611702442169,-0.6375469565391541,0.1491231173276901,-0.4260959029197693)
>* MODEL2_texOff(vec2(0,0));\n"
>+"res +=
>mat4(0.1746832281351089,-0.0017380628269166,-0.1237998753786087,0.2028179317712784,0.2590698599815369,-0.0494076348841190,-0.1398809403181076,-0.2654671669006348,-0.0890956223011017,-0.0703305453062057,0.8770728707313538,0.2524497807025909,-0.1574884057044983,0.0695457831025124,-0.0433092303574085,0.1632892340421677)
>* MODEL1_texOff(vec2(0,1));\n"
>+"res +=
>mat4(-0.1302398443222046,-0.0040268478915095,-0.1021594405174255,0.2535715103149414,-0.1323277950286865,0.1275873929262161,-0.0125783141702414,-0.1065506339073181,0.2126190364360809,-0.0716433450579643,-0.1399456411600113,-0.1613145619630814,0.0611384660005569,0.1994681358337402,0.0071717957034707,0.3500899672508240)
>* MODEL2_texOff(vec2(0,1));\n"
>+"res +=
>mat4(0.1338834315538406,0.4561931192874908,-0.3260883390903473,-0.0752537846565247,-0.0519016571342945,-0.3868822753429413,0.0857315957546234,0.0304831005632877,0.0825385004281998,0.1934611946344376,-0.0811349377036095,-0.0652359500527382,-0.0335477814078331,0.0300130043178797,-0.0105781471356750,-0.0197946280241013)
>* MODEL1_texOff(vec2(1,-1));\n"
>+"res +=
>mat4(-0.0731661468744278,0.0308893136680126,0.0310089495033026,0.0473398417234421,-0.0115999020636082,-0.2099719643592834,0.1937284916639328,-0.0073863309808075,-0.1198604255914688,-0.3530882596969604,-0.0697741732001305,0.1949538886547089,-0.0272669252008200,0.0460121221840382,0.0147004248574376,0.1585798114538193)
>* MODEL2_texOff(vec2(1,-1));\n"
>+"res +=
>mat4(-0.1022168323397636,0.7095627784729004,-0.2185215055942535,0.2094996720552444,-0.1721526831388474,-0.6260859370231628,-0.5178827643394470,0.5061489939689636,-0.0798222795128822,-0.1110334396362305,0.0856799781322479,-0.0311204418540001,0.4083582460880280,0.2862063944339752,0.2614927589893341,-0.5276373028755188)
>* MODEL1_texOff(vec2(1,0));\n"
>+"res +=
>mat4(-0.1420304775238037,0.0572568885982037,0.3356675207614899,0.2554636895656586,0.0592874400317669,-0.5449101328849792,-0.4398454427719116,0.0600654222071171,-0.1661207824945450,-0.1341700553894043,-0.2126734405755997,0.2419272810220718,0.1610593050718307,0.6282448768615723,0.2777999937534332,-0.0905571207404137)
>* MODEL2_texOff(vec2(1,0));\n"
>+"res +=
>mat4(0.0298360809683800,0.1987157464027405,-0.1374524235725403,0.1534184962511063,0.0158272013068199,-0.1292124241590500,-0.0387871898710728,-0.1102364882826805,-0.0054649654775858,0.0611486248672009,0.2487671375274658,0.1022587195038795,-0.0555493459105492,0.0559154413640499,-0.0502201877534389,-0.0482881888747215)
>* MODEL1_texOff(vec2(1,1));\n"
>+"res +=
>mat4(-0.1757578998804092,0.0737955793738365,-0.1124436780810356,0.1969589740037918,0.0451212599873543,-0.1802255362272263,0.0657186284661293,-0.0965084135532379,-0.0404272116720676,-0.0456601753830910,-0.0886195003986359,0.0086781838908792,-0.0186991002410650,-0.0061616031453013,0.1062913164496422,0.2349348962306976)
>* MODEL2_texOff(vec2(1,1));\n"
>+"res = max(res, vec4(0.0)) +
>vec4(0.1609187573194504,-0.0946575552225113,-0.0790160596370697,0.1213655844330788)
>* min(res, vec4(0.0));\n"
>+"return res;\n"
>+"}\n"
>+"\n"
>+"//!HOOK LUMA\n"
>+"//!WHEN OUTPUT.w LUMA.w / 1.400 > OUTPUT.h LUMA.h / 1.400 > *\n"
>+"//!DESC mapping 3_2\n"
>+"//!BIND MODEL1\n"
>+"//!BIND MODEL2\n"
>+"//!SAVE MODEL22\n"
>+"//!COMPONENTS 4\n"
>+"vec4 hook()\n"
>+"{\n"
>+"vec4 res =
>vec4(0.0064181881025434,-0.0259227696806192,0.0406666919589043,0.0599326454102993);\n"
>+"res +=
>mat4(-0.0039523728191853,-0.0166944731026888,0.1361859589815140,-0.0201154630631208,0.0942757576704025,-0.1183404922485352,-0.2264956831932068,0.0679138749837875,-0.0542402677237988,-0.0026190269272774,0.0963397398591042,0.0989206135272980,-0.1445381492376328,0.0698397532105446,0.1937166750431061,-0.0864010825753212)
>* MODEL1_texOff(vec2(-1,-1));\n"
>+"res +=
>mat4(0.0150467175990343,-0.0312143526971340,-0.1048866659402847,-0.2127760201692581,0.0351309441030025,-0.0012529657687992,0.0341468080878258,-0.0028853572439402,0.1041057184338570,-0.0196230970323086,-0.3013583719730377,0.1678945571184158,-0.0668827295303345,0.0897152796387672,0.1255217045545578,-0.1349137872457504)
>* MODEL2_texOff(vec2(-1,-1));\n"
>+"res +=
>mat4(0.0176613666117191,0.0787993520498276,0.1570415347814560,-0.2253918200731277,0.0039341864176095,-0.0495097376406193,-0.1900888532400131,-0.2414494454860687,0.0237120874226093,-0.0472709573805332,0.2651004195213318,-0.1512611955404282,-0.0996168330311775,-0.0312318522483110,0.1397448033094406,0.5598028302192688)
>* MODEL1_texOff(vec2(-1,0));\n"
>+"res +=
>mat4(0.1033441573381424,0.0357948578894138,0.0066860495135188,-0.3447679877281189,0.0209082979708910,0.0074101840145886,-0.0075660115107894,-0.0895587205886841,-0.0044016228057444,0.2342877388000488,-0.4525326788425446,-0.8056878447532654,0.2871247231960297,-0.2533628046512604,0.1330502927303314,-0.2711409032344818)
>* MODEL2_texOff(vec2(-1,0));\n"
>+"res +=
>mat4(0.0583821088075638,0.0204717628657818,0.1192677393555641,-0.0600049458444118,0.0843947380781174,-0.0753051564097404,-0.2268095910549164,-0.2611580193042755,0.2172089070081711,0.1219054833054543,-0.0993994548916817,0.0905438512563705,-0.0409951210021973,0.1742875427007675,0.2137323915958405,0.2096306979656219)
>* MODEL1_texOff(vec2(-1,1));\n"
>+"res +=
>mat4(-0.0397010035812855,0.0251092258840799,0.0135528091341257,-0.1557388156652451,0.0413166508078575,-0.0047097569331527,0.0505524128675461,0.0224600080400705,0.0564471706748009,-0.0251139067113400,-0.0540590249001980,0.2744260728359222,0.1302299052476883,0.3032833337783813,0.1519231945276260,-0.3402486443519592)
>* MODEL2_texOff(vec2(-1,1));\n"
>+"res +=
>mat4(-0.0285596437752247,-0.0276553630828857,0.4868887960910797,-0.4238637983798981,0.3947734236717224,0.1251066476106644,-0.5504105091094971,0.1018530502915382,-0.0729319527745247,-0.0388933569192886,0.1533280014991760,-0.2760451734066010,0.0876579135656357,-0.2336451560258865,0.1346376091241837,0.1064044833183289)
>* MODEL1_texOff(vec2(0,-1));\n"
>+"res +=
>mat4(-0.1357216387987137,-0.1224066168069839,-0.0470801629126072,-0.1234838292002678,-0.0294233579188585,0.1328788548707962,-0.1545499563217163,-0.0000642365994281,0.2182460725307465,0.1404720246791840,-0.2252583205699921,-0.0620441175997257,-0.1656052023172379,-0.0115656917914748,0.3748327493667603,0.0667838007211685)
>* MODEL2_texOff(vec2(0,-1));\n"
>+"res +=
>mat4(0.0323339067399502,0.1893317997455597,0.5513858795166016,0.1013554707169533,-0.6044452786445618,0.8673651814460754,-0.5931649208068848,-0.3769782781600952,-0.2771540582180023,-0.1378411352634430,-0.4137916266918182,0.1723879426717758,0.5354951620101929,0.2126991301774979,0.2443658560514450,-0.0116818901151419)
>* MODEL1_texOff(vec2(0,0));\n"
>+"res +=
>mat4(0.3901599645614624,-0.0600736550986767,-0.1424410343170166,-0.5579664111137390,-0.1640415042638779,-0.2058803737163544,-0.2200153321027756,0.1915101855993271,-0.4552527368068695,-0.4645490348339081,-0.3845494687557220,-0.1247850656509399,-0.0977618470788002,-0.4014683365821838,0.9994732141494751,0.1317824721336365)
>* MODEL2_texOff(vec2(0,0));\n"
>+"res +=
>mat4(0.1280290782451630,-0.0382165834307671,0.1509062200784683,-0.1547142714262009,-0.2374099791049957,-0.1576380282640457,-0.0476975589990616,0.2468438446521759,0.4687332510948181,-0.0778920948505402,-0.0896032452583313,-0.1789693683385849,0.1652538627386093,0.3148133754730225,0.0339899696409702,0.0225938688963652)
>* MODEL1_texOff(vec2(0,1));\n"
>+"res +=
>mat4(0.0260912012308836,0.0463759563863277,-0.0895745158195496,-0.4719817340373993,-0.0984568670392036,0.0127850100398064,-0.2087419927120209,-0.0011450822930783,0.1505791991949081,0.0494427233934402,-0.1376535594463348,-0.0050549805164337,0.1307158023118973,0.2804140746593475,0.1087402924895287,-0.4842006862163544)
>* MODEL2_texOff(vec2(0,1));\n"
>+"res +=
>mat4(-0.0245725456625223,0.1157737150788307,-0.1305489689111710,-0.2341742664575577,-0.0085867978632450,0.0217456500977278,0.1095358431339264,0.2995744943618774,0.0353404842317104,-0.0478601306676865,0.1008872538805008,-0.2372021228075027,0.0912027508020401,-0.0460772588849068,-0.0647807717323303,0.0256041679531336)
>* MODEL1_texOff(vec2(1,-1));\n"
>+"res +=
>mat4(-0.1079787760972977,-0.0873825103044510,0.0202728714793921,-0.1394625753164291,-0.0651071518659592,0.1187325865030289,-0.0126405786722898,0.1127787902951241,0.1432453244924545,-0.0489304624497890,0.1141109019517899,0.2113149315118790,0.1943181455135345,-0.0201897267252207,-0.1323021799325943,-0.2091996222734451)
>* MODEL2_texOff(vec2(1,-1));\n"
>+"res +=
>mat4(-0.3917024731636047,0.0635988339781761,-0.2040501087903976,0.1099524125456810,0.5731406211853027,-0.1218973547220230,0.2559791207313538,-0.2311069816350937,-0.4361894726753235,-0.0275644734501839,-0.1601174473762512,0.0153250126168132,-0.3946089446544647,0.1204118654131889,0.0164085868746042,0.0389540232717991)
>* MODEL1_texOff(vec2(1,0));\n"
>+"res +=
>mat4(-0.0099905598908663,-0.0527591370046139,-0.1892661005258560,-0.1289718598127365,0.0783784911036491,-0.1491151750087738,0.5096955299377441,0.3531769812107086,0.0478162728250027,0.1140898466110229,0.1271728277206421,-0.4512892365455627,-0.3271526098251343,-0.0411172397434711,0.0192377734929323,-0.1060684397816658)
>* MODEL2_texOff(vec2(1,0));\n"
>+"res +=
>mat4(-0.1808445304632187,0.0439403019845486,0.0046319882385433,-0.0107918214052916,-0.0387498624622822,-0.1656891405582428,0.1761767268180847,-0.1364894211292267,0.1131881847977638,-0.0269920863211155,-0.0969191715121269,0.3675734698772430,-0.0277221314609051,0.2383823692798615,-0.1321512162685394,0.0091815656051040)
>* MODEL1_texOff(vec2(1,1));\n"
>+"res +=
>mat4(0.0388181433081627,0.0435212217271328,-0.0346373878419399,-0.2265397012233734,0.0378025285899639,0.0081948498263955,0.1107296943664551,-0.1417375653982162,0.0815773829817772,-0.0735603570938110,-0.0326302200555801,0.0479511842131615,0.0689493268728256,0.1757876574993134,-0.0191873144358397,-0.1522977501153946)
>* MODEL2_texOff(vec2(1,1));\n"
>+"res = max(res, vec4(0.0)) +
>vec4(0.7232648730278015,0.9874973893165588,-0.0601831488311291,0.0691924914717674)
>* min(res, vec4(0.0));\n"
>+"return res;\n"
>+"}\n"
>+"\n"
>+"//!HOOK LUMA\n"
>+"//!WHEN OUTPUT.w LUMA.w / 1.400 > OUTPUT.h LUMA.h / 1.400 > *\n"
>+"//!DESC mapping 4_1\n"
>+"//!BIND MODEL21\n"
>+"//!BIND MODEL22\n"
>+"//!SAVE MODEL1\n"
>+"//!COMPONENTS 4\n"
>+"vec4 hook()\n"
>+"{\n"
>+"vec4 res =
>vec4(-0.1219381392002106,-0.0790507122874260,-0.3221280276775360,0.0397348254919052);\n"
>+"res +=
>mat4(-0.1017600074410439,0.0495688579976559,-0.0654498636722565,-0.0167406126856804,-0.0007491247961298,0.1112839952111244,0.1065567061305046,-0.0225107502192259,0.2274755239486694,-0.0061609148979187,0.0719428509473801,0.0340589769184589,-0.2152699679136276,0.0420854240655899,-0.0334651134908199,0.0491120442748070)
>* MODEL21_texOff(vec2(-1,-1));\n"
>+"res +=
>mat4(0.1571779996156693,-0.0577792786061764,0.0097382329404354,0.0158820338547230,0.2712175846099854,-0.1488136202096939,0.1924094259738922,-0.0046032452955842,0.0637685656547546,-0.1152549237012863,0.0239769611507654,0.0751061886548996,0.2221538424491882,-0.0220860783010721,0.0449791625142097,-0.1009933352470398)
>* MODEL22_texOff(vec2(-1,-1));\n"
>+"res +=
>mat4(-0.0844984054565430,0.2636422216892242,0.0016927721444517,-0.0643225610256195,0.0337424241006374,0.4673462808132172,-0.6024654507637024,-0.0573053732514381,0.2988144159317017,0.0445896126329899,-0.0025431730318815,-0.1122468411922455,0.1105892434716225,-0.2006048411130905,0.1512571573257446,0.4046979248523712)
>* MODEL21_texOff(vec2(-1,0));\n"
>+"res +=
>mat4(-0.2191342264413834,0.1729478687047958,-0.4474693536758423,-0.0645105540752411,0.0259194243699312,-0.4066369831562042,0.0902574956417084,-0.0233057383447886,-0.0850830376148224,-0.0999078750610352,0.1487859487533569,0.0047223321162164,-0.0726208835840225,-0.1409423053264618,0.0899705886840820,-0.0766842514276505)
>* MODEL22_texOff(vec2(-1,0));\n"
>+"res +=
>mat4(0.1522485911846161,0.0448191352188587,-0.0241916012018919,0.1664255112409592,0.1005667597055435,0.3434527814388275,-0.0714822784066200,-0.2706309258937836,-0.1499702334403992,-0.1239210069179535,0.1764265000820160,-0.0681393072009087,-0.1617824137210846,-0.3176426589488983,0.0605716407299042,0.1052706092596054)
>* MODEL21_texOff(vec2(-1,1));\n"
>+"res +=
>mat4(0.2158439308404922,0.3614296019077301,-0.1488258391618729,-0.0626114830374718,-0.2261502742767334,-0.1595045328140259,-0.0628331452608109,-0.2174367755651474,-0.0012300200760365,-0.1403118968009949,0.0617400258779526,-0.0249802377074957,-0.0224191546440125,0.0074916360899806,0.0069430666044354,-0.0695253387093544)
>* MODEL22_texOff(vec2(-1,1));\n"
>+"res +=
>mat4(-0.0086935386061668,0.0023433216847479,-0.2092096805572510,0.0669924542307854,-0.2418711334466934,0.0315426290035248,-0.0542691163718700,0.0512491054832935,0.4985096752643585,-0.1108386516571045,0.1504421383142471,-0.0614218115806580,-0.3575291931629181,-0.0276890080422163,-0.0340618230402470,0.0840372964739799)
>* MODEL21_texOff(vec2(0,-1));\n"
>+"res +=
>mat4(-0.0347293987870216,0.1257031857967377,0.1808818429708481,-0.1229549273848534,0.1569978445768356,0.0310060828924179,0.0239518359303474,-0.0614995360374451,0.1544884443283081,-0.0836841315031052,0.0540530718863010,0.0833408832550049,-0.6157820224761963,0.1228396669030190,-0.1128233522176743,-0.1479846984148026)
>* MODEL22_texOff(vec2(0,-1));\n"
>+"res +=
>mat4(-0.2854860723018646,-0.4707961678504944,0.4754865765571594,-0.1192863062024117,0.0865553021430969,0.3882408440113068,0.5977408289909363,-0.2460058629512787,0.5416567325592041,-0.1934606134891510,-0.3532729744911194,0.1640860289335251,0.6124815940856934,0.1182176545262337,-0.3290739059448242,0.2970921397209167)
>* MODEL21_texOff(vec2(0,0));\n"
>+"res +=
>mat4(-0.3102855384349823,0.2551747262477875,0.2052904218435287,-0.2138385027647018,0.4829640090465546,0.4158059656620026,0.1083678156137466,-0.3597456812858582,-0.3352298736572266,-0.0784419924020767,0.0195386223495007,0.0849872529506683,0.2775708436965942,0.2592905759811401,0.0724860727787018,0.0689116716384888)
>* MODEL22_texOff(vec2(0,0));\n"
>+"res +=
>mat4(0.1967435926198959,0.0590742938220501,-0.1629939973354340,-0.1777479201555252,0.0392862856388092,0.3089727759361267,0.0910466834902763,0.2467705607414246,-0.4069617688655853,0.0346154943108559,0.4689309298992157,-0.2105397731065750,-0.6177817583084106,0.2816387712955475,0.1525848805904388,0.4978122413158417)
>* MODEL21_texOff(vec2(0,1));\n"
>+"res +=
>mat4(0.6134792566299438,-0.1651839166879654,-0.3392979800701141,-0.2016063481569290,-0.4988827109336853,0.0165337976068258,-0.1190381944179535,0.0861033424735069,-0.1875204294919968,-0.1175299808382988,-0.0018291439628229,0.2142289131879807,-0.1055680364370346,-0.0556148998439312,0.0594784431159496,0.1523706018924713)
>* MODEL22_texOff(vec2(0,1));\n"
>+"res +=
>mat4(0.1282928287982941,0.0646825581789017,0.0312928855419159,-0.0571724064648151,-0.0468447096645832,-0.0104887094348669,0.0229241624474525,0.0226127281785011,0.0348098129034042,-0.0056250318884850,0.0218307953327894,-0.0236172508448362,0.0443015806376934,0.0373805239796638,0.0865073651075363,0.1278683841228485)
>* MODEL21_texOff(vec2(1,-1));\n"
>+"res +=
>mat4(0.0582129806280136,0.0314427614212036,-0.0190347917377949,-0.1045988276600838,0.1489758193492889,0.0686797127127647,-0.0200294423848391,-0.0264233369380236,0.0114792706444860,-0.0254622921347618,0.0453386716544628,-0.0307057946920395,-0.0144761428236961,-0.1407660990953445,0.0296764168888330,-0.0640849620103836)
>* MODEL22_texOff(vec2(1,-1));\n"
>+"res +=
>mat4(-0.2620533704757690,0.3212752044200897,-0.2792171835899353,-0.0101119484752417,-0.1219495832920074,-0.1504399925470352,-0.1361173689365387,0.0446824319660664,0.0810224786400795,0.0766309276223183,0.1375989168882370,-0.0800683423876762,-0.1406240612268448,-0.0747951418161392,0.0301319975405931,0.0760102570056915)
>* MODEL21_texOff(vec2(1,0));\n"
>+"res +=
>mat4(-0.0646601468324661,-0.1756545603275299,-0.0859141200780869,-0.1492357999086380,0.1859129816293716,0.0563602522015572,-0.1343476921319962,-0.0493505783379078,0.1077095568180084,0.0083594713360071,-0.1668419688940048,-0.1470805108547211,-0.0465445592999458,-0.2999864816665649,-0.1158453449606895,-0.0573335997760296)
>* MODEL22_texOff(vec2(1,0));\n"
>+"res +=
>mat4(0.1681393831968307,0.0152606442570686,-0.1053326353430748,-0.3172874450683594,0.0793417170643806,-0.0107523798942566,0.0156386699527502,-0.0165198966860771,-0.0196700599044561,-0.0224391259253025,-0.0585874095559120,0.0483046658337116,0.1193192750215530,-0.3141980767250061,-0.0504838526248932,0.0017631716327742)
>* MODEL21_texOff(vec2(1,1));\n"
>+"res +=
>mat4(-0.0178457275032997,-0.0424896180629730,-0.0275529921054840,0.0286935623735189,-0.2767159342765808,0.1199326664209366,0.1847609430551529,0.0953740850090981,-0.0494991913437843,-0.1535772085189819,0.0131423044949770,-0.3098267316818237,-0.0422411374747753,-0.0453605018556118,0.0439272932708263,-0.0156619027256966)
>* MODEL22_texOff(vec2(1,1));\n"
>+"res = max(res, vec4(0.0)) +
>vec4(0.1535267978906631,0.0788198783993721,0.8006709218025208,-1.1152083873748779)
>* min(res, vec4(0.0));\n"
>+"return res;\n"
>+"}\n"
>+"\n"
>+"//!HOOK LUMA\n"
>+"//!WHEN OUTPUT.w LUMA.w / 1.400 > OUTPUT.h LUMA.h / 1.400 > *\n"
>+"//!DESC mapping 4_2\n"
>+"//!BIND MODEL21\n"
>+"//!BIND MODEL22\n"
>+"//!SAVE MODEL2\n"
>+"//!COMPONENTS 4\n"
>+"vec4 hook()\n"
>+"{\n"
>+"vec4 res =
>vec4(-0.1522458046674728,-0.1176200807094574,-0.0493635274469852,-0.1202499568462372);\n"
>+"res +=
>mat4(-0.0771020650863647,-0.1835827380418777,-0.0081384740769863,0.0861479341983795,0.0208919700235128,0.1035120040178299,-0.0502430573105812,0.1222835928201675,0.0430391579866409,0.0922289639711380,0.1100084111094475,0.0069761648774147,-0.1551695913076401,-0.0990428701043129,-0.0763163268566132,-0.0561440549790859)
>* MODEL21_texOff(vec2(-1,-1));\n"
>+"res +=
>mat4(0.0719620436429977,-0.0568698830902576,0.1621344834566116,0.0430643707513809,0.1784564107656479,0.2766394019126892,0.1303464770317078,-0.0785371139645576,-0.0372168906033039,0.0259647686034441,-0.0001707610354060,-0.0487672723829746,-0.0062727611511946,0.0827339813113213,-0.0015896770637482,0.0185013562440872)
>* MODEL22_texOff(vec2(-1,-1));\n"
>+"res +=
>mat4(-0.1141690313816071,-0.3864789903163910,0.0117045743390918,-0.0410739742219448,-0.2991279661655426,-0.3023860156536102,0.0640379041433334,-0.5278654098510742,0.0779961273074150,-0.1158203110098839,0.2473105341196060,-0.0286699123680592,0.1203970089554787,0.3581408858299255,-0.1676998734474182,-0.0002944025327452)
>* MODEL21_texOff(vec2(-1,0));\n"
>+"res +=
>mat4(-0.2078344970941544,-0.2168200612068176,-0.2492605745792389,0.1106662303209305,0.0422859936952591,0.6130946278572083,-0.1497821062803268,-0.1526037007570267,0.2224747985601425,0.2939948439598083,-0.1080380976200104,-0.0234465207904577,0.0625413656234741,0.1742270439863205,-0.0687456130981445,-0.0938172489404678)
>* MODEL22_texOff(vec2(-1,0));\n"
>+"res +=
>mat4(-0.0120489159598947,-0.0638357922434807,0.0465856455266476,0.0326742343604565,0.1520797610282898,0.0741466954350471,-0.1589285433292389,0.1507059484720230,0.0892619490623474,0.0574397295713425,0.1291393935680389,-0.0967971011996269,-0.0448387153446674,0.0426500365138054,0.0767922624945641,-0.1385603100061417)
>* MODEL21_texOff(vec2(-1,1));\n"
>+"res +=
>mat4(0.0089179025962949,-0.1982151120901108,-0.1210607215762138,0.1618970036506653,0.0632994994521141,0.1083795800805092,-0.0599545985460281,-0.0355151742696762,-0.1080972477793694,0.0240074582397938,0.0852770358324051,-0.0383624956011772,-0.0739892497658730,0.0166055001318455,-0.0541694983839989,-0.0688572153449059)
>* MODEL22_texOff(vec2(-1,1));\n"
>+"res +=
>mat4(0.0600926801562309,0.0330452211201191,-0.0600052624940872,0.0158219747245312,-0.0424280837178230,0.1686275601387024,0.0043287626467645,-0.1376630216836929,0.1595808714628220,-0.1054396033287048,0.0883698835968971,-0.0725852102041245,-0.3858007490634918,0.0984657034277916,-0.1034814044833183,0.0289911441504955)
>* MODEL21_texOff(vec2(0,-1));\n"
>+"res +=
>mat4(0.0847466960549355,-0.0574547760188580,0.1835886836051941,0.0323001705110073,0.1605575829744339,-0.1890910714864731,0.3518871665000916,0.0880172103643417,-0.0009017279371619,-0.0655495300889015,-0.0607127770781517,0.0656333267688751,-0.3252617418766022,-0.0882990211248398,-0.1063503772020340,-0.1173305958509445)
>* MODEL22_texOff(vec2(0,-1));\n"
>+"res +=
>mat4(-0.2139744013547897,0.2728379666805267,0.0953216552734375,0.1627894788980484,0.0782700255513191,0.2827286422252655,-0.0962168946862221,-0.2649762034416199,0.0268776975572109,0.0274035502225161,0.0634128600358963,0.0742966085672379,0.5284039378166199,-0.5676575303077698,-0.2223312854766846,-0.2637425065040588)
>* MODEL21_texOff(vec2(0,0));\n"
>+"res +=
>mat4(-0.2676552832126617,-0.1061118394136429,-0.2438690066337585,0.1965969502925873,0.3220265507698059,-0.6687815189361572,-0.4547998905181885,0.2259001135826111,0.1420317590236664,-0.3651925325393677,-0.1552470326423645,-0.7243188619613647,0.2074669301509857,-0.2797248661518097,-0.2326431572437286,-0.0420682765543461)
>* MODEL22_texOff(vec2(0,0));\n"
>+"res +=
>mat4(-0.1441280841827393,-0.0580659545958042,-0.0766427665948868,0.0445073284208775,-0.1947010904550552,0.3118771016597748,-0.1153057590126991,-0.1213182210922241,-0.1011707186698914,-0.0097622424364090,0.1497262865304947,-0.1319041848182678,-0.2436424195766449,-0.1389088928699493,0.0081290993839502,0.0271245092153549)
>* MODEL21_texOff(vec2(0,1));\n"
>+"res +=
>mat4(0.2379951030015945,-0.0184671003371477,-0.2403022646903992,0.2086649984121323,0.4841035306453705,0.0471651963889599,0.1150723621249199,-0.0110469879582524,-0.3783148527145386,-0.1705742329359055,0.2607840299606323,0.0240125581622124,-0.2391599118709564,-0.0585423707962036,0.0138141382485628,0.0322751887142658)
>* MODEL22_texOff(vec2(0,1));\n"
>+"res +=
>mat4(0.0621233880519867,-0.0027173764538020,0.0815972983837128,-0.0755037963390350,-0.0035977764055133,-0.0722839832305908,-0.0768231302499771,-0.0396159216761589,0.0116967726498842,-0.0022004032507539,0.1576369255781174,0.0411852225661278,0.0313400588929653,-0.1150726899504662,-0.0190158449113369,-0.0517728850245476)
>* MODEL21_texOff(vec2(1,-1));\n"
>+"res +=
>mat4(0.0093127898871899,0.0618187971413136,0.0160160325467587,0.0711727663874626,0.0770369693636894,-0.0805183798074722,0.0948489606380463,-0.0033589983358979,0.0155866248533130,-0.0041404594667256,0.0703734979033470,0.0753517970442772,-0.0638532936573029,-0.1308353394269943,-0.0125481272116303,0.1745975762605667)
>* MODEL22_texOff(vec2(1,-1));\n"
>+"res +=
>mat4(-0.2877179384231567,0.1759037822484970,-0.0149254146963358,-0.3645622134208679,-0.0966939702630043,0.2149588316679001,-0.0632176473736763,0.0326482281088829,0.0389980562031269,-0.0303172953426838,0.0756935626268387,-0.0256333146244287,-0.0878069028258324,0.1015449836850166,-0.0380791351199150,0.2184979170560837)
>* MODEL21_texOff(vec2(1,0));\n"
>+"res +=
>mat4(-0.0286560114473104,0.2136799246072769,-0.2311843186616898,0.0386331938207150,0.1171527504920959,0.1365598738193512,-0.1323762089014053,0.0242694225162268,0.0034821233712137,-0.0896023139357567,-0.0015278273494914,0.3900723457336426,0.0000983321660897,0.0944209173321724,-0.2164677530527115,0.0006809064652771)
>* MODEL22_texOff(vec2(1,0));\n"
>+"res +=
>mat4(0.0850212126970291,0.1542103290557861,-0.0473816059529781,0.0190168116241693,-0.1149476245045662,0.0453822985291481,-0.0028189518488944,-0.0764079689979553,0.1659836173057556,-0.1582878530025482,0.0611256584525108,0.0184390936046839,0.0180864483118057,-0.0088572278618813,-0.0146331088617444,0.0108325071632862)
>* MODEL21_texOff(vec2(1,1));\n"
>+"res +=
>mat4(-0.0319982506334782,0.1878758668899536,-0.0888885408639908,0.0096141481772065,0.0741596445441246,-0.1635657399892807,0.0493983142077923,-0.0128457061946392,0.0059395609423518,-0.1977029144763947,0.0657528415322304,0.1754793822765350,-0.1338032037019730,0.0237457044422626,0.0079643372446299,-0.0344907231628895)
>* MODEL22_texOff(vec2(1,1));\n"
>+"res = max(res, vec4(0.0)) +
>vec4(0.6511312127113342,0.1671129912137985,-0.0597441010177135,0.2055131942033768)
>* min(res, vec4(0.0));\n"
>+"return res;\n"
>+"}\n"
>+"\n"
>+"//!HOOK LUMA\n"
>+"//!WHEN OUTPUT.w LUMA.w / 1.400 > OUTPUT.h LUMA.h / 1.400 > *\n"
>+"//!DESC sub-band residuals 1\n"
>+"//!BIND MODEL1\n"
>+"//!BIND MODEL2\n"
>+"//!BIND FEATURE1\n"
>+"//!SAVE RES1\n"
>+"//!COMPONENTS 4\n"
>+"vec4 hook()\n"
>+"{\n"
>+"vec4 res =
>vec4(0.0283374618738890,-0.4720447361469269,0.0240570977330208,-0.0129809509962797);\n"
>+"res +=
>mat4(0.0371446721255779,-0.8995716571807861,-0.1120004579424858,-0.0627587214112282,0.2845768630504608,-0.0245083887130022,0.0065307612530887,-0.4454597830772400,0.0765401497483253,-0.2782167494297028,0.0263278763741255,-0.0536362379789352,-0.0615853369235992,-0.8115552663803101,0.0781464055180550,0.1291559040546417)
>* MODEL1_texOff(0);\n"
>+"res +=
>mat4(-0.0658674836158752,0.1201973780989647,-0.0006808685720898,0.1277942359447479,-0.0087147429585457,-0.1862100809812546,0.0072127245366573,0.0080450763925910,0.0551731735467911,-0.0700771659612656,0.1366149485111237,-0.0962043032050133,0.0518531203269958,0.0945324152708054,-0.0430086590349674,-0.0778950005769730)
>* MODEL2_texOff(0);\n"
>+"res += FEATURE1_texOff(0);\n"
>+"res = max(res, vec4(0.0)) +
>vec4(0.9849414229393005,0.0568453334271908,1.3530071973800659,1.0141726732254028)
>* min(res, vec4(0.0));\n"
>+"return res;\n"
>+"}\n"
>+"\n"
>+"//!HOOK LUMA\n"
>+"//!WHEN OUTPUT.w LUMA.w / 1.400 > OUTPUT.h LUMA.h / 1.400 > *\n"
>+"//!DESC sub-band residuals 2\n"
>+"//!BIND MODEL1\n"
>+"//!BIND MODEL2\n"
>+"//!BIND FEATURE2\n"
>+"//!SAVE RES2\n"
>+"//!COMPONENTS 4\n"
>+"vec4 hook()\n"
>+"{\n"
>+"vec4 res =
>vec4(-0.0436431728303432,-0.3684050440788269,-0.0273779705166817,-0.2828843593597412);\n"
>+"res +=
>mat4(0.0204514227807522,0.0304707400500774,-0.0052444878965616,0.1301165074110031,-0.1016156971454620,-0.4090886116027832,-0.2494817376136780,-0.2019464373588562,-0.0573944784700871,-0.1311245411634445,-0.0209540519863367,-0.1862112134695053,0.0028269081376493,-0.1761312633752823,-0.0276452936232090,-0.4574446380138397)
>* MODEL1_texOff(0);\n"
>+"res +=
>mat4(0.5362485647201538,0.0928969532251358,0.0283183977007866,0.0715762674808502,-0.0409743636846542,-0.6784394383430481,0.1981076449155807,-0.1035051122307777,-0.1994037181138992,-0.2863960266113281,-0.0452203117311001,-0.3109507262706757,-0.0268154032528400,-0.2877916097640991,0.3216417431831360,0.1942034363746643)
>* MODEL2_texOff(0);\n"
>+"res += FEATURE2_texOff(0);\n"
>+"res = max(res, vec4(0.0)) +
>vec4(0.1193217113614082,0.1106821373105049,0.6098618507385254,0.1243358179926872)
>* min(res, vec4(0.0));\n"
>+"return res;\n"
>+"}\n"
>+"\n"
>+"//!HOOK LUMA\n"
>+"//!WHEN OUTPUT.w LUMA.w / 1.400 > OUTPUT.h LUMA.h / 1.400 > *\n"
>+"//!DESC sub-pixel convolution 1\n"
>+"//!BIND RES1\n"
>+"//!BIND RES2\n"
>+"//!SAVE SUBCONV1\n"
>+"//!COMPONENTS 4\n"
>+"vec4 hook()\n"
>+"{\n"
>+"vec4 res =
>vec4(0.2010960131883621,0.2046597152948380,0.1881453990936279,0.1910871863365173);\n"
>+"res +=
>mat4x4(0.0011392289306968,-0.0093875946477056,-0.0148976910859346,-0.0036854455247521,0.0310414507985115,-0.0606263689696789,0.0127487797290087,0.0125642297789454,-0.0126910861581564,0.0004570177698042,0.0011062944540754,-0.0008521208656020,-0.0062735751271248,0.0107357343658805,0.0214790534228086,-0.0055235433392227)
>* RES1_texOff(vec2(-1,-1));\n"
>+"res +=
>mat4x4(-0.0214522331953049,0.0330132097005844,-0.0020214118994772,-0.0035901805385947,-0.0746964216232300,-0.0740821212530136,0.0056589865125716,-0.0772731676697731,0.0058290148153901,-0.0101303644478321,-0.0050438679754734,-0.0113526238128543,0.0830746516585350,0.0195941086858511,0.0153881441801786,-0.0237823426723480)
>* RES2_texOff(vec2(-1,-1));\n"
>+"res +=
>mat4x4(0.0152261219918728,0.0380328707396984,-0.0380241684615612,-0.0458207316696644,-0.0740007609128952,0.1113854795694351,-0.0054381615482271,-0.0118448669090867,-0.0294291805475950,0.0192470233887434,0.0224124677479267,-0.0103392861783504,-0.0091485409066081,-0.0309248529374599,0.0247288998216391,0.0517477244138718)
>* RES1_texOff(vec2(-1,0));\n"
>+"res +=
>mat4x4(0.0322216600179672,-0.0166396461427212,-0.0036350577138364,-0.0022594137117267,0.2693043053150177,0.2119481414556503,-0.5539517998695374,-0.2300848662853241,0.0046360963024199,0.0296224430203438,0.0274428315460682,0.0310378503054380,-0.1802419871091843,-0.1212233603000641,0.3254813551902771,0.1910651922225952)
>* RES2_texOff(vec2(-1,0));\n"
>+"res +=
>mat4x4(-0.0019635250791907,-0.0140673695132136,0.0027435051742941,-0.0002343246305827,0.0973082929849625,0.0291955452412367,0.0038000363856554,0.0472679212689400,-0.0076229665428400,0.0004003540379927,-0.0176377985626459,-0.0045110885985196,0.0026144199073315,0.0077777574770153,-0.0025362374726683,-0.0017223907634616)
>* RES1_texOff(vec2(-1,1));\n"
>+"res +=
>mat4x4(-0.0034773261286318,-0.0028598513454199,0.0010725271422416,0.0041992128826678,-0.1363923549652100,-0.0440688580274582,0.0808961465954781,-0.1321281194686890,-0.0028827539645135,-0.0036714002490044,-0.0035673903767020,0.0058416510000825,-0.0040158745832741,-0.0093965586274862,-0.0614721104502678,0.0040285577997565)
>* RES2_texOff(vec2(-1,1));\n"
>+"res +=
>mat4x4(-0.0088650919497013,0.0056629320606589,0.0264434609562159,-0.0041949660517275,-0.1044224500656128,-0.0465686991810799,0.0125883137807250,-0.0627587810158730,0.0218276027590036,-0.0218472853302956,-0.0049347621388733,-0.0232141949236393,0.0145897399634123,-0.0071130394935608,-0.0280623119324446,0.0204915180802345)
>* RES1_texOff(vec2(0,-1));\n"
>+"res +=
>mat4x4(-0.0538064986467361,0.0953739657998085,-0.0629424825310707,0.1158977001905441,0.1457169502973557,-0.0534004867076874,-0.0197371542453766,-0.0564802139997482,0.0450520217418671,-0.0303168613463640,-0.0138612175360322,0.0096343606710434,-0.1288891285657883,0.1899452060461044,0.0407251492142677,0.1303639262914658)
>* RES2_texOff(vec2(0,-1));\n"
>+"res +=
>mat4x4(0.6295898556709290,0.6015956401824951,0.5520075559616089,0.6055720448493958,-0.0045572095550597,0.1066368892788887,0.0315655320882797,0.3029754161834717,-0.3411723375320435,0.2853312790393829,-0.3344538211822510,0.2379437237977982,0.3485223650932312,0.3735182881355286,0.4117222428321838,0.3292364478111267)
>* RES1_texOff(vec2(0,0));\n"
>+"res +=
>mat4x4(0.0853470191359520,-0.1003382802009583,0.0866407155990601,-0.0864839553833008,0.0078956158831716,0.1524136662483215,0.0963815525174141,-0.2157683223485947,0.3842815756797791,0.3783615827560425,-0.3822300136089325,-0.3113161325454712,-0.3944143652915955,0.0037262889090925,-0.2098172903060913,0.3972991406917572)
>* RES2_texOff(vec2(0,0));\n"
>+"res +=
>mat4x4(-0.0198873616755009,0.0332897379994392,-0.0053030312992632,0.0059300977736712,0.4766073226928711,-0.2927798628807068,0.4145008027553558,-0.3058874309062958,0.0379787385463715,0.0197043158113956,0.0317554250359535,0.0262230820953846,0.0155623536556959,-0.0241930708289146,0.0015698857605457,0.0057815625332296)
>* RES1_texOff(vec2(0,1));\n"
>+"res +=
>mat4x4(-0.0317478515207767,0.0071203173138201,-0.0278743151575327,-0.0087346015498042,0.0300409756600857,-0.0009421137510799,-0.0694695711135864,0.2193532437086105,-0.0204254351556301,0.0709510073065758,0.0259671546518803,-0.0633780285716057,-0.3146271407604218,0.2372228205204010,-0.2508744001388550,0.2007979154586792)
>* RES2_texOff(vec2(0,1));\n"
>+"res +=
>mat4x4(0.0091309268027544,-0.0075138043612242,-0.0105690350756049,0.0015618086326867,0.0353675633668900,0.0147913852706552,-0.0222861394286156,-0.0231287963688374,-0.0041733644902706,0.0091610904783010,-0.0068060490302742,0.0074884011410177,-0.0105087012052536,0.0049646743573248,0.0059704952873290,-0.0073151844553649)
>* RES1_texOff(vec2(1,-1));\n"
>+"res +=
>mat4x4(0.0129704503342509,-0.0097298845648766,0.0126019529998302,0.0191528033465147,-0.0261679086834192,-0.0361513234674931,0.0167022943496704,-0.0521022230386734,-0.0067621842026711,0.0014493890339509,-0.0183391850441694,0.0022007490042597,0.0243291929364204,-0.0054394556209445,-0.0311558730900288,0.0641983225941658)
>* RES2_texOff(vec2(1,-1));\n"
>+"res +=
>mat4x4(0.0058755860663950,0.0231478270143270,0.0122163994237781,-0.0110751204192638,0.0287106744945049,0.0674569755792618,-0.0534705370664597,0.0728216767311096,0.0289570018649101,-0.0274134390056133,-0.0432904921472073,0.0321006551384926,-0.0029451604932547,-0.0224813763052225,-0.0072797401808202,0.0250357724726200)
>* RES1_texOff(vec2(1,0));\n"
>+"res +=
>mat4x4(-0.0160836856812239,0.0140370950102806,0.0083269150927663,-0.0176006872206926,0.1073665097355843,0.0961451977491379,-0.0665594264864922,0.0016301712021232,-0.0624651126563549,-0.0405720882117748,0.0156172541901469,-0.0068073389120400,-0.0190098043531179,-0.0738979279994965,0.0897897481918335,-0.0441876165568829)
>* RES2_texOff(vec2(1,0));\n"
>+"res +=
>mat4x4(0.0011073705973104,-0.0045707798562944,-0.0093563208356500,0.0014767179964110,-0.0280344896018505,0.0624363385140896,0.1537481248378754,0.0794916898012161,-0.0070973481051624,0.0027710921131074,-0.0011720197508112,-0.0107303149998188,-0.0028812016826123,0.0075960354879498,0.0102778393775225,-0.0087832165881991)
>* RES1_texOff(vec2(1,1));\n"
>+"res +=
>mat4x4(0.0007737030973658,-0.0068514398299158,-0.0028199783992022,0.0058472012169659,0.0018526014173403,0.0282068904489279,-0.0360841602087021,-0.0585683882236481,0.0174624379724264,-0.0120120961219072,-0.0130728278309107,-0.0085735730826855,0.0023475231137127,-0.0551190264523029,-0.1038432866334915,-0.0127087393775582)
>* RES2_texOff(vec2(1,1));\n"
>+"return res;\n"
>+"}\n"
>+"\n"
>+"//!HOOK LUMA\n"
>+"//!WHEN OUTPUT.w LUMA.w / 1.400 > OUTPUT.h LUMA.h / 1.400 > *\n"
>+"//!WIDTH LUMA.w 2 *\n"
>+"//!HEIGHT LUMA.h 2 *\n"
>+"//!DESC aggregation\n"
>+"//!BIND SUBCONV1\n"
>+"vec4 hook()\n"
>+"{\n"
>+"vec2 fcoord = fract(SUBCONV1_pos * SUBCONV1_size);\n"
>+"vec2 base = SUBCONV1_pos + (vec2(0.5) - fcoord) * SUBCONV1_pt;\n"
>+"ivec2 index = ivec2(fcoord * vec2(2));\n"
>+"vec4 res = SUBCONV1_tex(base);\n"
>+"return vec4(res[index.x * 2 + index.y], 0, 0, 1);\n"
>+"}\n"
>+"";
>+
>+const size_t fsrcnnx_8_0_4_1_len = sizeof(fsrcnnx_8_0_4_1) - 1;
>diff --git a/modules/video_output/vulkan/shaders/krig_bilateral.c
>b/modules/video_output/vulkan/shaders/krig_bilateral.c
>new file mode 100644
>index 0000000000..f6075d5122
>--- /dev/null
>+++ b/modules/video_output/vulkan/shaders/krig_bilateral.c
>@@ -0,0 +1,234 @@
>+/*****************************************************************************
>+ * KrigBilateral by Shiandow, adapted for mpv by igv
>+
>*****************************************************************************
>+ * Copyright (C) 2016 Shiandow
>+ * Copyright (C) 2020 igv
>+ *
>+ * This library is free software; you can redistribute it and/or
>modify it
>+ * under the terms of the GNU Lesser General Public License as
>published by the
>+ * Free Software Foundation; either version 3.0 of the License, or (at
>your
>+ * option) any later version.
>+ *
>+ * This library is distributed in the hope that it will be useful, but
>WITHOUT
>+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
>or
>+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General
>Public License
>+ * for more details.
>+ *
>+ * You should have received a copy of the GNU Lesser General Public
>License
>+ * along with this library.
>+
>*****************************************************************************/
>+
>+#include <stddef.h>
>+#include "shaders.h"
>+
>+const char krig_bilateral[] =
>+"//!HOOK CHROMA\n"
>+"//!BIND HOOKED\n"
>+"//!BIND LUMA\n"
>+"//!SAVE LOWRES_Y\n"
>+"//!WIDTH LUMA.w\n"
>+"//!WHEN CHROMA.w LUMA.w <\n"
>+"//!DESC KrigBilateral Downscaling Y pass 1\n"
>+"\n"
>+"#define offset vec2(0,0)\n"
>+"\n"
>+"#define axis 1\n"
>+"\n"
>+"#define Kernel(x) dot(vec3(0.42659, -0.49656, 0.076849),
>cos(vec3(0, 1, 2) * acos(-1.) * (x + 1.)))\n"
>+"\n"
>+"vec4 hook() {\n"
>+" // Calculate bounds\n"
>+" float low = ceil((LUMA_pos - CHROMA_pt) * LUMA_size - offset -
>0.5)[axis];\n"
>+" float high = floor((LUMA_pos + CHROMA_pt) * LUMA_size - offset -
>0.5)[axis];\n"
>+"\n"
>+" float W = 0.0;\n"
>+" vec4 avg = vec4(0);\n"
>+" vec2 pos = LUMA_pos;\n"
>+"\n"
>+" for (float k = low; k <= high; k++) {\n"
>+" pos[axis] = LUMA_pt[axis] * (k - offset[axis] + 0.5);\n"
>+" float rel = (pos[axis] -
>LUMA_pos[axis])*CHROMA_size[axis];\n"
>+" float w = Kernel(rel);\n"
>+"\n"
>+" vec4 y = textureGrad(LUMA_raw, pos, vec2(0.0),
>vec2(0.0)).xxxx * LUMA_mul;\n"
>+" y.y *= y.y;\n"
>+" avg += w * y;\n"
>+" W += w;\n"
>+" }\n"
>+" avg /= W;\n"
>+" avg.y = abs(avg.y - pow(avg.x, 2.0));\n"
>+" return avg;\n"
>+"}\n"
>+"\n"
>+"//!HOOK CHROMA\n"
>+"//!BIND HOOKED\n"
>+"//!BIND LOWRES_Y\n"
>+"//!SAVE LOWRES_Y\n"
>+"//!WHEN CHROMA.w LUMA.w <\n"
>+"//!DESC KrigBilateral Downscaling Y pass 2\n"
>+"\n"
>+"#define offset vec2(0,0)\n"
>+"\n"
>+"#define axis 0\n"
>+"\n"
>+"#define Kernel(x) dot(vec3(0.42659, -0.49656, 0.076849),
>cos(vec3(0, 1, 2) * acos(-1.) * (x + 1.)))\n"
>+"\n"
>+"vec4 hook() {\n"
>+" // Calculate bounds\n"
>+" float low = ceil((LOWRES_Y_pos - CHROMA_pt) * LOWRES_Y_size -
>offset - 0.5)[axis];\n"
>+" float high = floor((LOWRES_Y_pos + CHROMA_pt) * LOWRES_Y_size -
>offset - 0.5)[axis];\n"
>+"\n"
>+" float W = 0.0;\n"
>+" vec4 avg = vec4(0);\n"
>+" vec2 pos = LOWRES_Y_pos;\n"
>+"\n"
>+" for (float k = low; k <= high; k++) {\n"
>+" pos[axis] = LOWRES_Y_pt[axis] * (k - offset[axis] + 0.5);\n"
>+" float rel = (pos[axis] -
>LOWRES_Y_pos[axis])*CHROMA_size[axis];\n"
>+" float w = Kernel(rel);\n"
>+"\n"
>+" vec4 y = textureGrad(LOWRES_Y_raw, pos, vec2(0.0),
>vec2(0.0)).xxxx * LOWRES_Y_mul;\n"
>+" y.y *= y.y;\n"
>+" avg += w * y;\n"
>+" W += w;\n"
>+" }\n"
>+" avg /= W;\n"
>+" avg.y = abs(avg.y - pow(avg.x, 2.0)) + LOWRES_Y_texOff(0).y;\n"
>+" return avg;\n"
>+"}\n"
>+"\n"
>+"//!HOOK CHROMA\n"
>+"//!BIND HOOKED\n"
>+"//!BIND LUMA\n"
>+"//!BIND LOWRES_Y\n"
>+"//!WIDTH LUMA.w\n"
>+"//!HEIGHT LUMA.h\n"
>+"//!WHEN CHROMA.w LUMA.w <\n"
>+"//!OFFSET ALIGN\n"
>+"//!DESC KrigBilateral Upscaling UV\n"
>+"\n"
>+"// -- Convenience --\n"
>+"#define sqr(x) dot(x,x)\n"
>+"#define bitnoise 1.0/(2.0*255.0)\n"
>+"#define noise 0.05//5.0*bitnoise\n"
>+"#define chromaOffset vec2(0.0, 0.0)\n"
>+"\n"
>+"// -- Window Size --\n"
>+"#define taps 3\n"
>+"#define even (float(taps) - 2.0 * floor(float(taps) / 2.0) == 0.0)\n"
>+"#define minX int(1.0-ceil(float(taps)/2.0))\n"
>+"#define maxX int(floor(float(taps)/2.0))\n"
>+"\n"
>+"#define Kernel(x) (cos(acos(-1.0)*(x)/float(taps))) // Hann kernel\n"
>+"\n"
>+"// -- Input processing --\n"
>+"#define GetY(coord)
>LOWRES_Y_tex(LOWRES_Y_pt*(pos+coord+vec2(0.5))).xy\n"
>+"#define GetUV(coord)
>CHROMA_tex(CHROMA_pt*(pos+coord+vec2(0.5))).xy\n"
>+"\n"
>+"#define N (taps*taps - 1)\n"
>+"\n"
>+"#define M(i,j) Mx[min(i,j)*N + max(i,j) - min(i,j)*(min(i,j)+1)/2]\n"
>+"\n"
>+"#define C(i,j) (inversesqrt(1.0 + (X[i].y + X[j].y)/localVar) *
>exp(-0.5*(sqr(X[i].x - X[j].x)/(localVar + X[i].y + X[j].y) +
>sqr((coords[i] - coords[j])/radius))) + (X[i].x - y) * (X[j].x - y) /
>localVar)\n"
>+"#define c(i) (inversesqrt(1.0 + X[i].y/localVar) *
>exp(-0.5*(sqr(X[i].x - y)/(localVar + X[i].y) + sqr((coords[i] -
>offset)/radius))))\n"
>+"\n"
>+"vec4 hook() {\n"
>+" vec2 pos = CHROMA_pos * HOOKED_size - chromaOffset -
>vec2(0.5);\n"
>+" vec2 offset = pos - (even ? floor(pos) : round(pos));\n"
>+" pos -= offset;\n"
>+"\n"
>+" vec2 coords[N+1];\n"
>+" vec4 X[N+1];\n"
>+" float y = LUMA_texOff(0).x;\n"
>+" vec4 total = vec4(0);\n"
>+"\n"
>+" coords[0] = vec2(-1,-1); coords[1] = vec2(-1, 0); coords[2] =
>vec2(-1, 1);\n"
>+" coords[3] = vec2( 0,-1); coords[4] = vec2( 0, 1); coords[5] =
>vec2( 1,-1);\n"
>+" coords[6] = vec2( 1, 0); coords[7] = vec2( 1, 1); coords[8] =
>vec2( 0, 0);\n"
>+"\n"
>+" for (int i=0; i<N+1; i++) {\n"
>+" X[i] = vec4(GetY(coords[i]), GetUV(coords[i]));\n"
>+" vec2 w = clamp(1.5 - abs(coords[i] - offset), 0.0, 1.0);\n"
>+" total += w.x*w.y*vec4(X[i].x, pow(X[i].x, 2.0), X[i].y,
>1.0);\n"
>+" }\n"
>+" total.xyz /= total.w;\n"
>+" float localVar = sqr(noise) + abs(total.y - pow(total.x, 2.0)) +
>total.z;\n"
>+" float radius = 1.0;\n"
>+"\n"
>+" float Mx[N*(N+1)/2];\n"
>+" float b[N];\n"
>+" vec4 interp = X[N];\n"
>+"\n"
>+" b[0] = c(0) - c(N) - C(0,N) + C(N,N); M(0, 0) = C(0,0) - C(0,N) -
>C(0,N) + C(N,N); M(0, 1) = C(0,1) - C(1,N) - C(0,N) + C(N,N); M(0, 2) =
>C(0,2) - C(2,N) - C(0,N) + C(N,N); M(0, 3) = C(0,3) - C(3,N) - C(0,N) +
>C(N,N); M(0, 4) = C(0,4) - C(4,N) - C(0,N) + C(N,N); M(0, 5) = C(0,5) -
>C(5,N) - C(0,N) + C(N,N); M(0, 6) = C(0,6) - C(6,N) - C(0,N) + C(N,N);
>M(0, 7) = C(0,7) - C(7,N) - C(0,N) + C(N,N);\n"
>+" b[1] = c(1) - c(N) - C(1,N) + C(N,N); M(1, 1) = C(1,1) - C(1,N) -
>C(1,N) + C(N,N); M(1, 2) = C(1,2) - C(2,N) - C(1,N) + C(N,N); M(1, 3) =
>C(1,3) - C(3,N) - C(1,N) + C(N,N); M(1, 4) = C(1,4) - C(4,N) - C(1,N) +
>C(N,N); M(1, 5) = C(1,5) - C(5,N) - C(1,N) + C(N,N); M(1, 6) = C(1,6) -
>C(6,N) - C(1,N) + C(N,N); M(1, 7) = C(1,7) - C(7,N) - C(1,N) +
>C(N,N);\n"
>+" b[2] = c(2) - c(N) - C(2,N) + C(N,N); M(2, 2) = C(2,2) - C(2,N) -
>C(2,N) + C(N,N); M(2, 3) = C(2,3) - C(3,N) - C(2,N) + C(N,N); M(2, 4) =
>C(2,4) - C(4,N) - C(2,N) + C(N,N); M(2, 5) = C(2,5) - C(5,N) - C(2,N) +
>C(N,N); M(2, 6) = C(2,6) - C(6,N) - C(2,N) + C(N,N); M(2, 7) = C(2,7) -
>C(7,N) - C(2,N) + C(N,N);\n"
>+" b[3] = c(3) - c(N) - C(3,N) + C(N,N); M(3, 3) = C(3,3) - C(3,N) -
>C(3,N) + C(N,N); M(3, 4) = C(3,4) - C(4,N) - C(3,N) + C(N,N); M(3, 5) =
>C(3,5) - C(5,N) - C(3,N) + C(N,N); M(3, 6) = C(3,6) - C(6,N) - C(3,N) +
>C(N,N); M(3, 7) = C(3,7) - C(7,N) - C(3,N) + C(N,N);\n"
>+" b[4] = c(4) - c(N) - C(4,N) + C(N,N); M(4, 4) = C(4,4) - C(4,N) -
>C(4,N) + C(N,N); M(4, 5) = C(4,5) - C(5,N) - C(4,N) + C(N,N); M(4, 6) =
>C(4,6) - C(6,N) - C(4,N) + C(N,N); M(4, 7) = C(4,7) - C(7,N) - C(4,N) +
>C(N,N);\n"
>+" b[5] = c(5) - c(N) - C(5,N) + C(N,N); M(5, 5) = C(5,5) - C(5,N) -
>C(5,N) + C(N,N); M(5, 6) = C(5,6) - C(6,N) - C(5,N) + C(N,N); M(5, 7) =
>C(5,7) - C(7,N) - C(5,N) + C(N,N);\n"
>+" b[6] = c(6) - c(N) - C(6,N) + C(N,N); M(6, 6) = C(6,6) - C(6,N) -
>C(6,N) + C(N,N); M(6, 7) = C(6,7) - C(7,N) - C(6,N) + C(N,N);\n"
>+" b[7] = c(7) - c(N) - C(7,N) + C(N,N); M(7, 7) = C(7,7) - C(7,N) -
>C(7,N) + C(N,N);\n"
>+"\n"
>+" b[1] -= b[0] * M(1, 0) / M(0, 0); M(1, 1) -= M(0, 1) * M(1, 0) /
>M(0, 0); M(1, 2) -= M(0, 2) * M(1, 0) / M(0, 0); M(1, 3) -= M(0, 3) *
>M(1, 0) / M(0, 0); M(1, 4) -= M(0, 4) * M(1, 0) / M(0, 0); M(1, 5) -=
>M(0, 5) * M(1, 0) / M(0, 0); M(1, 6) -= M(0, 6) * M(1, 0) / M(0, 0);
>M(1, 7) -= M(0, 7) * M(1, 0) / M(0, 0);\n"
>+" b[2] -= b[0] * M(2, 0) / M(0, 0); M(2, 2) -= M(0, 2) * M(2, 0) /
>M(0, 0); M(2, 3) -= M(0, 3) * M(2, 0) / M(0, 0); M(2, 4) -= M(0, 4) *
>M(2, 0) / M(0, 0); M(2, 5) -= M(0, 5) * M(2, 0) / M(0, 0); M(2, 6) -=
>M(0, 6) * M(2, 0) / M(0, 0); M(2, 7) -= M(0, 7) * M(2, 0) / M(0, 0);\n"
>+" b[3] -= b[0] * M(3, 0) / M(0, 0); M(3, 3) -= M(0, 3) * M(3, 0) /
>M(0, 0); M(3, 4) -= M(0, 4) * M(3, 0) / M(0, 0); M(3, 5) -= M(0, 5) *
>M(3, 0) / M(0, 0); M(3, 6) -= M(0, 6) * M(3, 0) / M(0, 0); M(3, 7) -=
>M(0, 7) * M(3, 0) / M(0, 0);\n"
>+" b[4] -= b[0] * M(4, 0) / M(0, 0); M(4, 4) -= M(0, 4) * M(4, 0) /
>M(0, 0); M(4, 5) -= M(0, 5) * M(4, 0) / M(0, 0); M(4, 6) -= M(0, 6) *
>M(4, 0) / M(0, 0); M(4, 7) -= M(0, 7) * M(4, 0) / M(0, 0);\n"
>+" b[5] -= b[0] * M(5, 0) / M(0, 0); M(5, 5) -= M(0, 5) * M(5, 0) /
>M(0, 0); M(5, 6) -= M(0, 6) * M(5, 0) / M(0, 0); M(5, 7) -= M(0, 7) *
>M(5, 0) / M(0, 0);\n"
>+" b[6] -= b[0] * M(6, 0) / M(0, 0); M(6, 6) -= M(0, 6) * M(6, 0) /
>M(0, 0); M(6, 7) -= M(0, 7) * M(6, 0) / M(0, 0);\n"
>+" b[7] -= b[0] * M(7, 0) / M(0, 0); M(7, 7) -= M(0, 7) * M(7, 0) /
>M(0, 0);\n"
>+"\n"
>+" b[2] -= b[1] * M(2, 1) / M(1, 1); M(2, 2) -= M(1, 2) * M(2, 1) /
>M(1, 1); M(2, 3) -= M(1, 3) * M(2, 1) / M(1, 1); M(2, 4) -= M(1, 4) *
>M(2, 1) / M(1, 1); M(2, 5) -= M(1, 5) * M(2, 1) / M(1, 1); M(2, 6) -=
>M(1, 6) * M(2, 1) / M(1, 1); M(2, 7) -= M(1, 7) * M(2, 1) / M(1, 1);\n"
>+" b[3] -= b[1] * M(3, 1) / M(1, 1); M(3, 3) -= M(1, 3) * M(3, 1) /
>M(1, 1); M(3, 4) -= M(1, 4) * M(3, 1) / M(1, 1); M(3, 5) -= M(1, 5) *
>M(3, 1) / M(1, 1); M(3, 6) -= M(1, 6) * M(3, 1) / M(1, 1); M(3, 7) -=
>M(1, 7) * M(3, 1) / M(1, 1);\n"
>+" b[4] -= b[1] * M(4, 1) / M(1, 1); M(4, 4) -= M(1, 4) * M(4, 1) /
>M(1, 1); M(4, 5) -= M(1, 5) * M(4, 1) / M(1, 1); M(4, 6) -= M(1, 6) *
>M(4, 1) / M(1, 1); M(4, 7) -= M(1, 7) * M(4, 1) / M(1, 1);\n"
>+" b[5] -= b[1] * M(5, 1) / M(1, 1); M(5, 5) -= M(1, 5) * M(5, 1) /
>M(1, 1); M(5, 6) -= M(1, 6) * M(5, 1) / M(1, 1); M(5, 7) -= M(1, 7) *
>M(5, 1) / M(1, 1);\n"
>+" b[6] -= b[1] * M(6, 1) / M(1, 1); M(6, 6) -= M(1, 6) * M(6, 1) /
>M(1, 1); M(6, 7) -= M(1, 7) * M(6, 1) / M(1, 1);\n"
>+" b[7] -= b[1] * M(7, 1) / M(1, 1); M(7, 7) -= M(1, 7) * M(7, 1) /
>M(1, 1);\n"
>+"\n"
>+" b[3] -= b[2] * M(3, 2) / M(2, 2); M(3, 3) -= M(2, 3) * M(3, 2) /
>M(2, 2); M(3, 4) -= M(2, 4) * M(3, 2) / M(2, 2); M(3, 5) -= M(2, 5) *
>M(3, 2) / M(2, 2); M(3, 6) -= M(2, 6) * M(3, 2) / M(2, 2); M(3, 7) -=
>M(2, 7) * M(3, 2) / M(2, 2);\n"
>+" b[4] -= b[2] * M(4, 2) / M(2, 2); M(4, 4) -= M(2, 4) * M(4, 2) /
>M(2, 2); M(4, 5) -= M(2, 5) * M(4, 2) / M(2, 2); M(4, 6) -= M(2, 6) *
>M(4, 2) / M(2, 2); M(4, 7) -= M(2, 7) * M(4, 2) / M(2, 2);\n"
>+" b[5] -= b[2] * M(5, 2) / M(2, 2); M(5, 5) -= M(2, 5) * M(5, 2) /
>M(2, 2); M(5, 6) -= M(2, 6) * M(5, 2) / M(2, 2); M(5, 7) -= M(2, 7) *
>M(5, 2) / M(2, 2);\n"
>+" b[6] -= b[2] * M(6, 2) / M(2, 2); M(6, 6) -= M(2, 6) * M(6, 2) /
>M(2, 2); M(6, 7) -= M(2, 7) * M(6, 2) / M(2, 2);\n"
>+" b[7] -= b[2] * M(7, 2) / M(2, 2); M(7, 7) -= M(2, 7) * M(7, 2) /
>M(2, 2);\n"
>+"\n"
>+" b[4] -= b[3] * M(4, 3) / M(3, 3); M(4, 4) -= M(3, 4) * M(4, 3) /
>M(3, 3); M(4, 5) -= M(3, 5) * M(4, 3) / M(3, 3); M(4, 6) -= M(3, 6) *
>M(4, 3) / M(3, 3); M(4, 7) -= M(3, 7) * M(4, 3) / M(3, 3);\n"
>+" b[5] -= b[3] * M(5, 3) / M(3, 3); M(5, 5) -= M(3, 5) * M(5, 3) /
>M(3, 3); M(5, 6) -= M(3, 6) * M(5, 3) / M(3, 3); M(5, 7) -= M(3, 7) *
>M(5, 3) / M(3, 3);\n"
>+" b[6] -= b[3] * M(6, 3) / M(3, 3); M(6, 6) -= M(3, 6) * M(6, 3) /
>M(3, 3); M(6, 7) -= M(3, 7) * M(6, 3) / M(3, 3);\n"
>+" b[7] -= b[3] * M(7, 3) / M(3, 3); M(7, 7) -= M(3, 7) * M(7, 3) /
>M(3, 3);\n"
>+"\n"
>+" b[5] -= b[4] * M(5, 4) / M(4, 4); M(5, 5) -= M(4, 5) * M(5, 4) /
>M(4, 4); M(5, 6) -= M(4, 6) * M(5, 4) / M(4, 4); M(5, 7) -= M(4, 7) *
>M(5, 4) / M(4, 4);\n"
>+" b[6] -= b[4] * M(6, 4) / M(4, 4); M(6, 6) -= M(4, 6) * M(6, 4) /
>M(4, 4); M(6, 7) -= M(4, 7) * M(6, 4) / M(4, 4);\n"
>+" b[7] -= b[4] * M(7, 4) / M(4, 4); M(7, 7) -= M(4, 7) * M(7, 4) /
>M(4, 4);\n"
>+"\n"
>+" b[6] -= b[5] * M(6, 5) / M(5, 5); M(6, 6) -= M(5, 6) * M(6, 5) /
>M(5, 5); M(6, 7) -= M(5, 7) * M(6, 5) / M(5, 5);\n"
>+" b[7] -= b[5] * M(7, 5) / M(5, 5); M(7, 7) -= M(5, 7) * M(7, 5) /
>M(5, 5);\n"
>+"\n"
>+" b[7] -= b[6] * M(7, 6) / M(6, 6); M(7, 7) -= M(6, 7) * M(7, 6) /
>M(6, 6);\n"
>+"\n"
>+" b[N-1-0] /= M(N-1-0, N-1-0);\n"
>+" interp += b[N-1-0] * (X[N-1-0] - X[N]);\n"
>+"\n"
>+" b[N-1-1] -= M(N-1-1, 7) * b[7]; b[N-1-1] /= M(N-1-1, N-1-1);\n"
>+" interp += b[N-1-1] * (X[N-1-1] - X[N]);\n"
>+"\n"
>+" b[N-1-2] -= M(N-1-2, 6) * b[6]; b[N-1-2] -= M(N-1-2, 7) * b[7];
>b[N-1-2] /= M(N-1-2, N-1-2);\n"
>+" interp += b[N-1-2] * (X[N-1-2] - X[N]);\n"
>+"\n"
>+" b[N-1-3] -= M(N-1-3, 5) * b[5]; b[N-1-3] -= M(N-1-3, 6) * b[6];
>b[N-1-3] -= M(N-1-3, 7) * b[7]; b[N-1-3] /= M(N-1-3, N-1-3);\n"
>+" interp += b[N-1-3] * (X[N-1-3] - X[N]);\n"
>+"\n"
>+" b[N-1-4] -= M(N-1-4, 4) * b[4]; b[N-1-4] -= M(N-1-4, 5) * b[5];
>b[N-1-4] -= M(N-1-4, 6) * b[6]; b[N-1-4] -= M(N-1-4, 7) * b[7];
>b[N-1-4] /= M(N-1-4, N-1-4);\n"
>+" interp += b[N-1-4] * (X[N-1-4] - X[N]);\n"
>+"\n"
>+" b[N-1-5] -= M(N-1-5, 3) * b[3]; b[N-1-5] -= M(N-1-5, 4) * b[4];
>b[N-1-5] -= M(N-1-5, 5) * b[5]; b[N-1-5] -= M(N-1-5, 6) * b[6];
>b[N-1-5] -= M(N-1-5, 7) * b[7]; b[N-1-5] /= M(N-1-5, N-1-5);\n"
>+" interp += b[N-1-5] * (X[N-1-5] - X[N]);\n"
>+"\n"
>+" b[N-1-6] -= M(N-1-6, 2) * b[2]; b[N-1-6] -= M(N-1-6, 3) * b[3];
>b[N-1-6] -= M(N-1-6, 4) * b[4]; b[N-1-6] -= M(N-1-6, 5) * b[5];
>b[N-1-6] -= M(N-1-6, 6) * b[6]; b[N-1-6] -= M(N-1-6, 7) * b[7];
>b[N-1-6] /= M(N-1-6, N-1-6);\n"
>+" interp += b[N-1-6] * (X[N-1-6] - X[N]);\n"
>+"\n"
>+" b[N-1-7] -= M(N-1-7, 1) * b[1]; b[N-1-7] -= M(N-1-7, 2) * b[2];
>b[N-1-7] -= M(N-1-7, 3) * b[3]; b[N-1-7] -= M(N-1-7, 4) * b[4];
>b[N-1-7] -= M(N-1-7, 5) * b[5]; b[N-1-7] -= M(N-1-7, 6) * b[6];
>b[N-1-7] -= M(N-1-7, 7) * b[7]; b[N-1-7] /= M(N-1-7, N-1-7);\n"
>+" interp += b[N-1-7] * (X[N-1-7] - X[N]);\n"
>+"\n"
>+" return interp.zwxx;\n"
>+"}\n"
>+"";
>+
>+const size_t krig_bilateral_len = sizeof(krig_bilateral) - 1;
>diff --git a/modules/video_output/vulkan/shaders/ravu_r3_compute.c
>b/modules/video_output/vulkan/shaders/ravu_r3_compute.c
>new file mode 100644
>index 0000000000..23c312ff8c
>--- /dev/null
>+++ b/modules/video_output/vulkan/shaders/ravu_r3_compute.c
>@@ -0,0 +1,479 @@
>+/*****************************************************************************
>+ * RAVU r3, luma-only compute variant
>+
>*****************************************************************************
>+ * Copyright (C) Bin Jin 2019
>+ *
>+ * All rights reserved.
>+ *
>+ * Redistribution and use in source and binary forms, with or without
>+ * modification, are permitted provided that the following conditions
>are met:
>+ *
>+ * * Redistributions of source code must retain the above
>copyright
>+ * notice, this list of conditions and the following disclaimer.
>+ *
>+ * * Redistributions in binary form must reproduce the above
>+ * copyright notice, this list of conditions and the following
>+ * disclaimer in the documentation and/or other materials
>provided
>+ * with the distribution.
>+ *
>+ * * Neither the name of Author name here nor the names of other
>+ * contributors may be used to endorse or promote products
>derived
>+ * from this software without specific prior written permission.
>+ *
>+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
>"AS IS"
>+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
>TO, THE
>+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
>PURPOSE
>+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
>CONTRIBUTORS BE
>+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
>+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
>OF
>+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
>BUSINESS
>+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
>WHETHER IN
>+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
>OTHERWISE)
>+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
>OF THE
>+ * POSSIBILITY OF SUCH DAMAGE.
>+
>*****************************************************************************/
>+
>+#include <stddef.h>
>+#include "shaders.h"
>+
>+const char ravu_r3_compute[] =
>+"// \n"
>+"// This program is free software: you can redistribute it and/or
>modify\n"
>+"// it under the terms of the GNU Lesser General Public License as
>published by\n"
>+"// the Free Software Foundation, either version 3 of the License,
>or\n"
>+"// (at your option) any later version.\n"
>+"// \n"
>+"// This program is distributed in the hope that it will be useful,\n"
>+"// but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
>+"// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n"
>+"// GNU Lesser General Public License for more details.\n"
>+"// \n"
>+"// You should have received a copy of the GNU Lesser General Public
>License\n"
>+"// along with this program. If not, see
><http://www.gnu.org/licenses/>.\n"
>+"\n"
>+"//!DESC RAVU (step1, luma, r3, compute)\n"
>+"//!HOOK LUMA\n"
>+"//!BIND HOOKED\n"
>+"//!BIND ravu_lut3\n"
>+"//!SAVE ravu_int11\n"
>+"//!WHEN HOOKED.w OUTPUT.w / 0.707106 < HOOKED.h OUTPUT.h / 0.707106 <
>*\n"
>+"//!COMPUTE 32 8\n"
>+"shared float inp0[481];\n"
>+"void hook() {\n"
>+"ivec2 group_base = ivec2(gl_WorkGroupID) *
>ivec2(gl_WorkGroupSize);\n"
>+"int local_pos = int(gl_LocalInvocationID.x) * 13 +
>int(gl_LocalInvocationID.y);\n"
>+"for (int id = int(gl_LocalInvocationIndex); id < 481; id +=
>int(gl_WorkGroupSize.x * gl_WorkGroupSize.y)) {\n"
>+"int x = id / 13, y = id % 13;\n"
>+"inp0[id] = HOOKED_tex(HOOKED_pt * vec2(float(group_base.x+x)+(-1.5),
>float(group_base.y+y)+(-1.5))).x;\n"
>+"}\n"
>+"groupMemoryBarrier();\n"
>+"barrier();\n"
>+"{\n"
>+"float luma6 = inp0[local_pos + 13];\n"
>+"float luma7 = inp0[local_pos + 14];\n"
>+"float luma8 = inp0[local_pos + 15];\n"
>+"float luma9 = inp0[local_pos + 16];\n"
>+"float luma10 = inp0[local_pos + 17];\n"
>+"float luma11 = inp0[local_pos + 18];\n"
>+"float luma1 = inp0[local_pos + 1];\n"
>+"float luma12 = inp0[local_pos + 26];\n"
>+"float luma13 = inp0[local_pos + 27];\n"
>+"float luma14 = inp0[local_pos + 28];\n"
>+"float luma15 = inp0[local_pos + 29];\n"
>+"float luma2 = inp0[local_pos + 2];\n"
>+"float luma16 = inp0[local_pos + 30];\n"
>+"float luma17 = inp0[local_pos + 31];\n"
>+"float luma18 = inp0[local_pos + 39];\n"
>+"float luma3 = inp0[local_pos + 3];\n"
>+"float luma19 = inp0[local_pos + 40];\n"
>+"float luma20 = inp0[local_pos + 41];\n"
>+"float luma21 = inp0[local_pos + 42];\n"
>+"float luma22 = inp0[local_pos + 43];\n"
>+"float luma23 = inp0[local_pos + 44];\n"
>+"float luma4 = inp0[local_pos + 4];\n"
>+"float luma24 = inp0[local_pos + 52];\n"
>+"float luma25 = inp0[local_pos + 53];\n"
>+"float luma26 = inp0[local_pos + 54];\n"
>+"float luma27 = inp0[local_pos + 55];\n"
>+"float luma28 = inp0[local_pos + 56];\n"
>+"float luma29 = inp0[local_pos + 57];\n"
>+"float luma31 = inp0[local_pos + 66];\n"
>+"float luma32 = inp0[local_pos + 67];\n"
>+"float luma33 = inp0[local_pos + 68];\n"
>+"float luma34 = inp0[local_pos + 69];\n"
>+"vec3 abd = vec3(0.0);\n"
>+"float gx, gy;\n"
>+"gx = (luma13-luma1)/2.0;\n"
>+"gy = (luma8-luma6)/2.0;\n"
>+"abd += vec3(gx * gx, gx * gy, gy * gy) * 0.04792235409415088;\n"
>+"gx = (luma14-luma2)/2.0;\n"
>+"gy = (-luma10+8.0*luma9-8.0*luma7+luma6)/12.0;\n"
>+"abd += vec3(gx * gx, gx * gy, gy * gy) * 0.06153352068439959;\n"
>+"gx = (luma15-luma3)/2.0;\n"
>+"gy = (-luma11+8.0*luma10-8.0*luma8+luma7)/12.0;\n"
>+"abd += vec3(gx * gx, gx * gy, gy * gy) * 0.06153352068439959;\n"
>+"gx = (luma16-luma4)/2.0;\n"
>+"gy = (luma11-luma9)/2.0;\n"
>+"abd += vec3(gx * gx, gx * gy, gy * gy) * 0.04792235409415088;\n"
>+"gx = (-luma25+8.0*luma19-8.0*luma7+luma1)/12.0;\n"
>+"gy = (luma14-luma12)/2.0;\n"
>+"abd += vec3(gx * gx, gx * gy, gy * gy) * 0.06153352068439959;\n"
>+"gx = (-luma26+8.0*luma20-8.0*luma8+luma2)/12.0;\n"
>+"gy = (-luma16+8.0*luma15-8.0*luma13+luma12)/12.0;\n"
>+"abd += vec3(gx * gx, gx * gy, gy * gy) * 0.07901060453704994;\n"
>+"gx = (-luma27+8.0*luma21-8.0*luma9+luma3)/12.0;\n"
>+"gy = (-luma17+8.0*luma16-8.0*luma14+luma13)/12.0;\n"
>+"abd += vec3(gx * gx, gx * gy, gy * gy) * 0.07901060453704994;\n"
>+"gx = (-luma28+8.0*luma22-8.0*luma10+luma4)/12.0;\n"
>+"gy = (luma17-luma15)/2.0;\n"
>+"abd += vec3(gx * gx, gx * gy, gy * gy) * 0.06153352068439959;\n"
>+"gx = (-luma31+8.0*luma25-8.0*luma13+luma7)/12.0;\n"
>+"gy = (luma20-luma18)/2.0;\n"
>+"abd += vec3(gx * gx, gx * gy, gy * gy) * 0.06153352068439959;\n"
>+"gx = (-luma32+8.0*luma26-8.0*luma14+luma8)/12.0;\n"
>+"gy = (-luma22+8.0*luma21-8.0*luma19+luma18)/12.0;\n"
>+"abd += vec3(gx * gx, gx * gy, gy * gy) * 0.07901060453704994;\n"
>+"gx = (-luma33+8.0*luma27-8.0*luma15+luma9)/12.0;\n"
>+"gy = (-luma23+8.0*luma22-8.0*luma20+luma19)/12.0;\n"
>+"abd += vec3(gx * gx, gx * gy, gy * gy) * 0.07901060453704994;\n"
>+"gx = (-luma34+8.0*luma28-8.0*luma16+luma10)/12.0;\n"
>+"gy = (luma23-luma21)/2.0;\n"
>+"abd += vec3(gx * gx, gx * gy, gy * gy) * 0.06153352068439959;\n"
>+"gx = (luma31-luma19)/2.0;\n"
>+"gy = (luma26-luma24)/2.0;\n"
>+"abd += vec3(gx * gx, gx * gy, gy * gy) * 0.04792235409415088;\n"
>+"gx = (luma32-luma20)/2.0;\n"
>+"gy = (-luma28+8.0*luma27-8.0*luma25+luma24)/12.0;\n"
>+"abd += vec3(gx * gx, gx * gy, gy * gy) * 0.06153352068439959;\n"
>+"gx = (luma33-luma21)/2.0;\n"
>+"gy = (-luma29+8.0*luma28-8.0*luma26+luma25)/12.0;\n"
>+"abd += vec3(gx * gx, gx * gy, gy * gy) * 0.06153352068439959;\n"
>+"gx = (luma34-luma22)/2.0;\n"
>+"gy = (luma29-luma27)/2.0;\n"
>+"abd += vec3(gx * gx, gx * gy, gy * gy) * 0.04792235409415088;\n"
>+"float a = abd.x, b = abd.y, d = abd.z;\n"
>+"float T = a + d, D = a * d - b * b;\n"
>+"float delta = sqrt(max(T * T / 4.0 - D, 0.0));\n"
>+"float L1 = T / 2.0 + delta, L2 = T / 2.0 - delta;\n"
>+"float sqrtL1 = sqrt(L1), sqrtL2 = sqrt(L2);\n"
>+"float theta = mix(mod(atan(L1 - a, b) + 3.141592653589793,
>3.141592653589793), 0.0, abs(b) < 1.192092896e-7);\n"
>+"float lambda = sqrtL1;\n"
>+"float mu = mix((sqrtL1 - sqrtL2) / (sqrtL1 + sqrtL2), 0.0, sqrtL1 +
>sqrtL2 < 1.192092896e-7);\n"
>+"float angle = floor(theta * 24.0 / 3.141592653589793);\n"
>+"float strength = clamp(floor(log2(lambda * 2000.0 + 1.192092896e-7)),
>0.0, 8.0);\n"
>+"float coherence = mix(mix(0.0, 1.0, mu >= 0.25), 2.0, mu >= 0.5);\n"
>+"float coord_y = ((angle * 9.0 + strength) * 3.0 + coherence + 0.5) /
>648.0;\n"
>+"float res = 0.0;\n"
>+"vec4 w;\n"
>+"w = texture(ravu_lut3, vec2(0.1, coord_y));\n"
>+"res += (inp0[local_pos + 0] + inp0[local_pos + 70]) * w[0];\n"
>+"res += (inp0[local_pos + 1] + inp0[local_pos + 69]) * w[1];\n"
>+"res += (inp0[local_pos + 2] + inp0[local_pos + 68]) * w[2];\n"
>+"res += (inp0[local_pos + 3] + inp0[local_pos + 67]) * w[3];\n"
>+"w = texture(ravu_lut3, vec2(0.3, coord_y));\n"
>+"res += (inp0[local_pos + 4] + inp0[local_pos + 66]) * w[0];\n"
>+"res += (inp0[local_pos + 5] + inp0[local_pos + 65]) * w[1];\n"
>+"res += (inp0[local_pos + 13] + inp0[local_pos + 57]) * w[2];\n"
>+"res += (inp0[local_pos + 14] + inp0[local_pos + 56]) * w[3];\n"
>+"w = texture(ravu_lut3, vec2(0.5, coord_y));\n"
>+"res += (inp0[local_pos + 15] + inp0[local_pos + 55]) * w[0];\n"
>+"res += (inp0[local_pos + 16] + inp0[local_pos + 54]) * w[1];\n"
>+"res += (inp0[local_pos + 17] + inp0[local_pos + 53]) * w[2];\n"
>+"res += (inp0[local_pos + 18] + inp0[local_pos + 52]) * w[3];\n"
>+"w = texture(ravu_lut3, vec2(0.7, coord_y));\n"
>+"res += (inp0[local_pos + 26] + inp0[local_pos + 44]) * w[0];\n"
>+"res += (inp0[local_pos + 27] + inp0[local_pos + 43]) * w[1];\n"
>+"res += (inp0[local_pos + 28] + inp0[local_pos + 42]) * w[2];\n"
>+"res += (inp0[local_pos + 29] + inp0[local_pos + 41]) * w[3];\n"
>+"w = texture(ravu_lut3, vec2(0.9, coord_y));\n"
>+"res += (inp0[local_pos + 30] + inp0[local_pos + 40]) * w[0];\n"
>+"res += (inp0[local_pos + 31] + inp0[local_pos + 39]) * w[1];\n"
>+"res = clamp(res, 0.0, 1.0);\n"
>+"imageStore(out_image, ivec2(gl_GlobalInvocationID), vec4(res, 0.0,
>0.0, 0.0));\n"
>+"}\n"
>+"}\n"
>+"//!DESC RAVU (step2, luma, r3, compute)\n"
>+"//!HOOK LUMA\n"
>+"//!BIND HOOKED\n"
>+"//!BIND ravu_lut3\n"
>+"//!BIND ravu_int11\n"
>+"//!WIDTH 2 HOOKED.w *\n"
>+"//!HEIGHT 2 HOOKED.h *\n"
>+"//!OFFSET -0.500000 -0.500000\n"
>+"//!WHEN HOOKED.w OUTPUT.w / 0.707106 < HOOKED.h OUTPUT.h / 0.707106 <
>*\n"
>+"//!COMPUTE 64 16 32 8\n"
>+"shared float inp0[481];\n"
>+"shared float inp1[481];\n"
>+"void hook() {\n"
>+"ivec2 group_base = ivec2(gl_WorkGroupID) *
>ivec2(gl_WorkGroupSize);\n"
>+"int local_pos = int(gl_LocalInvocationID.x) * 13 +
>int(gl_LocalInvocationID.y);\n"
>+"for (int id = int(gl_LocalInvocationIndex); id < 481; id +=
>int(gl_WorkGroupSize.x * gl_WorkGroupSize.y)) {\n"
>+"int x = id / 13, y = id % 13;\n"
>+"inp0[id] = ravu_int11_tex(ravu_int11_pt *
>vec2(float(group_base.x+x)+(-2.5), float(group_base.y+y)+(-2.5))).x;\n"
>+"}\n"
>+"for (int id = int(gl_LocalInvocationIndex); id < 481; id +=
>int(gl_WorkGroupSize.x * gl_WorkGroupSize.y)) {\n"
>+"int x = id / 13, y = id % 13;\n"
>+"inp1[id] = HOOKED_tex(HOOKED_pt * vec2(float(group_base.x+x)+(-1.5),
>float(group_base.y+y)+(-1.5))).x;\n"
>+"}\n"
>+"groupMemoryBarrier();\n"
>+"barrier();\n"
>+"{\n"
>+"float luma12 = inp0[local_pos + 15];\n"
>+"float luma7 = inp0[local_pos + 16];\n"
>+"float luma2 = inp0[local_pos + 17];\n"
>+"float luma24 = inp0[local_pos + 27];\n"
>+"float luma19 = inp0[local_pos + 28];\n"
>+"float luma14 = inp0[local_pos + 29];\n"
>+"float luma9 = inp0[local_pos + 30];\n"
>+"float luma4 = inp0[local_pos + 31];\n"
>+"float luma31 = inp0[local_pos + 40];\n"
>+"float luma26 = inp0[local_pos + 41];\n"
>+"float luma21 = inp0[local_pos + 42];\n"
>+"float luma16 = inp0[local_pos + 43];\n"
>+"float luma11 = inp0[local_pos + 44];\n"
>+"float luma33 = inp0[local_pos + 54];\n"
>+"float luma28 = inp0[local_pos + 55];\n"
>+"float luma23 = inp0[local_pos + 56];\n"
>+"float luma18 = inp1[local_pos + 14];\n"
>+"float luma13 = inp1[local_pos + 15];\n"
>+"float luma8 = inp1[local_pos + 16];\n"
>+"float luma3 = inp1[local_pos + 17];\n"
>+"float luma25 = inp1[local_pos + 27];\n"
>+"float luma20 = inp1[local_pos + 28];\n"
>+"float luma15 = inp1[local_pos + 29];\n"
>+"float luma6 = inp1[local_pos + 2];\n"
>+"float luma10 = inp1[local_pos + 30];\n"
>+"float luma1 = inp1[local_pos + 3];\n"
>+"float luma32 = inp1[local_pos + 40];\n"
>+"float luma27 = inp1[local_pos + 41];\n"
>+"float luma22 = inp1[local_pos + 42];\n"
>+"float luma17 = inp1[local_pos + 43];\n"
>+"float luma34 = inp1[local_pos + 54];\n"
>+"float luma29 = inp1[local_pos + 55];\n"
>+"vec3 abd = vec3(0.0);\n"
>+"float gx, gy;\n"
>+"gx = (luma13-luma1)/2.0;\n"
>+"gy = (luma8-luma6)/2.0;\n"
>+"abd += vec3(gx * gx, gx * gy, gy * gy) * 0.04792235409415088;\n"
>+"gx = (luma14-luma2)/2.0;\n"
>+"gy = (-luma10+8.0*luma9-8.0*luma7+luma6)/12.0;\n"
>+"abd += vec3(gx * gx, gx * gy, gy * gy) * 0.06153352068439959;\n"
>+"gx = (luma15-luma3)/2.0;\n"
>+"gy = (-luma11+8.0*luma10-8.0*luma8+luma7)/12.0;\n"
>+"abd += vec3(gx * gx, gx * gy, gy * gy) * 0.06153352068439959;\n"
>+"gx = (luma16-luma4)/2.0;\n"
>+"gy = (luma11-luma9)/2.0;\n"
>+"abd += vec3(gx * gx, gx * gy, gy * gy) * 0.04792235409415088;\n"
>+"gx = (-luma25+8.0*luma19-8.0*luma7+luma1)/12.0;\n"
>+"gy = (luma14-luma12)/2.0;\n"
>+"abd += vec3(gx * gx, gx * gy, gy * gy) * 0.06153352068439959;\n"
>+"gx = (-luma26+8.0*luma20-8.0*luma8+luma2)/12.0;\n"
>+"gy = (-luma16+8.0*luma15-8.0*luma13+luma12)/12.0;\n"
>+"abd += vec3(gx * gx, gx * gy, gy * gy) * 0.07901060453704994;\n"
>+"gx = (-luma27+8.0*luma21-8.0*luma9+luma3)/12.0;\n"
>+"gy = (-luma17+8.0*luma16-8.0*luma14+luma13)/12.0;\n"
>+"abd += vec3(gx * gx, gx * gy, gy * gy) * 0.07901060453704994;\n"
>+"gx = (-luma28+8.0*luma22-8.0*luma10+luma4)/12.0;\n"
>+"gy = (luma17-luma15)/2.0;\n"
>+"abd += vec3(gx * gx, gx * gy, gy * gy) * 0.06153352068439959;\n"
>+"gx = (-luma31+8.0*luma25-8.0*luma13+luma7)/12.0;\n"
>+"gy = (luma20-luma18)/2.0;\n"
>+"abd += vec3(gx * gx, gx * gy, gy * gy) * 0.06153352068439959;\n"
>+"gx = (-luma32+8.0*luma26-8.0*luma14+luma8)/12.0;\n"
>+"gy = (-luma22+8.0*luma21-8.0*luma19+luma18)/12.0;\n"
>+"abd += vec3(gx * gx, gx * gy, gy * gy) * 0.07901060453704994;\n"
>+"gx = (-luma33+8.0*luma27-8.0*luma15+luma9)/12.0;\n"
>+"gy = (-luma23+8.0*luma22-8.0*luma20+luma19)/12.0;\n"
>+"abd += vec3(gx * gx, gx * gy, gy * gy) * 0.07901060453704994;\n"
>+"gx = (-luma34+8.0*luma28-8.0*luma16+luma10)/12.0;\n"
>+"gy = (luma23-luma21)/2.0;\n"
>+"abd += vec3(gx * gx, gx * gy, gy * gy) * 0.06153352068439959;\n"
>+"gx = (luma31-luma19)/2.0;\n"
>+"gy = (luma26-luma24)/2.0;\n"
>+"abd += vec3(gx * gx, gx * gy, gy * gy) * 0.04792235409415088;\n"
>+"gx = (luma32-luma20)/2.0;\n"
>+"gy = (-luma28+8.0*luma27-8.0*luma25+luma24)/12.0;\n"
>+"abd += vec3(gx * gx, gx * gy, gy * gy) * 0.06153352068439959;\n"
>+"gx = (luma33-luma21)/2.0;\n"
>+"gy = (-luma29+8.0*luma28-8.0*luma26+luma25)/12.0;\n"
>+"abd += vec3(gx * gx, gx * gy, gy * gy) * 0.06153352068439959;\n"
>+"gx = (luma34-luma22)/2.0;\n"
>+"gy = (luma29-luma27)/2.0;\n"
>+"abd += vec3(gx * gx, gx * gy, gy * gy) * 0.04792235409415088;\n"
>+"float a = abd.x, b = abd.y, d = abd.z;\n"
>+"float T = a + d, D = a * d - b * b;\n"
>+"float delta = sqrt(max(T * T / 4.0 - D, 0.0));\n"
>+"float L1 = T / 2.0 + delta, L2 = T / 2.0 - delta;\n"
>+"float sqrtL1 = sqrt(L1), sqrtL2 = sqrt(L2);\n"
>+"float theta = mix(mod(atan(L1 - a, b) + 3.141592653589793,
>3.141592653589793), 0.0, abs(b) < 1.192092896e-7);\n"
>+"float lambda = sqrtL1;\n"
>+"float mu = mix((sqrtL1 - sqrtL2) / (sqrtL1 + sqrtL2), 0.0, sqrtL1 +
>sqrtL2 < 1.192092896e-7);\n"
>+"float angle = floor(theta * 24.0 / 3.141592653589793);\n"
>+"float strength = clamp(floor(log2(lambda * 2000.0 + 1.192092896e-7)),
>0.0, 8.0);\n"
>+"float coherence = mix(mix(0.0, 1.0, mu >= 0.25), 2.0, mu >= 0.5);\n"
>+"float coord_y = ((angle * 9.0 + strength) * 3.0 + coherence + 0.5) /
>648.0;\n"
>+"float res = 0.0;\n"
>+"vec4 w;\n"
>+"w = texture(ravu_lut3, vec2(0.1, coord_y));\n"
>+"res += (inp0[local_pos + 3] + inp0[local_pos + 68]) * w[0];\n"
>+"res += (inp1[local_pos + 3] + inp1[local_pos + 54]) * w[1];\n"
>+"res += (inp0[local_pos + 17] + inp0[local_pos + 54]) * w[2];\n"
>+"res += (inp1[local_pos + 17] + inp1[local_pos + 40]) * w[3];\n"
>+"w = texture(ravu_lut3, vec2(0.3, coord_y));\n"
>+"res += (inp0[local_pos + 31] + inp0[local_pos + 40]) * w[0];\n"
>+"res += (inp1[local_pos + 31] + inp1[local_pos + 26]) * w[1];\n"
>+"res += (inp1[local_pos + 2] + inp1[local_pos + 55]) * w[2];\n"
>+"res += (inp0[local_pos + 16] + inp0[local_pos + 55]) * w[3];\n"
>+"w = texture(ravu_lut3, vec2(0.5, coord_y));\n"
>+"res += (inp1[local_pos + 16] + inp1[local_pos + 41]) * w[0];\n"
>+"res += (inp0[local_pos + 30] + inp0[local_pos + 41]) * w[1];\n"
>+"res += (inp1[local_pos + 30] + inp1[local_pos + 27]) * w[2];\n"
>+"res += (inp0[local_pos + 44] + inp0[local_pos + 27]) * w[3];\n"
>+"w = texture(ravu_lut3, vec2(0.7, coord_y));\n"
>+"res += (inp0[local_pos + 15] + inp0[local_pos + 56]) * w[0];\n"
>+"res += (inp1[local_pos + 15] + inp1[local_pos + 42]) * w[1];\n"
>+"res += (inp0[local_pos + 29] + inp0[local_pos + 42]) * w[2];\n"
>+"res += (inp1[local_pos + 29] + inp1[local_pos + 28]) * w[3];\n"
>+"w = texture(ravu_lut3, vec2(0.9, coord_y));\n"
>+"res += (inp0[local_pos + 43] + inp0[local_pos + 28]) * w[0];\n"
>+"res += (inp1[local_pos + 43] + inp1[local_pos + 14]) * w[1];\n"
>+"res = clamp(res, 0.0, 1.0);\n"
>+"imageStore(out_image, ivec2(gl_GlobalInvocationID) * 2 + ivec2(0, 1),
>vec4(res, 0.0, 0.0, 0.0));\n"
>+"}\n"
>+"{\n"
>+"float luma6 = inp0[local_pos + 15];\n"
>+"float luma1 = inp0[local_pos + 16];\n"
>+"float luma18 = inp0[local_pos + 27];\n"
>+"float luma13 = inp0[local_pos + 28];\n"
>+"float luma8 = inp0[local_pos + 29];\n"
>+"float luma3 = inp0[local_pos + 30];\n"
>+"float luma25 = inp0[local_pos + 40];\n"
>+"float luma20 = inp0[local_pos + 41];\n"
>+"float luma15 = inp0[local_pos + 42];\n"
>+"float luma10 = inp0[local_pos + 43];\n"
>+"float luma32 = inp0[local_pos + 53];\n"
>+"float luma27 = inp0[local_pos + 54];\n"
>+"float luma22 = inp0[local_pos + 55];\n"
>+"float luma17 = inp0[local_pos + 56];\n"
>+"float luma34 = inp0[local_pos + 67];\n"
>+"float luma29 = inp0[local_pos + 68];\n"
>+"float luma12 = inp1[local_pos + 14];\n"
>+"float luma7 = inp1[local_pos + 15];\n"
>+"float luma2 = inp1[local_pos + 16];\n"
>+"float luma24 = inp1[local_pos + 26];\n"
>+"float luma19 = inp1[local_pos + 27];\n"
>+"float luma14 = inp1[local_pos + 28];\n"
>+"float luma9 = inp1[local_pos + 29];\n"
>+"float luma4 = inp1[local_pos + 30];\n"
>+"float luma31 = inp1[local_pos + 39];\n"
>+"float luma26 = inp1[local_pos + 40];\n"
>+"float luma21 = inp1[local_pos + 41];\n"
>+"float luma16 = inp1[local_pos + 42];\n"
>+"float luma11 = inp1[local_pos + 43];\n"
>+"float luma33 = inp1[local_pos + 53];\n"
>+"float luma28 = inp1[local_pos + 54];\n"
>+"float luma23 = inp1[local_pos + 55];\n"
>+"vec3 abd = vec3(0.0);\n"
>+"float gx, gy;\n"
>+"gx = (luma13-luma1)/2.0;\n"
>+"gy = (luma8-luma6)/2.0;\n"
>+"abd += vec3(gx * gx, gx * gy, gy * gy) * 0.04792235409415088;\n"
>+"gx = (luma14-luma2)/2.0;\n"
>+"gy = (-luma10+8.0*luma9-8.0*luma7+luma6)/12.0;\n"
>+"abd += vec3(gx * gx, gx * gy, gy * gy) * 0.06153352068439959;\n"
>+"gx = (luma15-luma3)/2.0;\n"
>+"gy = (-luma11+8.0*luma10-8.0*luma8+luma7)/12.0;\n"
>+"abd += vec3(gx * gx, gx * gy, gy * gy) * 0.06153352068439959;\n"
>+"gx = (luma16-luma4)/2.0;\n"
>+"gy = (luma11-luma9)/2.0;\n"
>+"abd += vec3(gx * gx, gx * gy, gy * gy) * 0.04792235409415088;\n"
>+"gx = (-luma25+8.0*luma19-8.0*luma7+luma1)/12.0;\n"
>+"gy = (luma14-luma12)/2.0;\n"
>+"abd += vec3(gx * gx, gx * gy, gy * gy) * 0.06153352068439959;\n"
>+"gx = (-luma26+8.0*luma20-8.0*luma8+luma2)/12.0;\n"
>+"gy = (-luma16+8.0*luma15-8.0*luma13+luma12)/12.0;\n"
>+"abd += vec3(gx * gx, gx * gy, gy * gy) * 0.07901060453704994;\n"
>+"gx = (-luma27+8.0*luma21-8.0*luma9+luma3)/12.0;\n"
>+"gy = (-luma17+8.0*luma16-8.0*luma14+luma13)/12.0;\n"
>+"abd += vec3(gx * gx, gx * gy, gy * gy) * 0.07901060453704994;\n"
>+"gx = (-luma28+8.0*luma22-8.0*luma10+luma4)/12.0;\n"
>+"gy = (luma17-luma15)/2.0;\n"
>+"abd += vec3(gx * gx, gx * gy, gy * gy) * 0.06153352068439959;\n"
>+"gx = (-luma31+8.0*luma25-8.0*luma13+luma7)/12.0;\n"
>+"gy = (luma20-luma18)/2.0;\n"
>+"abd += vec3(gx * gx, gx * gy, gy * gy) * 0.06153352068439959;\n"
>+"gx = (-luma32+8.0*luma26-8.0*luma14+luma8)/12.0;\n"
>+"gy = (-luma22+8.0*luma21-8.0*luma19+luma18)/12.0;\n"
>+"abd += vec3(gx * gx, gx * gy, gy * gy) * 0.07901060453704994;\n"
>+"gx = (-luma33+8.0*luma27-8.0*luma15+luma9)/12.0;\n"
>+"gy = (-luma23+8.0*luma22-8.0*luma20+luma19)/12.0;\n"
>+"abd += vec3(gx * gx, gx * gy, gy * gy) * 0.07901060453704994;\n"
>+"gx = (-luma34+8.0*luma28-8.0*luma16+luma10)/12.0;\n"
>+"gy = (luma23-luma21)/2.0;\n"
>+"abd += vec3(gx * gx, gx * gy, gy * gy) * 0.06153352068439959;\n"
>+"gx = (luma31-luma19)/2.0;\n"
>+"gy = (luma26-luma24)/2.0;\n"
>+"abd += vec3(gx * gx, gx * gy, gy * gy) * 0.04792235409415088;\n"
>+"gx = (luma32-luma20)/2.0;\n"
>+"gy = (-luma28+8.0*luma27-8.0*luma25+luma24)/12.0;\n"
>+"abd += vec3(gx * gx, gx * gy, gy * gy) * 0.06153352068439959;\n"
>+"gx = (luma33-luma21)/2.0;\n"
>+"gy = (-luma29+8.0*luma28-8.0*luma26+luma25)/12.0;\n"
>+"abd += vec3(gx * gx, gx * gy, gy * gy) * 0.06153352068439959;\n"
>+"gx = (luma34-luma22)/2.0;\n"
>+"gy = (luma29-luma27)/2.0;\n"
>+"abd += vec3(gx * gx, gx * gy, gy * gy) * 0.04792235409415088;\n"
>+"float a = abd.x, b = abd.y, d = abd.z;\n"
>+"float T = a + d, D = a * d - b * b;\n"
>+"float delta = sqrt(max(T * T / 4.0 - D, 0.0));\n"
>+"float L1 = T / 2.0 + delta, L2 = T / 2.0 - delta;\n"
>+"float sqrtL1 = sqrt(L1), sqrtL2 = sqrt(L2);\n"
>+"float theta = mix(mod(atan(L1 - a, b) + 3.141592653589793,
>3.141592653589793), 0.0, abs(b) < 1.192092896e-7);\n"
>+"float lambda = sqrtL1;\n"
>+"float mu = mix((sqrtL1 - sqrtL2) / (sqrtL1 + sqrtL2), 0.0, sqrtL1 +
>sqrtL2 < 1.192092896e-7);\n"
>+"float angle = floor(theta * 24.0 / 3.141592653589793);\n"
>+"float strength = clamp(floor(log2(lambda * 2000.0 + 1.192092896e-7)),
>0.0, 8.0);\n"
>+"float coherence = mix(mix(0.0, 1.0, mu >= 0.25), 2.0, mu >= 0.5);\n"
>+"float coord_y = ((angle * 9.0 + strength) * 3.0 + coherence + 0.5) /
>648.0;\n"
>+"float res = 0.0;\n"
>+"vec4 w;\n"
>+"w = texture(ravu_lut3, vec2(0.1, coord_y));\n"
>+"res += (inp1[local_pos + 2] + inp1[local_pos + 67]) * w[0];\n"
>+"res += (inp0[local_pos + 16] + inp0[local_pos + 67]) * w[1];\n"
>+"res += (inp1[local_pos + 16] + inp1[local_pos + 53]) * w[2];\n"
>+"res += (inp0[local_pos + 30] + inp0[local_pos + 53]) * w[3];\n"
>+"w = texture(ravu_lut3, vec2(0.3, coord_y));\n"
>+"res += (inp1[local_pos + 30] + inp1[local_pos + 39]) * w[0];\n"
>+"res += (inp0[local_pos + 44] + inp0[local_pos + 39]) * w[1];\n"
>+"res += (inp0[local_pos + 15] + inp0[local_pos + 68]) * w[2];\n"
>+"res += (inp1[local_pos + 15] + inp1[local_pos + 54]) * w[3];\n"
>+"w = texture(ravu_lut3, vec2(0.5, coord_y));\n"
>+"res += (inp0[local_pos + 29] + inp0[local_pos + 54]) * w[0];\n"
>+"res += (inp1[local_pos + 29] + inp1[local_pos + 40]) * w[1];\n"
>+"res += (inp0[local_pos + 43] + inp0[local_pos + 40]) * w[2];\n"
>+"res += (inp1[local_pos + 43] + inp1[local_pos + 26]) * w[3];\n"
>+"w = texture(ravu_lut3, vec2(0.7, coord_y));\n"
>+"res += (inp1[local_pos + 14] + inp1[local_pos + 55]) * w[0];\n"
>+"res += (inp0[local_pos + 28] + inp0[local_pos + 55]) * w[1];\n"
>+"res += (inp1[local_pos + 28] + inp1[local_pos + 41]) * w[2];\n"
>+"res += (inp0[local_pos + 42] + inp0[local_pos + 41]) * w[3];\n"
>+"w = texture(ravu_lut3, vec2(0.9, coord_y));\n"
>+"res += (inp1[local_pos + 42] + inp1[local_pos + 27]) * w[0];\n"
>+"res += (inp0[local_pos + 56] + inp0[local_pos + 27]) * w[1];\n"
>+"res = clamp(res, 0.0, 1.0);\n"
>+"imageStore(out_image, ivec2(gl_GlobalInvocationID) * 2 + ivec2(1, 0),
>vec4(res, 0.0, 0.0, 0.0));\n"
>+"}\n"
>+"float res;\n"
>+"res = inp0[local_pos + 42];\n"
>+"imageStore(out_image, ivec2(gl_GlobalInvocationID) * 2 + ivec2(1, 1),
>vec4(res, 0.0, 0.0, 0.0));\n"
>+"res = inp1[local_pos + 28];\n"
>+"imageStore(out_image, ivec2(gl_GlobalInvocationID) * 2 + ivec2(0, 0),
>vec4(res, 0.0, 0.0, 0.0));\n"
>+"}\n"
>+"//!TEXTURE ravu_lut3\n"
>+"//!SIZE 5 648\n"
>+"//!FORMAT rgba16f\n"
>+"//!FILTER NEAREST\n"
>+"1a88533af88e23bb14d5c73afaa0e53ab42022bbcfc4583abb5687bb3fe2283cd2080d3c23c4ff3b97812f3cd41d95bbf8384c3bd081803c65bf583e57a6603eb9c28e3ca1e1833b0000000000000000f7572b3a485110bbd9225c3b3f3b373b1ae84cbbfafe293a22fdcbbb1bded03ba2c4a53ca50ba93ca7158b3b33bb29bcdeec353c861f7f3c010d243e3577523ef322463d94b2b53c0000000000000000cfab4a3974c1923a306fac3b5c33a33b92ae0dbaec67f4388c7b9eba38484ebd7d1f633d9ae5ad3dc7fc1bbd5a78b6bb471616bba8882abd791ba93dea365a3e75682b3ea374c93c000000000000000042eeba397216e3ba69265c3b136e5c3bcfbbcbba4096c139cf552ebb5f45f53b4389a5bc5afca9bc9e9feb3bc89f1bbb93b09f3b647b86bcb7208b3e4b4b8e3e44b582bc09e0a33b00000000000000005f1b933907d988bac6138c3ad2518b3a16e7ddba0d9ca839ef490cbca6e7973b01e1bebbfb71b9bb2e478b3b839b11bc1dcca83b51cf7a3c59fd673e81cd783efd1ab83c47d8f83b000000000000000022ac0539362d08bbb745483b7ce33f3bbfbf50bb3b48dc388b720ebc2e1919bcebcbc13cc8e0cb3c4f96f6bbd65d25bcac19253c28dbc13c5e20323e118b443ea67c653dbbe1f93c0000000000000000b939c83978cf17bb07499c3b5ffa933bf479e2baae3aa139738c7dbbaeec883b884a07bd667008bd70093d3b841355bbd6b5fb3b479706bdc9f29a3eeb839d3e0ac502bd57e1ee3b00000000000000001d8c2a39849f8eba2263373b4491683be4377cba23bc39390a7ee6bb63f0963ba3b6ebbca7baf1bca218673a08aad7bba3d6d23b127996bcad77903e5690973ed03452bc4dd1083c0000000000000000794c39394be7b3b9df61c63af4e3083b294d03bbf5dc8739dab745bc44e8d7bbb461cbbbd0d5acbb81bf51bcb92b61bc3a907e3bfe92a13c19a46a3ef3237f3e2847183d5f4a823c000000000000000033143d3a4ab0f2bae087063ccabc023ca1a53aba54bb2c3a46f043bbc87f043a68383fbd9cf43ebd3b2d1cbb541a4abbe17c2d3c4cd546bd3c7fa73ebaeea93e7cdc3dbd33a43c3c0000000000000000e6d97a394b2e9bba23e38c3b70ae8f3b48d6293aa1dfe6b7e23cacbb332a223baecb15bd38e216bdd027a3bb2e57e1bb8388c13b03290ebdade39b3eeb5ea23e57dfd5bc15de543c000000000000000080f2d2b815e00639aeb8283bcdff843b8f0cfeb9a7eee1b854bd14bcaa7417bb7f67b9bcc94eb5bc5b9439bc579175bc1f00ce3afcd007bc818b883e3256933e5e69ef3b9af1ae3c00000000000000000f4e023af70509bb5f71303c55082b3c4df4ddb92f6880399fafb9ba775b6c3bb0fa62bdf5646dbd063f833a9d1f07bb46af403c214176bd106bad3e6e0fb13e71806dbd50946f3c00000000000000009d76c4b77bc5c6ba840ed93be3ddde3b9d180f3b415eaab9a298dabad28b503ba8be31bd04a43cbde54d06bc9035ebbbc45e7b3b39aa51bd4171a33e8b39ab3e56ac12bd074f9c3c0000000000000000e34c75b90a5e9eb9b6cf2d3bf0008d3be58ed33ae9e841bab3fe00bbbcfb903b63abbdbcfeb5cdbcab1c86bc2e83cfbcbe3689bc0d3f07bdc1548e3e286a9a3ecb41733b2f403f3d000000000000000026ec85bbed0ee9b761f6bc3b9b12ea3bf8f5de3a2c808dbb91509c3b93ba933c06346abd8e0479bde121683cd9fd4f3b3936d53a37016bbd8bd9a93e72beaf3ef7df60bdb092ef3b0000000000000000130f7bbaace7bdbaee87b93b3c61013c5eae4d3bb79055ba3323a6b9ce2e4c3c14453cbd0e3b5ebd9cdc99bbb3bf07bc1a72443ae1e081bd5712a33ec1deb13eb86118bd6985b03c0000000000000000e8f506b9d90b86ba1338e93a7d509b3b44f9fd3a3dda3d3a6173c73b10d1903cc9f393bcc381c7bcd542d2bc06093abda70842bdb8ff8cbd77c68d3e0650a13e8461863cff66b73d0000000000000000dfb5f2b6c3e2b1bae0ff3c3c5b76613c29399f3a5c4a4a3a024f76bbf4cfe63b046176bdd64b87bd390afbb92ac2d7bb46a6683c8f3791bd382faf3e2ca8b93eda5985bd8f0cad3c0000000000000000108926ba9260daba4f61ab3b92e4233ccc4e453b8009093bcab701bb01d5393c4a4721bdb70265bd8c3d5bbc123f59bc0cc4e23bfd88a6bd1eeaa03e6d11b93ee7740dbd8407e33c0000000000000000818a143a353b1abb6723fcb8f05a373b82905fbbe651333c81093b3cd681103de1ae43bb3e9cb6bc5e7f03bd33979fbd7c5491bd656efebd6bef843e1be5a73e70c15a3d4ea4093e0000000000000000851a9f3a8e3766baab342f3c7fd9573ccd953f3b54bf5a3bff31b9bb3f1d843aea5c55bd7cff7fbd7c1b14bc11ad17bc4f54733cb5b688bd7d04aa3e4b7dba3ef03575bd1b96b83c00000000000000000da8f83a0a226cbb3434893b6277213c9a4d7b3b5322163c0af2fbbb4760343c21b7e9bc39776ebdd19cb0bc666badbc14c3603cc74eb6bd49ea983e2bd6be3e0726bcbcaae8e23c0000000000000000378a903a13e9c2bb07db25bbb8e34439a05c0dbc0a8be53c19ed543cb5973b3dc6a36d3c4c92e3bcda552fbd4ae9c7bd299785bd79b433beb2566f3e5e7eb93e95bfab3d0efb123e00000000000000005e840b3c8fde02bc2971bb3cf1fcda3cac95343bb1b53d3b4a467dbced4aa73c3425a6bd2e96bfbd56b0db3bb20b21bcfd72b63c4463a4bd5b65b23e87c0bf3e458d9abd28c6e13c00000000000000009cb6f23bb60ad638d76d7e3c3292ac3c141e323c17cc773c6ba965bc3282b2ba58e94bbd7b458fbd365402bd3d40a9bc6f34a73c2dce8dbd34fe8a3e6057bc3ef6a9a63c5035da3b0000000000000000b8950abcc91c6cbba41606bc3e3d943b3763043c75531c3de29d673c59ab0b3dd6c8763d534a79bdbf38ddbda2fb66bd7cc00abd3a0c56bee356ff3d72f2dc3ea254583e48b27c3d0000000000000000c907a43aa5b0fbbad955b2b509ba5e3a42acedba48a6ca3a7cab89bbca0e483c6afca43b7ecbc33aad473b3cf3dfbbbb8141703a9586273c530b533e0ccf773e9146903ca9a6443b000000000000000085f9a73a54a9c1384be4be3acb3857ba94ff57bbf336c13aebca0bbce0042c3cc2588c3cc592893c8d863a3a75f29abc6285163bb8f3c73b5ec0e73ddbab663e12a4d93d55ceed3c0000000000000000e3953239c8e5df392888663b416d703ba9a4dcbb0ef6d5b7d73d81bb00e2be3b30fd183c05e1eb3c06a3ed3b8463d7bc7f4833bcd2670ab96368883de1a10c3e80702a3e7314f33d00000000000000006c12a7390ef3f5ba97c4523be0a2683ba48cccba0816eb3953bc27bb4a9cf93bfe25a5bcd473b2bcaa46f33b755306bbd4439b3b518f8fbce35d883e1e11923ec05085bc0bd29e3b000000000000000019f2a63972ef31ba1b90043abf4f883a25b436bbc24b0b3a31a4ecbb5eaef63b97de0cbc54360cbc8a09ef3b0ab616bce102a73a7fcff63ba4d0583e1896873e1ce5dc3c89dcf53b0000000000000000918cab3980e7afba4f42983a2cc9b339cf8fe5bb9f285b3989c95dbc9f9b3c3c46d8513c5764783c5c98cb3bd7bec3bcac9ef5bbbf48b63c3ed1143e6ee0423ed7b7bc3d1b57633d0000000000000000a28ee339feee3ebb0ce0a63ba7aa8f3b53fe8fba6cd88639593b81bbf5a2b73be31107bd6b080bbde664c33ad0b41bbbc18ff73b77c10dbd46ea983e1a46a03e5cbe01bd9e08e63b0000000000000000825572390d99b6ba5d92123bd32e8e3b85536ebae0cb8f39861acfbb99db143cc2e4fabcb74903bd8e05c6ba8acda0bb433a923b4c1cd8bc095f8b3eee28a13e5f783bbc3313023c00000000000000001d7326b88b1e133b6273deba1c57883bb86fb2bbb2a1463ac4823ebc35a5053c2a457cbc70c728bc2c3208bc89f95ebc1bb10fbc9e83813bd6ca5c3e98cf8d3e84513b3d1a37903c0000000000000000e3fb7b3ade503fbb93520e3c59ec003c48c49d39a750123ab66c6dbbef085b3ba8fd3fbd0f0243bd175f94bbd4aa3fbb8ea0253c30b44ebda836a53e96f2ac3ef3603abda600473c0000000000000000e843243a9b8f4ebb6c63a23b57e39f3bca11403bc33492b9cb2984bb36e02f3c8b3d23bd577924bde12e3fbccd0ed2bba114ea3a1e903dbd63c7973eb040ac3e804bc0bc3951873c00000000000000008a42b0b9035eef3a0e8761bb007f363c01ea0bbbb230a63995110abc783eb13c979925bd628fb0bcb82bd4bce45c19bc3dc844bcde5cedbc47ad803eb4bba93e3d02fc3bc338de3c00000000000000007f063d3a10cc47bbb18b2d3c3038463c44878f399d4d303a06e30abb0849d83b924463bd22a275bd9d1e38bb41366abbdae12d3c2b4f81bd5c89aa3eb89bb53e37b867bde93b8e3c0000000000000000abf54b3a0afb94bbe676c73b88dbfb3bb7d6d23b11cb85b96da425ba7a6c6f3ce49a2abd52b856bd1e928cbcf51148bc84ff42bb5cc98bbd00ae9c3e6025b63eca32d8bc8ea6ee3c000000000000000011372c3a05e26dbb24be0fbbb97fc43b641b173c231cbeba4da54e3b3c06d63ccf5ac5bc6a9b11bdc667fabc8b2503bdccc003bdf23190bd8eff853e7d71b13e8448783c1a01823d00000000000000001c76abb9d0af31bb5b3b1c3c9981623c36c4f13aa65f94b8e13bd7bad8ad4b3c0c296cbd00be86bd978f1cbbb53092bb118d073c2bcf8bbdff00a93e2ad9ba3eb7606cbd8497a43c000000000000000098c97a3a1637a8bb7980483b8c982b3c4ee9e13bfa661e3b5f1ae9baedf4c33c576417bdd3c971bd6886bdbc407699bc97c260bb57afb7bd0f85973ee743c13e8f9bb0bcbff51c3d00000000000000009d25c53a189c9cbb5c6952bbcf92f3ba2297a33b6fc0113c8eb1913bd05b0e3da9a692bb54e1b3bcfb750dbd902d84bdab813abd0f23e1bd23fa763e1ab4b43e8883253dff44d03d0000000000000000aa6eeb3a11ab88bb73d42e3c2b0b8f3cf95f383b1fb9553b0f73c1bbb574373c183167bdb43c94bdd1a420bcaa4331bc14f5533cf6fa9bbd4fcba63e2a65c43eaaf07cbd0ef2e43c00000000000000006076ea3a33ca9ebbe14002bbeff3463c4627ac3b4c4e233c9a36b0bb0d1ce93cbe3bb1bcbfea81bd9ec1fcbc4659f6bcb1ba953b49deeabd784e8a3e9eb2ce3ea499efbb8bfd343d0000000000000000245a163ba00d66bb9ca14fbb7367ddbb4cc434bc4457d03c91bc00b9b6060b3dbe426e3c929a6fbaa755e5bc09ebc6bdcd3e0cbde6e217be5b194e3e363db53ed609ad3dfa1bf03d0000000000000000af206d3ae37258bbddac013c49617c3cda23ed3ba8da8f3bb360cfbb0131203cbe7f39bd28e491bd4e869bbc608c46bc71ba4e3c1f3294bd948b9a3e587aca3e36df5abdda45e13c0000000000000000034b823b1f7401bc873546bb8e24143cdec3fc3b96e28c3cc4c735bcdd09fd3cee47c4bb92a88dbd9f2a17bdca0c15bd3e4b733c13adffbd6e006d3e8cd9dc3e614e383c45081a3d00000000000000000efc523b7c0b15bb9091a5bb07f8c4bb525bc6bc49b2243d7574a3bb4138f03c1503023dac837dbb31b9b4bc9b68dfbd4f4316bc26063cbe24a8283ebc7ec33eb6f3e13d3e37df3d0000000000000000ab6a0e3c0dd1b8bbf38f843c3928d83c64a7283c61c8743b316e88bc81069a3c502182bd4e3fd4bd21c20abcb8a30ebcc7d0a73c36aca4bd7d89a13e56fdce3e6f6691bdd6010a3d00000000000000008bea323cf4ad30bc121b0c3cb42f1a3c1380b73c3952b73c9b61bfbc76b5a13ceb0437bcc422acbdd5ba03bd5c3022bde7990c3d0f2bebbd2b08323e9d7eee3e4698243da12d093c0000000000000000e356b53b27f72bbb24b214bc91725dbbdd59f2bc2075633d84dea9bc542ae43cac824b3d58d79abcc32caebc0872cbbdb681173db38a5abe30a66e3da337dc3e77c55a3e91bd263d0000000000000000bd54a53a085f05bb2ce9fdb816e52e3a414022bbe6e6df3af08360bbc72e433c5fb7a83b65778439dfc64b3cf10badbb4d2d613a6058063ce502483e5168833e310b8a3cca16073b00000000000000000b70cf3ac1a16fbab28e163aaaf4cfba55d52bbb46a5ed3a2dbbabbbbe7a833c41d2643c46dbf13b12ad5dba01a489bc4901a3bb5d81d23b288ea83de3d5863ef627063e7ac00b3c0000000000000000947d78393b20a9399d9ca6ba592811bb7df528bbea39c7383f4e82bbdcecc63c057c183b8992223b7b3669bb0155e5bb51824abc64cf583b7bc2253d250f5a3efaa0693e1533963c00000000000000002886ba390ec8fdba7192613be8b7733bba15c9bafcea023a5e662bbb039ffd3bf1eca4bc06f3bcbc244e003cb4c6e9ba3695993b28bb97bc4bce853e3cf4953e05858ebcb93f933b00000000000000005505d339147b73babfe7953834b6bc3a5ca68ebbf6625f3a63bdbcbb2a9b363c123d44bce54752bc43ef3a3c47ed0fbca74dbcba2f60c5bad70e4c3ef331953e2accdf3c10e48b3b00000000000000008bf0303ae68955bab0f95b3a98a50fbbd5d41dbc6250253a45622bbc00caa93c6de73abb3df6683bd05b973cdc6966bca48758bc39180a3cebd2063e23705e3ec0e3093e41f9853c00000000000000006aa20b3aa03b77bbb370c03b6383873b353706ba2bde4339f0a48ebb4301e73b09b308bd58570ebdd983083a5c71a3ba7e4c023c0cca12bdfc0d973e41fba23ebd1a01bdd8ddbc3b0000000000000000982dd339ecb111bb0762423b798f963bb9cd70ba3897ce3931aec7bb9e12553c7e6607bde2eb0fbdbe4a0fbb765834bbf49fa13b66d80cbd83b7873ebdd7aa3ebfcc5fbc40f0af3b0000000000000000cde0d6b72ee34d3b10116fbbb87dc13b850515bc60ccb23aa34e1dbc8b1a8e3cff30b7bc036685bc80fbdeba8c0c20bca1eb42bce5112cbca4554c3eab7d9d3eff674e3d87251d3c0000000000000000ce4c903a564777bbcb291c3cd958f33bbc99b63a8e7aea39680089bb83b6bc3b2d6243bd5f3c47bd178acabbe71622bb63c0233c4e3c56bdc047a33e9a26b03e4c393abdb17f463c000000000000000047e4853a76ac95bbdbe3c73b8c969d3b4136b53b3167edb9e8449ebb6aa08d3cfdae32bd904e36bd701c87bcef1f90bbb891533be63d64bd5266943efa42b63e1642c7bc32bb773c0000000000000000e4424fb9a7a47b3b2f5505bc0c9a783cc8caa0ba52a68639fd4059bc0e60213d914065bd90bf90bc231320bd4317743783dc1abc99892abdda876f3eda2cbf3e586e26bb33e5bd3c0000000000000000c50c793a0ac067bb75a8263c74bd573c73a9b43a0ac9ef3929204fbb37b90d3c5dd561bd38e27dbdeda1babb235f6ebb9d1d2d3ca37f84bd5bcca73ea080b93e5a4064bdabfe943c00000000000000004c8ed63a7a14c6bb8e17af3b36b9eb3b9ac72f3ce9dd2739664150bbe3eaae3c0fe121bdd0d869bd37e1d0bc20b954bc831784b99a4ba0bd5d3b953edf4dc13ee632b5bc34e1f13c0000000000000000cd38473a87ffe6ba94cfaebbb09f753bdd99873ce579c8b767c480bbe75c093da16cf5bcc4f51ebd1a6638bd9379a7bc026f69bc097f9abdd098753ede38c73e57d8243c5e6b293d00000000000000000e15a43ad14996bbea59243cfd4a8b3c35f10f3b37c7e93a2e8298bb87d9693cc8456bbd57748dbd05d11ebcbb13f0bb442f243cd32496bde38ba53eda24c23e18246ebdc5f4cd3c0000000000000000f790173be2069ebb565579baddd81c3c7183253ce684c73bb492dcbb937eea3ce801e2bceed36ebdf14c1dbd8a1dc9bc41a3803a7302d0bddf36893e5fe8ce3ea40b1fbcdc712f3d00000000000000000870843a708087babad768bb46aee5bbef39353c093b453cbf4a87bb6bd6cb3c9893293b6920f1bc13c04cbd9e5c49bd229f09bccf9fdcbd6e2f583e9788c73edb775e3d74fd5b3d00000000000000002f5e113b29f8b9bba34e163ceab99b3cbcfba73bbf8f4d3b343ccdbb1863703c711a59bd18209cbd4c3d88bc79ff1cbc2a18493c013e9fbd4c009f3e59dfcc3e53f974bd2eb4ea3c0000000000000000277f743b2a9439bb3ec3c3bb1fc0ce3b11d0063c2397743c8cf63ebcf474e33c4926abbb1bd763bdc81b43bd84ac1fbd0457123c7edaf4bd0494633e56dedf3e8fa2fe3b65274e3d00000000000000006867113a86c3fd3a8d65d0baf25b1ebc5163a8bb4767c83c08e5f6bb608b6c3c6e4aa13c2c5cc4ba18f756bda64395bd6cfb033c1bfe01be30551f3e0f9ec73ee8a8e53d96d7503d00000000000000001e2d193bb5a2cdbb8218d93bbbb3773c7ca5423c98ad673b947cf4bb6a2e733cb76126bd52559abd67afe2bc90662bbca3c6383cde5a94bd17be8e3e773ed63e548750bde22be83c0000000000000000f302d53b58187bbb5b649abb6c6aa2ba2435253c05a6ae3ca11389bc6cc0bc3ca3374b3c75685fbd0bc250bd052342bdaaba8b3c815cf4bd122e2a3e3ab6f13e1324c33c7c593d3d0000000000000000277ec9391711833b992328ba1662f6bbbd509fbc3b56113df0b424bcc665d93b10ece93c05ccf23b6b1d3ebd940fb0bdd9fdc03cb97910beb31dfa3d7b76c93e7211153e54ea333d0000000000000000c513493cad322ebc7fb68e3cf547d03cc046413cad87c63b7e5859bc96455e3cffdd51bd0ec3e0bd7c2471bc45f4c2bb3b617c3c2f218fbd043b913eca0fde3e2633a1bd40b00e3d00000000000000008277173cd6a1b4ba204ca3bb9de6ec3aadf0c33c38e7be3c11f8b7bc56083b3ce8e3843c59af88bd4bbc1ebd820150bd42acc23cdd4dbbbd85f0a33dcc18093fc10ac23ce428e23c0000000000000000ef30ee3aa3db6b3b5b44623a41a2bbbb0928cbbcf389343d05355fbc6e3624bb7b83e93c13b3f43bf8d209bda148bfbdc569233d0bf4e6bd3104033dfdbcd23ed5d4503eaa86503c000000000000000055a99d3a8dc10ebb6ffd77bac578923afa5e48bb3a2c063b6cf528bb778d473c6a12a13b1959cdbaf00f663caf1c88bbab740c396f0be83b4ae53e3e90a98a3e0f5b653c63f9063a0000000000000000fe80d83aa5d529bb55e608bb6d6cbcba1d52e4ba33ff873ac4935ebbb2dfa73c1fc02b3c07f97dbbeed4313b7088e43ad444c2bb484db53b915dac3d787da43e5b289c3dc11c8cbb000000000000000008d02d3ac671f9ba4d9a0abbfd9abc3ae4dc95bbf41c043a73d2abba1b47c93c9d537fbb5841b5bcf813ce3c7f761dbbe5f83fbc9cfda0bb02a0273d6d5bab3e0d15ff3d7eb0213b00000000000000003971d4390a5015bb2a7a6e3b712c793bd41ad5bae15a2a3ad08524bb9ce5023c2c7da5bccc54c5bc95a4103c88c2cabaa5009a3bf16d9fbc7eb3833e1967993e098b9cbca4ed813b0000000000000000cff2e8399269aeba3e8590b9e013133be9e3b7bb7283a03a305c92bbb5d25f3c36d562bc9e5f9fbcb3778c3c7889f8bb4af805bb52ea0ebc8cd2443e9d99a33e87ce713cf6a30a3b000000000000000013985b3a47b4b1ba280800bb25a292ba6ab443bcf734963a7628f5bb15ddf73cfc513abc758740bc46cbed3c9d9278bb9d7595bc7bd19ab9bb71103e82dc923e700a8f3d12c5283c000000000000000063a1333a197490bbe8bcda3b8630763b83121ab93afe533990fb9abb98e8043c9c030bbdea0910bdaef32039a4fdb2b9c76d063ca5ce14bde96c953e1d86a53e8e9f05bde9ee9b3b0000000000000000163e3c3a39036ebbd701983b43c2833b4e919eb99c5b84399e20c8bb0d12773cd01d0ebdeda31fbd7bc071b95bab62bad80ff43b973622bd0115853e5efbb23ed6789dbccd6e013b0000000000000000258eb839c0d5353ab6ae81ba4b826f3b63ad2dbc137fa63a4190d9bb068ca23c85bbbdbc72f9e1bcce7c823ca9e10cbc37a00abc7362a7bc35a6453ee302ad3ec338013d8b55133b0000000000000000ffd0b23ade8c93bb3d63273c37e4f13baea6023b8ff98339931da0bb041bf23b550447bd9fbc4abd2bd9e1bb6ed6c6ba3a232c3c9cb159bdffdea13e9171b23eebea3bbde256363c000000000000000094aac93a0503bdbbab860b3ccbc6633b5455f33bb1cc7abafe31dabb2e05a53c60523ebdc6fa47bd23b989bc53d366ba8bec0a3c406f77bde551923e76d2bd3eab57ecbc29ed1b3c000000000000000000c4913aaecd92bafe79013bf260653b7825d73b278335bbc3fc34bca35a0d3db2284abda41616bd303cacbcdf41003adb32a739964a52bdbcf16e3e47b0c73e2f0a0abca112223c0000000000000000c4b3993a88aa82bba911273c2a17633c79eddf3a1b08c039ce686fbbeec5203c849c63bda56481bdeb6fe6bb9ce93bbbaa502d3c040584bdaed6a53efb71bc3e360e68bd7f68913c000000000000000021b0123bb2afc2bb6b5fab3bd79fea3bb835503ce4d16cba9e46d2bb2b07ba3c750022bdba4b7fbd650ce6bc5dfcbcbb097cf83b2bb29ebda3388f3ec193cb3e65fbe4bcfd6e9f3c0000000000000000813fb23a11eb14bbe09210bbef7fc4399b04bc3cde85a5bb3af8e2bbf310093ddbe807bd03dc5bbd96b22bbd01af17bbd5a36539de0791bd5842693eb185d83e245cfbbbf9148b3c0000000000000000b84de03a7b43b2bb1b9f1e3c9098993c3af61d3bcb21113b76c3bebb059d843c71d16cbd20d38fbdc69561bc4a97d1bb8c5f363cf0a097bdbbeba13eec3ec73e259a71bdafd2cc3c00000000000000009454063bb7200bbb0ab06ebb310f213c1e0f663c4ecb8d3b15fa1bbcbd3cd23c9ae3babcf9d97fbda0414bbdffbf56bc35d3213c1b3cc1bd2d037a3e868edc3e9d6938bc7fe2e63c0000000000000000feef723a183bcb39bc807cbbb37600bc9a81d53c41efe63aec63dcbb12adba3ca30a4dbb680446bd55f68bbdee881ebcaf66ee3b1d4dadbd9ff53c3e36b0e43e25caf03c2cd5503c0000000000000000174b223b811cddbb543e0d3cba399f3c125eef3b8c700e3b3c47e8bb8545903c2c2456bd09339ebdb3e4b7bcfa6dd1bb0ca4493cd12e9cbd4d57983ed5ded33e758776bd3b36e03c00000000000000005c680f3bfbf43d3ab9c1cebb2811083becd9883c21192a3c5ef344bc1bcd953c0f300b3b9fe861bd58d88cbdc247a9bc096b7b3c9700c6bd9c793a3e2e34f23e6664b93b0c90fd3c00000000000000009a40ce3854df1b3b970f31393a7168bc3c83923cc04d343c3eddd2bb67a5de3b8ffa8c3c88b5c9bc12fdb7bd811089bc981b893c5376a8bd1c5dfd3d40b3eb3eca67a33da7cf06bb0000000000000000317c573b3ddf04bc8a5ec63bb10e6c3c6adc7d3cbc4eb13a9de914bc5edf903c10fe1bbdf8d39bbdd54610bd3e87b2bb240e493c7b428ebd0f99853e7066df3e197054bd005ad13c0000000000000000f491393b96db953a7e4e52bbfed5cfbbcf6e8b3c77ee853c540964bc3baf183c4b3b923cf5a634bddfd7a4bd7b91d9bc418d9a3c8a8bacbde9dbef3d7e1a023fa773bf3c9270db3c0000000000000000e16f01ba45216f3b2d52ce3ae16d53bc58cda73b1e3aac3c4b10bfbb567938bb57cde33cc0e74abcb78fbdbd98c3dbbcdbd6b13c0b15a4bd29afae3dce12ef3ec14bdf3d89a606bc00000000000000001ed2433c5b3054bcb853873cc9a1cf3c5504383cba15bd3bddce2dbceae9133cdba62fbdfa2ce3bd30599dbc3e9eacb7cc11683cd1fd70bd6080833e1a54ea3e34f9aabd65faf83c00000000000000002e44b53b61850d3b134e22bbfe5b8dbbcfb6c33c29d98c3c616388bc0eb8edba0610ab3c6cd40fbdf111aebda538dfbce3ef853ce8c74fbd9d95073dccc20f3f232bb63c3857a73c0000000000000000362be2b8b140783a6724b63b513b46bc347dfeba47e9dd3c0dbc05bbfc1427bcfbeaa43cc347893b06adadbde89b27bd558c823ce29101bd951240bcfbad023fe511fc3d138443bc0000000000000000d8dfae3a297509bb38a832ba030af2394a6368bb1c4f173ba16d21bb21214d3c67a4b13b7a5a5eba342c813c9efa96bbeab4a1bae3c9d13b2d663a3e3314903e1178f53b73f4af390000000000000000bf33de3a279213bbe92194bb7b49493aef1599bb5147e53a9ec04abbb0eca13cbe26173c30f715bc41a9943cab68353bec4d9fbba1c5b43b4940b23d228db53eb97f063d87d4b5bb00000000000000008ced4c3a2912a8ba9a78bfbb864682bb75c6b6ba40671e3a1333fbba5328ee3c8c84c83baffcf6bc4569cf3c3edc0d3c0bce79bc578ce23b7f522e3dee81d03ed6ab183dc4179bbb0000000000000000a1b1e639933a1bbb24e3863b5649763b74d0d1ba3f0a373a7e2029bbe8f2033c22d7a4bcc7f9cbbc52cb223c6f87c3ba4ae49b3b363da5bc56df813ee8899c3ef135b1bca61e733b000000000000000072ca093a7b0103bba25b4cb962333c3bf35ce2bb6b02ea3ab97567bb53225f3c5efb61bcc4e5c7bc106bcb3c3c0cfebb77a826ba826a49bc6c3e3f3e00c5af3e6f8c60bba2cea23a0000000000000000a80f5f3a9c88a4bae1f1c1bbe98f4fbb845f32bcfcb5013b2795debb67530f3d4c8f32bcad9a99bc72d3253d5ac99cbb35be70bcba976cbbd610093e8416b53e56e8483cb9952d3b0000000000000000e1513d3a25b49dbbbc7ffb3bf4e5523bd9d0b13913e81e39eb2ea3bb88a8103c59380dbde5ef10bdfee2963947647d397a54103c3cee16bdb40a943ea25ca73eefca08bdae286c3b0000000000000000f91a903adf23acbb394fef3be3470f3b24fdfb39c4413c378833d8bb5c7c823cfccc12bdb95c27bd2bb91f3b85fd853a2cd02d3cf93629bd5adc823ecb31b93ed579e0bc072a91ba00000000000000001c56403a02dbc2ba08ca733a2d97983abedb4bbcf296d53a71b6adbb3384ab3ccc99c2bc4ce907bd598b123d131238bc235264bb425bbcbcc3603d3e72dabb3e2d2b243b0fd4d6ba00000000000000005d0cce3a5ef3acbb858f373c0a11eb3bfa63de3a566ebc393fd4aebb138a043c28204abd1d904cbd1d9bd8bb755befb998a43b3c9f5c57bd4acba03e923fb43e98fd42bd67c21b3c0000000000000000a5280c3b9f82e1bbc392353ca2df0d3bbd1af53bdaebd3ba382508bc4d74a53c211b47bd4b5a51bd54ff5bbc3d7e553b469f613c024675bd3d78913e9736c23e333717bdd326533b0000000000000000faa2083b8fd5a2bba8b30d3cea061eba0002923b364a71bbded114bca013d83ce61231bd3c1a4dbdb2adb73a5defd83ad9011c3cd61455bda404753e04e1c93eee45b0bc5d0626bb0000000000000000727fc33a0f9f93bb5a4f2c3c93746c3ceae3af3ae5ae8e39c97e98bb5860363c043568bde3c982bdef05e2bb3d33ddbac4f83a3c07bb81bd03eea33e8849bf3ec4df73bd3fa1893c0000000000000000e7f1453b472ccbbbaed0e23ba0b9ea3b0c534c3c17ff4dbbd41514bc5c12b13c732830bdcc0486bd3661c7bc6cf34b3b480f5f3cbe3c8cbd407f8b3e52efd23e5d3c2ebde4f5203c0000000000000000d6a5113b794b2cbbb50bb73a4284413b3c6c983cae9708bcdf9d1dbc64f3d53cc4e70bbde0b689bd4db8c5bce7891e3c9e8a4c3cf84179bd23076b3e7906df3e30f6ffbc81b8b7b90000000000000000d64c213b14f4debb3345243c03e4a83ce15e813af983143b9af1e9bb0ce8963cba0d76bd67ed91bdfd8261bc6f3e94bb6215453c176b93bd3e779f3e3c07cb3e25f380bd8323c23c0000000000000000d2f81b3bbe780bbbd4f121bb81063e3c8f3e893c21c302bb31c928bcc0f0b53cf934d8bcb1e08fbd634a42bd64fd943b0295683c999d98bd2a9c6c3e8999e73e00de02bd94674a3c000000000000000032e5943ae149b03a60c2a0bb8cfba13ac679d73c79eefbbb1c3ef8bb3c50813c57e905bccb7292bda7885abd6db87d3cc9a65b3cc99666bdd917393ec9a2f43e629895bc1e13b4bb00000000000000003d57433b1dabf4bb0c6b0c3c649ead3c8410d93b533f5c3afe1e01bc60f2963c533459bdca40a1bd524bc0bc3c07e5ba75d1533c395092bd04ad933e368bd93e03f386bd1a0bcb3c0000000000000000ba01cc3adfb2173ac53d97bb2a5fa13bc294c53ca5e796b847881abc2a6b423c80d63fbb3cde8cbdd1938ebd04dba13be1cb753ce9b082bd35fb2c3efa5f003fa656dbbcc7644f3c0000000000000000a3d6a7390fd4113bcf0ce1bab10d04bcacdcf33c016c90bb5593a8bbcd526d3bdbcb2b3c136871bdcf0d9fbd02c5873cb0905e3caa7233bdc916fd3d28a5023f261b303ae3213bbc000000000000000014a65b3b3fb202bcf3a4c63b11b6843cb630613c89b3b4b8cf7d1fbc65778e3c0d9c1fbdd0529bbdacba1ebdd9661a3b0152553cb52b7abde82d7f3e1801e63e8c096fbd87d5a53c0000000000000000b38dbc3a3fd37a3a451109bb060368bbbe6fdb3cdeab9f3b18b516bc525b953ba84b273c775167bda223b7bdbae2ae3bca155d3cf42441bd3027e13d4f48093f912c66bc795b043c00000000000000000cc223b9b7d7043b6a058e3a7ebe5abc75d3d53cdcc93b3ba50452bb3ee61bbbe2b8aa3c70393abd562db7bd5108153c407e3d3c81fe16bd998ea13deaa9083fdb49603cb9ae15bc0000000000000000aaa61f3c4de04fbc9ae48c3c5bffba3c2ad5383cced3603b8e323ebce2d1853ba0241cbd220fe0bd1c4aa7bc083d103cd4d1a33cd0e955bdc82f783ea239f13efb51b2bd553ba93c0000000000000000d9ed023ba7c21e3b07f85fbaf5061ab972ddd23c9acef53b0e7e31bc01a257bb72515e3cad3f33bdac36c8bdcaec243cb5ad413c500dd6bcedf84b3d1b1c103f4ce1dcbb17a3703b00000000000000007f4b78b98e7059396b493c3ba6685abc1920883c0a4c3e3c1c9a46b9487868bb517b823c757b91bc3514c8bd95e203bbce4e833b39dd56bc120c223cd56c113fc921b83c1dda78bb0000000000000000ba99ac3aa5031cbb37911aba32d55b39086a86bb63172a3b5df822bb6f2f4c3c534dcd3be529013a0f168e3c0eb195bb91414fba6b9bbd3bb81e363ef3d3923eefdb693bddbd833900000000000000003d47cd3a76a037bbd0a888bb8173773968f4debbfa53843bcb1629bb53be8c3c5f160b3c3971c9bb59f7ff3c264384bb972725bb4772ac3bcf09b73d44a1bb3ea0a2203c61c996bb00000000000000005a98eb3977b2d2b937d0afbbd7856a3ac2317fbb7f4e233b36b86bba7566693c589f8e3b14ab9dbb24641a3df6ae03bb12e6a3bba13e45bb9038d33cdac5df3e270d583b775764ba0000000000000000c02bf7391fb51fbb0a288b3b4b3b7a3b4f47cebac8555d3a622823bb44e0043c1146a5bcc0efccbcd853333c9072c6ba0c14953b791ea6bc83a8803ef35c9e3eca9fc2bc8461703b0000000000000000db80163a975d21bbf2e9b7396ab32b3b7daa0abccfda283b70f932bbc66f4e3c16b653bc18afd1bc44e3003dfbfc0abc131ba339677f4dbc7039383eea8db83e78099dbc3777c53a0000000000000000d2d1dc3931b2adba4808b6bb03080dbb438941bcbd316c3be43813bb35b8af3ce8ee84bb46db91bcad26683d235f2fbc96a5dbbb219c79bbaea7bd3d43e5cd3e30540cbca6d30dbb00000000000000004657553a0442a8bb77f50a3cb920403bc0ea583a2d54af387f83aabbee74163c404510bd22a311bd48acc83975f06e3ae832133cac3214bdd613933e257da83e40890dbd8fdf3e3b00000000000000007975bd3a4b13d9bb0142293cb04f2cbaabbfbd3adcd659b7fac5e5bbe235823c560115bd76a029bd69d0c23b8211ff3a50bd433c99b01ebd05c47f3e6d03be3e74b715bda3ea20bb0000000000000000207d5b3ae02b29bbede8183ac8b2803abd2e5bbcab0c353b316e6cbb360f943c78b1a3bccdc60dbdb6f53c3d221653bce5d085b9a613a1bc0df3263eaff9cc3e9976d0bcf1ebb1b90000000000000000cdb8f43ad2b1c2bb6979413c40b6ee3b23a9ca3a2fdf2b39d605c8bb7b44163c7d9d4ebd03a84abd4cb3c6bb95fbe739a25d473cdb0454bd30f49f3e751db53ed55f48bd53d7043c00000000000000008d37333b70ea09bc43be653c05aad1384d16e93bd332fcba144f19bc6097a53c0ab451bd0a514fbdeae817bcc96bbe3b5209843c920963bd628f903e479fc43e28063cbd6f62c1b90000000000000000d3ea323b1d9adbbb24ab263cb594a4ba2e16fc39570430bbbe5b14bc8caaba3c91a228bd2bca4abd07f97c3c28755c3ab527483cf37c31bd9d146a3e0e8ccf3e29fa27bdd70680bb00000000000000008e24013ba1a9aabbd112313c5f1c7f3ccd238c3978e3c5395746b8bbe45c503c466971bd1f8883bd193db8bbc14984ba0f8e413c154d7dbdd93fa33e87cac03e18d17fbd771f833c0000000000000000e22f7f3b66d103bc1aba293c6335ce3b506c273cc17a78bbe53422bcc0dda93ce24d44bdddae82bd4d6598bc7287f03b9e196e3c67b26cbda7c7883e48d2d63e6bc367bd1323d03b0000000000000000c665593b208799bb8071a63b9dddc93b59c5de3b6e0dacbb680426bc1db0ae3cd0f717bdcfe58ebda12c04ba7b1af13bbccf483c3f8535bd84df673e524ee23e0e6e75bdb58f783a0000000000000000c428a53b0f5e3fbc51f64b3ca292cb3c0df2c5bb758fa33b42383fbca25ae33c4b158bbd900b99bdcb6e6ebbf5fcffbb152b5f3cbad395bd677ba03ee51acd3e53c892bd9e77d13c00000000000000004daa7d3b7a9bcabbd0adc03916856f3ccff26e3c1692d3bbfe4722bc0f97e53c54fd24bd48de92bd35800dbd0adc433c2743123c046870bdd2d26b3eec87eb3e6ad665bd0de1373c00000000000000006172003bd0690bba28d376bbd838503c5ad32a3c8106c9bbd0aae0bbe498653c1cc594bc4ff8adbdda435fbcccae343c4f46fb3b7c610abdec433e3efd66f93e77a188bdf2d0783b0000000000000000df3caf3b36c83fbce3053e3c85d8d53c5dede6ba5ae3803b596144bcecd6d23c6be07cbd585ba8bd4fdd67bc30e272bbc7586a3cc3e98ebd688d943ef539dc3e37e79bbdfee3d33c00000000000000001c71583bb35077bbe0301dbb03654d3c1762b73cbd40ebbb376c08bc5c25863c30b5a0bcc95f9dbde67b66bd4bf2833cba11f73b38a72cbd17ca303e5681033fea3578bd18054e3c00000000000000004a19a83abffd873a9b9994bb1405f53b0dbe933c09b2f4bb036cacbb9610003c3f50a1bb9a9ea6bd2c5c0cbd02d9743cef7fcb3bf189c5bcee97113e1fcc053ffdbf7ebd342e233b000000000000000051bd123b5e85f0bb6473ef3b36379c3c19a41c3cc3871fba94b613bcc68b8b3c5a4432bd080799bdd05e21bdd810063cafc7423c451e5abd94c57b3e6942e93e450589bdf1a3933c0000000000000000d7fc203b773c08bb10bfdcba36f39f3be7f0e13cd02884bb9fe1e3bb67efed3b88f8b5bba0a78abda404a2bd414fa73cb9eac53b7ecfccbc4f4af53d86ab0c3f649058bdd821e83b00000000000000002911873a359a413a72a644bbf5b13e3a1f7ab53cee8fbbbb7ada5fbb67778b3b4e76823b1e148fbd66e058bdc0fc813c43087b3bf4258abc89f3d03da72b0c3f3b6f55bd74ffe73a00000000000000004957023c98e12fbc23fc9c3c30ff973cae835d3c7ef2443ab00734bc1cbe63ba857527bde2ffd0bd49f190bcc1b0513cb510b73ce1d54fbd55d6783ee725f13e0918b9bd8fdf793c000000000000000098dbc43aabea86ba944721ba2105c03bfae0ca3c656ce8b99da6cbbb3c25fd395f04653a25f279bd73e098bd0886ac3cb51cf73b981ca9bc31efa83daf950f3f17193fbd09b2be3b0000000000000000a534673a04256ab821490ebb8790b1ba5e947c3c39db8f38033405bb0e37323b5e28da3b061d20bd21a785bda31f263cbe3cf63a0dab3abc83d73a3dae4f0f3f0078c7bc9726253b0000000000000000e515ab3a3a6d1fbb78c61dbaeb14a03937b598bbfc91283bd3e818bb9383463ce907bc3bea05773b81598e3cf45589bb40e5d4b9097ccb3ba71e363ec3a5923edc11393a2e1b853900000000000000000926cc3a458827bb596025bbf09994bb0c9782bb351d843b9bb336bbc6d98b3ccd16ab3b7874243cd5ffff3c15a1ddbbcda687bb3d020a3cba15b73d4f63bb3e1d7ec3bbb5469039000000000000000043d7a839b770f8b90dceb7bb7d45a6ba77fe92bb311e3c3bcc2233b913466f3c050454bb7b290a3bfb812f3dc6df9fbbbcded0bb9bbc8c3b01efd43cc3b9df3e38bfabbbea1ce33a00000000000000008ae5f639361923bb5f20953ba069703b534cc6ba716a5c3af4a61fbb69d3043c1e1fa6bc8c9ec2bcbf56333c781dcebad8338b3bd646a5bc6ca8803ec45c9e3e59eeccbc16427a3b0000000000000000e168163a74fa32bb4326a23965a6c53ac2000bbc63dc283bed5e21bb06854e3ce88c4dbca50d9dbcffe1003df9ad0abc2601b73954c253bcc83b383ee18db83e55b2d1bcabcb2b3b00000000000000000824d13964e60cbbbe89debb6b6e07bb03dc38bc15a27c3b75c5a5ba6f2eaf3c19f36fbb0ab416bce1726d3d2d8848bcea67bbbbc0ff7cbbaabbbc3dd63ace3e21b396bc5181fcba0000000000000000c744553adc7faabb6833133ccddb3e3b88006f3a41c6ae38443ea8bb7f71163c3b3214bd31880dbd978dc83927fc583adef50a3cdd4410bd9613933e187da83e22a211bdd31c403b0000000000000000cd72bd3a97c4e5bbdfbc433cfbe920bbcd0fff3aaaed59b7f511d9bb9035823c83b01ebd52b715bd69d1c23b27bebd3a9641293c4a0115bd00c47f3e6503be3e58a029bd1e4e2cba0000000000000000cf86593a86e969bbd94ea6b98dfb74b997a755bc4552393bb97b27bbb38c933cd536a0bcd804d2bc0c1f3e3db47a5dbcc110083aedd0a2bc53c7263e5113cd3e4c890ebd07ec8e3a000000000000000085b4f43ab204c8bba15d473c2ad7043c6bffe739e6dd2b3995b0c2bbc543163cd90454bdc85f48bdc1b3c6bb16aaca3a5f79413c7b9d4ebd32f49f3e731db53ef5a74abdefb5ee3b0000000000000000de37333b014f19bc4609843c6364c1b9e76bbe3b1833fcba78ea09bc4197a53c830963bd21063cbd0de917bc6a16e93b3bbe653cfcb351bd618f903e479fc43e04514fbdb9a1d13800000000000000003a1b323b14c613bc8482473c3e367dbb6f82503a988e2ebb35cfdabbde50ba3c184c31bdd83328bd6b0f7e3cd352e539a3fc253cc07128bdd8066a3e4093cf3e92024bbdd57b9eba0000000000000000d025013b3c47b8bb7e8e413ce11e833c004284ba27d6c5397daaaabbab5c503c874c7dbdc2d07fbd2b41b8bbfd418c393013313cbb6871bd8d3fa33eb2cac03ef98783bd511b7f3c0000000000000000db2f7f3bdb3422bc9c196e3c0d23d03b7987f03bcb7a78bb5fd103bcb6dda93c65b26cbd6ac367bd4f6598bc536c273c17ba293ce04d44bda7c7883e48d2d63eddae82bd5f35ce3b00000000000000000bea583bf9ac25bccb48483c308a803a0c35f03bb893abbb1b2e99bb6c82ae3ce86635bd9a9175bd91eef4b996c8dd3b0aa5a53bffd717bd82d7673e7952e23e03f88ebdd40acb3b0000000000000000ab28a53b43383fbc342b5f3c9677d13ceffcffbb748fa33be05d3fbc715ae33cb6d395bd54c892bd9e6e6ebb10f2c5bb3cf64b3c44158bbd667ba03ee61acd3e930b99bda592cb3c00000000000000004daa7d3bfe4722bc2743123c0de1373c0adc433c1692d3bb7a9bcabb0f97e53c046870bd6ad665bd35800dbdcff26e3cd0adc03954fd24bdd2d26b3eec87eb3e48de92bd16856f3c00000000000000009645003bec52e0bbfb76fa3bd87e7b3bd7f1333cd748c8bbe2fa0abafb77653c6b4a0abd57b788bd3a535ebc54372a3cfa6e77bbf8a094bce13c3e3e646bf93ebc0baebd7da8503c0000000000000000df3caf3b596144bcc7586a3cfee3d33c30e272bb5ae3803b36c83fbcecd6d23cc3e98ebd37e79bbd4fdd67bc5dede6bae3053e3c6be07cbd688d943ef539dc3e585ba8bd85d8d53c00000000000000001c71583b376c08bcba11f73b18054e3c4bf2833cbd40ebbbb35077bb5c25863c38a72cbdea3578bde67b66bd1762b73ce0301dbb30b5a0bc17ca303e5681033fc95f9dbd03654d3c00000000000000002707a83af45aacbba257cb3b49a0233b7eb7743cf68ef4bb39ff873ad30e003ca984c5bcc8c67ebdbc520cbd43b2933ce6a594bb8b3da1bb0997113e6ecc053f2da1a6bde727f53b000000000000000051bd123b94b613bcafc7423cf1a3933cd810063cc3871fba5e85f0bbc68b8b3c451e5abd450589bdd05e21bd19a41c3c6473ef3b5a4432bd94c57b3e6942e93e080799bd36379c3c0000000000000000d7fc203b9fe1e3bbb9eac53bd821e83b414fa73cd02884bb773c08bb67efed3b7ecfccbc649058bda404a2bde7f0e13c10bfdcba88f8b5bb4f4af53d86ab0c3fa0a78abd36f39f3b00000000000000009904873a44cf5fbb01ef7a3b505be83a77f5813c0d80bbbbd4a8413a66778b3bf2248abc4d7155bd02dd58bd9275b53c62b044bb457d823bd9f2d03dc42b0c3f01158fbd7a0b3f3a0000000000000000e35d023c361034bc3711b73c0bd7793cfab7513cd02f443ad2e92fbca44063ba68d44fbdb217b9bd09ed90bcb88b5d3c12fd9c3c747427bdc9d5783ed825f13ea2ffd0bd3cfb973c000000000000000098dbc43a9da6cbbbb51cf73b09b2be3b0886ac3c656ce8b9abea86ba3c25fd39981ca9bc17193fbd73e098bdfae0ca3c944721ba5f04653a31efa83daf950f3f25f279bd2105c03b0000000000000000f13d673a433005bb8322f63aea35253b1318263c33a49238bd6e6bb87539323b8bab3abccc79c7bc8ca685bd9a907c3cec490ebbc32cda3bb2d63a3dbe4f0f3f4d1d20bd2380b1ba0000000000000000d8dfae3aa16d21bbeab4a1ba74f4af399efa96bb1c4f173b297509bb21214d3ce3c9d13b1178f53b352c813c4a6368bb38a832ba67a4b13b2d663a3e3314903e7b5a5eba030af2390000000000000000b833de3abac04abbe84d9fbb8ad4b5bb5568353b5c47e53a189213bbafeca13cbac5b43bbb7f063d42a9943c081699bbe12194bbbd26173c4a40b23d228db53e2ff715bc4449493a00000000000000008ced4c3a1333fbba0bce79bcc4179bbb3edc0d3c40671e3a2912a8ba5328ee3c578ce23bd6ab183d4569cf3c75c6b6ba9a78bfbb8d84c83b7f522e3dee81d03eaefcf6bc864682bb0000000000000000a1b1e6397d2029bb4ae49b3ba71e733b7487c3ba410a373a943a1bbbe8f2033c373da5bcf135b1bc51cb223c76d0d1ba26e3863b22d7a4bc56df813ee8899c3ec7f9cbbc5549763b000000000000000072ca093ab97567bb77a826baa2cea23a3c0cfebb6b02ea3a7b0103bb53225f3c826a49bc6f8c60bb106bcb3cf35ce2bba25b4cb95efb61bc6c3e3f3e00c5af3ec4e5c7bc62333c3b0000000000000000a80f5f3a2795debb35be70bcb8952d3b5ac99cbbfcb5013b9b88a4ba67530f3db9976cbb56e8483c72d3253d845f32bce1f1c1bb4c8f32bcd610093e8416b53ead9a99bce98f4fbb0000000000000000db513d3aeb2ea3bb7a54103cac286c3b9c647d3906e81e3920b49dbb88a8103c3eee16bdedca08bd7ae29639d9d0b139bb7ffb3b57380dbdb30a943ea25ca73ee5ef10bdefe5523b0000000000000000f91a903a8833d8bb2cd02d3c072a91ba85fd853ac5413c37df23acbb5c7c823cf93629bdd579e0bc2bb91f3b24fdfb39394fef3bfccc12bd5adc823ecb31b93eb95c27bde3470f3b00000000000000003b56403a61b6adbb895264bb40d3d6ba121238bcb096d53a41dbc2ba4284ab3c475bbcbc502b243b518b123dbfdb4bbc5fc9733ad699c2bcc2603d3e73dabb3e46e907bd5d97983a00000000000000005e0cce3a40d4aebb98a43b3c67c21b3c765befb9596ebc395ef3acbb138a043c9f5c57bd98fd42bd1d9bd8bbfa63de3a858f373c28204abd4acba03e923fb43e1d904cbd0a11eb3b0000000000000000a5280c3b382508bc469f613cd326533b3d7e553bdaebd3ba9f82e1bb4d74a53c024675bd333717bd54ff5bbcbd1af53bc392353c211b47bd3d78913e9736c23e4b5a51bda2df0d3b0000000000000000faa2083bded114bcd9011c3c5e0626bb5defd83a364a71bb8fd5a2bba013d83cd61455bdee45b0bcb2adb73a0002923ba8b30d3ce61231bda404753e04e1c93e3c1a4dbdea061eba0000000000000000727fc33ac97e98bbc4f83a3c3fa1893c3d33ddbae5ae8e390f9f93bb5860363c07bb81bdc4df73bdef05e2bbeae3af3a5a4f2c3c043568bd03eea33e8849bf3ee3c982bd93746c3c0000000000000000e7f1453bd41514bc480f5f3ce4f5203c6cf34b3b17ff4dbb472ccbbb5c12b13cbe3c8cbd5d3c2ebd3661c7bc0c534c3caed0e23b732830bd407f8b3e52efd23ecc0486bda0b9ea3b0000000000000000d5a5113bdc9d1dbc9a8a4c3c50b8b7b9ea891e3cb19708bc824b2cbb65f3d53cf84179bd34f6ffbc4eb8c5bc3d6c983cb50bb73ac4e70bbd23076b3e7906df3edfb689bd3d84413b0000000000000000a14c213b7af1e9bb5c15453c8423c23c703e94bbfb83143b08f4debb09e8963c176b93bd25f380bdfe8261bce65e813a3845243cbb0d76bd3e779f3e3c07cb3e66ed91bd01e4a83c0000000000000000d2f81b3b31c928bc0295683c94674a3c64fd943b21c302bbbe780bbbc0f0b53c999d98bd00de02bd634a42bd8f3e893cd4f121bbf934d8bc2a9c6c3e8999e73eb1e08fbd81063e3c000000000000000032e5943a1c3ef8bbc9a65b3c1e13b4bb6db87d3c79eefbbbe149b03a3c50813cc99666bd629895bca7885abdc679d73c60c2a0bb57e905bcd917393ec9a2f43ecb7292bd8cfba13a00000000000000003d57433bfe1e01bc75d1533c1a0bcb3c3c07e5ba533f5c3a1dabf4bb60f2963c395092bd03f386bd524bc0bc8410d93b0c6b0c3c533459bd04ad933e368bd93eca40a1bd649ead3c0000000000000000ba01cc3a47881abce1cb753cc7644f3c04dba13ba5e796b8dfb2173a2a6b423ce9b082bda656dbbcd1938ebdc294c53cc53d97bb80d63fbb35fb2c3efa5f003f3cde8cbd2a5fa13b0000000000000000a3d6a7395593a8bbb0905e3ce3213bbc02c5873c016c90bb0fd4113bcd526d3baa7233bd261b303acf0d9fbdacdcf33ccf0ce1badbcb2b3cc916fd3d28a5023f136871bdb10d04bc0000000000000000c4a55b3bbc7d1fbcfe51553c85d5a53cdd661a3b0eafb4b835b202bc62778e3cb72b7abd90096fbda5ba1ebd9c30613c19a5c63b179c1fbdea2d7f3e1801e63ed2529bbd18b6843c0000000000000000b38dbc3a18b516bcca155d3c795b043cbae2ae3bdeab9f3b3fd37a3a525b953bf42441bd912c66bca223b7bdbe6fdb3c451109bba84b273c3027e13d4f48093f775167bd060368bb00000000000000000cc223b9a50452bb407e3d3cb9ae15bc5108153cdcc93b3bb7d7043b3ee61bbb81fe16bddb49603c562db7bd75d3d53c6a058e3ae2b8aa3c998ea13deaa9083f70393abd7ebe5abc0000000000000000aaa61f3c8e323ebcd4d1a33c553ba93c083d103cced3603b4de04fbce2d1853bd0e955bdfb51b2bd1c4aa7bc2ad5383c9ae48c3ca0241cbdc82f783ea239f13e220fe0bd5bffba3c0000000000000000d9ed023b0e7e31bcb5ad413c17a3703bcaec243c9acef53ba7c21e3b01a257bb500dd6bc4ce1dcbbac36c8bd72ddd23c07f85fba72515e3cedf84b3d1b1c103fad3f33bdf5061ab900000000000000007f4b78b91c9a46b9ce4e833b1dda78bb95e203bb0a4c3e3c8e705939487868bb39dd56bcc921b83c3514c8bd1920883c6b493c3b517b823c120c223cd56c113f757b91bca6685abc0000000000000000bfa99d3a9ffa28bbae0e0f39afad063a3e1988bb3a2b063b4fc90ebb6e8a473c0cfde73b2654653c410e663c296e48bbc40a78ba400ea13bf1e53e3ee7a98a3e0291cdba22b3923a00000000000000007b81d83a71935ebb9445c2bbae1c8cbbbe89e43a93fe873af2d529bbb0dfa73ce84db53b52289c3d46d5313b5c53e4babae708bb1fc02b3c8f5dac3d7a7da43e08f87dbbd36bbcba000000000000000008d02d3a74d2abbae5f83fbc7eb0213b80761dbbf51c043ac671f9ba1b47c93c9cfda0bb0d15ff3df813ce3ce4dc95bb4d9a0abb9d537fbb02a0273d6d5bab3e5841b5bcfd9abc3a00000000000000003371d439bf8524bb82009a3bb3ed813b7fc2cababe5a2a3a035015bb9de5023ce36d9fbcf98a9cbc9ba4103c9e1ad5ba3f7a6e3b287da5bc7cb3833e1867993ec154c5bc322c793b000000000000000004f3e8393d5c92bb16f805bb04a40a3ba889f8bb4283a03aa969aebabed25f3c41ea0ebc97ce713cb9778c3c28e4b7bbed8590b929d562bc8cd2443e9c99a33e9b5f9fbc1614133b000000000000000013985b3a7628f5bb9d7595bc12c5283c9d9278bbf734963a47b4b1ba15ddf73c7bd19ab9700a8f3d46cbed3c6ab443bc280800bbfc513abcbb71103e82dc923e758740bc25a292ba0000000000000000a0a1333a94fb9abbc66d063ceaee9b3b01feb2b906ff53391f7490bb97e8043ca3ce14bd909f05bdb4f42039c3121ab9e9bcda3b9e030bbde96c953e1c86a53eea0910bd8830763b0000000000000000163e3c3a9e20c8bbd80ff43bcd6e013b5bab62ba9c5b843939036ebb0d12773c973622bdd6789dbc7bc071b94e919eb9d701983bd01d0ebd0115853e5efbb23eeda31fbd43c2833b0000000000000000c58db8393f90d9bb36a00abc8b55133ba8e10cbc077fa63addd5353a068ca23c7362a7bcc338013dce7c823c62ad2dbcc3ae81ba84bbbdbc35a6453ee302ad3e72f9e1bc4c826f3b0000000000000000ffd0b23a931da0bb3a232c3ce256363c6ed6c6ba8ff98339de8c93bb041bf23b9cb159bdebea3bbd2bd9e1bbaea6023b3d63273c550447bdffdea13e9171b23e9fbc4abd37e4f13b000000000000000094aac93afe31dabb8bec0a3c29ed1b3c53d366bab1cc7aba0503bdbb2e05a53c406f77bdab57ecbc23b989bc5455f33bab860b3c60523ebde551923e76d2bd3ec6fa47bdcbc6633b000000000000000000c4913ac3fc34bcdb32a739a112223cdf41003a278335bbaecd92baa35a0d3d964a52bd2f0a0abc303cacbc7825d73bfe79013bb2284abdbcf16e3e47b0c73ea41616bdf260653b0000000000000000c4b3993ace686fbbaa502d3c7f68913c9ce93bbb1b08c03988aa82bbeec5203c040584bd360e68bdeb6fe6bb79eddf3aa911273c849c63bdaed6a53efb71bc3ea56481bd2a17633c000000000000000021b0123b9e46d2bb097cf83bfd6e9f3c5dfcbcbbe4d16cbab2afc2bb2b07ba3c2bb29ebd65fbe4bc650ce6bcb835503c6b5fab3b750022bda3388f3ec193cb3eba4b7fbdd79fea3b0000000000000000823fb23a3cf8e2bbf3a46539f4148b3cf7ae17bbdb85a5bb0deb14bbf210093dde0791bd115cfbbb95b22bbd9a04bc3ce79210bbdce807bd5842693eb185d83e04dc5bbda780c4390000000000000000b84de03a76c3bebb8c5f363cafd2cc3c4a97d1bbcb21113b7b43b2bb059d843cf0a097bd259a71bdc69561bc3af61d3b1b9f1e3c71d16cbdbbeba13eec3ec73e20d38fbd9098993c00000000000000009454063b15fa1bbc35d3213c7fe2e63cffbf56bc4ecb8d3bb7200bbbbd3cd23c1b3cc1bd9d6938bca0414bbd1e0f663c0ab06ebb9ae3babc2d037a3e868edc3ef9d97fbd310f213c0000000000000000feef723aec63dcbbaf66ee3b2cd5503cee881ebc41efe63a183bcb3912adba3c1d4dadbd25caf03c55f68bbd9a81d53cbc807cbba30a4dbb9ff53c3e36b0e43e680446bdb37600bc0000000000000000174b223b3c47e8bb0ca4493c3b36e03cfa6dd1bb8c700e3b811cddbb8545903cd12e9cbd758776bdb3e4b7bc125eef3b543e0d3c2c2456bd4d57983ed5ded33e09339ebdba399f3c00000000000000005c680f3b5ef344bc096b7b3c0c90fd3cc247a9bc21192a3cfbf43d3a1bcd953c9700c6bd6664b93b58d88cbdecd9883cb9c1cebb0f300b3b9c793a3e2e34f23e9fe861bd2811083b00000000000000009a40ce383eddd2bb981b893ca7cf06bb811089bcc04d343c54df1b3b67a5de3b5376a8bdca67a33d12fdb7bd3c83923c960f31398ffa8c3c1c5dfd3d40b3eb3e88b5c9bc3a7168bc0000000000000000817c573bb1e914bc270e493c025ad13c3b87b2bb654eb13a48df04bc60df903c7a428ebd167054bddc4610bd87dc7d3c665ec63b06fe1bbd0e99853e7066df3ef7d39bbda30e6c3c0000000000000000f491393b540964bc418d9a3c9270db3c7b91d9bc77ee853c96db953a3baf183c8a8bacbda773bf3cdfd7a4bdcf6e8b3c7e4e52bb4b3b923ce9dbef3d7e1a023ff5a634bdfed5cfbb0000000000000000e16f01ba5010bfbbded6b13c8ca606bc94c3dbbc1c3aac3c47216f3b527938bb0a15a4bdc04bdf3db88fbdbd63cda73b2452ce3a54cde33c2aafae3dce12ef3ecbe74abcdf6d53bc00000000000000001ed2433cddce2dbccc11683c65faf83c3e9eacb7ba15bd3b5b3054bceae9133cd1fd70bd34f9aabd30599dbc5504383cb853873cdba62fbd6080833e1a54ea3efa2ce3bdc9a1cf3c00000000000000002e44b53b616388bce3ef853c3857a73ca538dfbc29d98c3c61850d3b0eb8edbae8c74fbd232bb63cf111aebdcfb6c33c134e22bb0610ab3c9d95073dccc20f3f6cd40fbdfe5b8dbb0000000000000000362be2b80dbc05bb558c823c138443bce89b27bd47e9dd3cb140783afc1427bce29101bde511fc3d06adadbd347dfeba6724b63bfbeaa43c951240bcfbad023fc347893b513b46bc00000000000000004054a53a517e60bbc383603a3229073bb70fadbbdfe8df3a975605bbc031433ce660063c9a0e8a3c4cc84b3caf2f22bbe971fdb8fbbaa83b3d02483efb67833e7d3c8539d56e2e3a0000000000000000796fcf3a38bbabbb5300a3bb62c00b3c0ea489bcd1a5ed3ad9a06fbad07a833cc680d23bf827063e29af5dbaaed42bbbb893163a2ed2643c2a8ea83de1d5863ea1daf13b82f5cfba0000000000000000947d78393f4e82bb51824abc1533963c0155e5bbea39c7383e20a939dcecc63c64cf583bfaa0693e7b3669bb7df528bb9d9ca6ba057c183b7bc2253d250f5a3e8a92223b592811bb00000000000000002d86ba3970662bbb5b95993ba83f933bb6c6e9ba1eeb023a1bc8fdba039ffd3b38bb97bc16858ebc1f4e003cf215c9ba5992613bf6eca4bc4cce853e3df4953e11f3bcbc2ab8733b00000000000000001505d33950bdbcbb264ebcba04e48b3b2aed0fbc45635f3ae07a73ba1f9b363cf960c5ba21ccdf3c39ef3a3c1ca68ebb07ea9538253d44bcd70e4c3ef431953eea4752bcaeb5bc3a00000000000000008bf0303a45622bbca48758bc41f9853cdc6966bc6250253ae68955ba00caa93c39180a3cc0e3093ed05b973cd5d41dbcb1f95b3a6de73abbebd2063e23705e3e3df6683b99a50fbb00000000000000006ba20b3af0a48ebb7e4c023cd8ddbc3b5c71a3ba2ade4339a03b77bb4301e73b0cca12bdbd1a01bdd983083a333706bab270c03b09b308bdfc0d973e41fba23e58570ebd6383873b0000000000000000982dd33931aec7bbf49fa13b40f0af3b765834bb3897ce39ecb111bb9e12553c66d80cbdbfcc5fbcbe4a0fbbb9cd70ba0762423b7e6607bd83b7873ebdd7aa3ee2eb0fbd798f963b0000000000000000e7e0d6b7a34e1dbca1eb42bc86251d3c8c0c20bc66ccb23a2ee34d3b8b1a8e3ce5112cbc00684e3d80fbdeba860515bc10116fbbff30b7bca4554c3eab7d9d3e036685bcb87dc13b0000000000000000ce4c903a680089bb63c0233cb17f463ce71622bb8e7aea39564777bb83b6bc3b4e3c56bd4c393abd178acabbbc99b63acb291c3c2d6243bdc047a33e9a26b03e5f3c47bdd958f33b000000000000000047e4853ae8449ebbb891533b32bb773cef1f90bb3167edb976ac95bb6aa08d3ce63d64bd1642c7bc701c87bc4136b53bdbe3c73bfdae32bd5266943efa42b63e904e36bd8c969d3b0000000000000000e4424fb9fd4059bc83dc1abc33e5bd3c4517743752a68639a7a47b3b0e60213d98892abd586e26bb231320bdc8caa0ba2f5505bc914065bdda876f3eda2cbf3e90bf90bc0c9a783c0000000000000000c50c793a29204fbb9d1d2d3cabfe943c235f6ebb0ac9ef390ac067bb37b90d3ca37f84bd5a4064bdeda1babb73a9b43a75a8263c5dd561bd5bcca73ea080b93e38e27dbd74bd573c00000000000000004c8ed63a664150bb831784b934e1f13c20b954bce9dd27397a14c6bbe3eaae3c9a4ba0bde632b5bc37e1d0bc9ac72f3c8e17af3b0fe121bd5d3b953edf4dc13ed0d869bd36b9eb3b0000000000000000cd38473a67c480bb026f69bc5e6b293d9379a7bce479c8b787ffe6bae75c093d097f9abd57d8243c1a6638bddd99873c94cfaebba16cf5bcd098753ede38c73ec4f51ebdb09f753b00000000000000000e15a43a2e8298bb442f243cc5f4cd3cbb13f0bb37c7e93ad14996bb87d9693cd32496bd18246ebd05d11ebc35f10f3bea59243cc8456bbde38ba53eda24c23e57748dbdfd4a8b3c0000000000000000f790173bb492dcbb41a3803adc712f3d8a1dc9bce684c73be2069ebb937eea3c7302d0bda40b1fbcf14c1dbd7183253c565579bae801e2bcdf36893e5fe8ce3eeed36ebdddd81c3c00000000000000000870843abf4a87bb229f09bc74fd5b3d9e5c49bd093b453c708087ba6bd6cb3ccf9fdcbddb775e3d13c04cbdef39353cbad768bb9893293b6e2f583e9788c73e6920f1bc46aee5bb00000000000000002f5e113b343ccdbb2a18493c2eb4ea3c79ff1cbcbf8f4d3b29f8b9bb1863703c013e9fbd53f974bd4c3d88bcbcfba73ba34e163c711a59bd4c009f3e59dfcc3e18209cbdeab99b3c0000000000000000277f743b8cf63ebc0457123c65274e3d84ac1fbd2397743c2a9439bbf474e33c7edaf4bd8fa2fe3bc81b43bd11d0063c3ec3c3bb4926abbb0494633e56dedf3e1bd763bd1fc0ce3b00000000000000006867113a08e5f6bb6cfb033c96d7503da64395bd4767c83c86c3fd3a608b6c3c1bfe01bee8a8e53d18f756bd5163a8bb8d65d0ba6e4aa13c30551f3e0f9ec73e2c5cc4baf25b1ebc00000000000000001e2d193b947cf4bba3c6383ce22be83c90662bbc98ad673bb5a2cdbb6a2e733cde5a94bd548750bd67afe2bc7ca5423c8218d93bb76126bd17be8e3e773ed63e52559abdbbb3773c0000000000000000f302d53ba11389bcaaba8b3c7c593d3d052342bd05a6ae3c58187bbb6cc0bc3c815cf4bd1324c33c0bc250bd2435253c5b649abba3374b3c122e2a3e3ab6f13e75685fbd6c6aa2ba00000000000000001e7ec939efb424bcd8fdc03c54ea333d950fb0bd3b56113d1711833bc065d93bb97910be7211153e6b1d3ebdbe509fbc8b2328ba11ece93cb31dfa3d7b76c93e0cccf23b1862f6bb0000000000000000c513493c7e5859bc3b617c3c40b00e3d45f4c2bbad87c63bad322ebc96455e3c2f218fbd2633a1bd7c2471bcc046413c7fb68e3cffdd51bd043b913eca0fde3e0ec3e0bdf547d03c00000000000000008277173c11f8b7bc42acc23ce428e23c820150bd38e7be3cd6a1b4ba56083b3cdd4dbbbdc10ac23c4bbc1ebdadf0c33c204ca3bbe8e3843c85f0a33dcc18093f59af88bd9de6ec3a0000000000000000ef30ee3a05355fbcc569233daa86503ca148bfbdf389343da3db6b3b6e3624bb0bf4e6bdd5d4503ef8d209bd0928cbbc5b44623a7b83e93c3104033dfdbcd23e13b3f43b41a2bbbb0000000000000000c907a43a7cab89bb8141703aa9a6443bf3dfbbbb48a6ca3aa5b0fbbaca0e483c9586273c9146903cad473b3c42acedbac056b2b56afca43b530b533e0ccf773e7ecbc33a09ba5e3a000000000000000085f9a73aebca0bbc6285163b55ceed3c75f29abcf336c13a60a9c138e0042c3cb8f3c73b12a4d93d8b863a3a94ff57bb4be4be3ac2588c3c5ec0e73ddbab663ec592893ccc3857ba0000000000000000e3953239d73d81bb7f4833bc7314f33d8463d7bc0df6d5b7c8e5df39ffe1be3bcd670ab980702a3e06a3ed3ba9a4dcbb2888663b30fd183c6368883de1a10c3e05e1eb3c416d703b00000000000000006c12a73953bc27bbd4439b3b0bd29e3b755306bb0816eb390ef3f5ba4a9cf93b518f8fbcc05085bcaa46f33ba48cccba97c4523bfe25a5bce35d883e1e11923ed473b2bce0a2683b000000000000000019f2a63931a4ecbbe102a73a89dcf53b0ab616bcc24b0b3a72ef31ba5eaef63b7fcff63b1ce5dc3c8a09ef3b25b436bb1b90043a97de0cbca4d0583e1896873e54360cbcbf4f883a0000000000000000918cab3989c95dbcac9ef5bb1b57633dd7bec3bc9f285b3980e7afba9f9b3c3cbf48b63cd7b7bc3d5c98cb3bcf8fe5bb4f42983a46d8513c3ed1143e6ee0423e5764783c2ec9b3390000000000000000a28ee339593b81bbc18ff73b9e08e63bd0b41bbb6cd88639feee3ebbf5a2b73b77c10dbd5cbe01bde664c33a53fe8fba0ce0a63be31107bd46ea983e1a46a03e6b080bbda7aa8f3b0000000000000000925572397e1acfbb433a923b2c13023c85cda0bbe7cb8f392499b6ba9edb143c4d1cd8bc59783bbc5a05c6ba8a536eba6592123bc4e4fabc095f8b3eee28a13eb94903bdd12e8e3b00000000000000001d7326b8c4823ebc1bb10fbc1a37903c89f95ebcb2a1463a8b1e133b35a5053c9e83813b84513b3d2c3208bcb86fb2bb6273deba2a457cbcd6ca5c3e98cf8d3e70c728bc1c57883b0000000000000000e3fb7b3ab66c6dbb8ea0253ca600473cd4aa3fbba750123ade503fbbef085b3b30b44ebdf3603abd175f94bb48c49d3993520e3ca8fd3fbda836a53e96f2ac3e0f0243bd59ec003c0000000000000000e843243acb2984bba114ea3a3951873ccd0ed2bbc33492b99b8f4ebb36e02f3c1e903dbd804bc0bce12e3fbcca11403b6c63a23b8b3d23bd63c7973eb040ac3e577924bd57e39f3b00000000000000009b42b0b98e110abc64c844bcc638de3ceb5c19bccb30a639df5def3a943eb13cc55cedbc4802fc3baf2bd4bcfbe90bbbed8661bbb09925bd48ad803eb3bba93e478fb0bcf97e363c00000000000000007f063d3a06e30abbdae12d3ce93b8e3c41366abb9d4d303a10cc47bb0849d83b2b4f81bd37b867bd9d1e38bb44878f39b18b2d3c924463bd5c89aa3eb89bb53e22a275bd3038463c0000000000000000b8f54b3a3ca425bab2ff42bb7ea6ee3cbf1148bcfdca85b91efb94bbb96c6f3c5dc98bbdc632d8bc1e928cbc4fd6d23bf576c73bf49a2abd02ae9c3e6025b63e66b856bdf7dbfb3b000000000000000011372c3a4da54e3bccc003bd1a01823d8b2503bd231cbeba05e26dbb3c06d63cf23190bd8448783cc667fabc641b173c24be0fbbcf5ac5bc8eff853e7d71b13e6a9b11bdb97fc43b00000000000000001c76abb9e13bd7ba118d073c8497a43cb53092bba65f94b8d0af31bbd8ad4b3c2bcf8bbdb7606cbd978f1cbb36c4f13a5b3b1c3c0c296cbdff00a93e2ad9ba3e00be86bd9981623c000000000000000098c97a3a5f1ae9ba97c260bbbff51c3d407699bcfa661e3b1637a8bbedf4c33c57afb7bd8f9bb0bc6886bdbc4ee9e13b7980483b576417bd0f85973ee743c13ed3c971bd8c982b3c00000000000000009d25c53a8eb1913bab813abdff44d03d902d84bd6fc0113c189c9cbbd05b0e3d0f23e1bd8883253dfb750dbd2297a33b5c6952bba9a692bb23fa763e1ab4b43e54e1b3bccf92f3ba0000000000000000aa6eeb3a0f73c1bb14f5533c0ef2e43caa4331bc1fb9553b11ab88bbb574373cf6fa9bbdaaf07cbdd1a420bcf95f383b73d42e3c183167bd4fcba63e2a65c43eb43c94bd2b0b8f3c00000000000000006076ea3a9a36b0bbb1ba953b8bfd343d4659f6bc4c4e233c33ca9ebb0d1ce93c49deeabda499efbb9ec1fcbc4627ac3be14002bbbe3bb1bc784e8a3e9eb2ce3ebfea81bdeff3463c0000000000000000245a163b91bc00b9cd3e0cbdfa1bf03d09ebc6bd4457d03ca00d66bbb6060b3de6e217bed609ad3da755e5bc4cc434bc9ca14fbbbe426e3c5b194e3e363db53e929a6fba7367ddbb0000000000000000af206d3ab360cfbb71ba4e3cda45e13c608c46bca8da8f3be37258bb0131203c1f3294bd36df5abd4e869bbcda23ed3bddac013cbe7f39bd948b9a3e587aca3e28e491bd49617c3c0000000000000000034b823bc4c735bc3e4b733c45081a3dca0c15bd96e28c3c1f7401bcdd09fd3c13adffbd614e383c9f2a17bddec3fc3b873546bbee47c4bb6e006d3e8cd9dc3e92a88dbd8e24143c00000000000000000efc523b7574a3bb4f4316bc3e37df3d9b68dfbd49b2243d7c0b15bb4138f03c26063cbeb6f3e13d31b9b4bc525bc6bc9091a5bb1503023d24a8283ebc7ec33eac837dbb07f8c4bb0000000000000000ab6a0e3c316e88bcc7d0a73cd6010a3db8a30ebc61c8743b0dd1b8bb81069a3c36aca4bd6f6691bd21c20abc64a7283cf38f843c502182bd7d89a13e56fdce3e4e3fd4bd3928d83c00000000000000008bea323c9b61bfbce7990c3da12d093c5c3022bd3952b73cf4ad30bc76b5a13c0f2bebbd4698243dd5ba03bd1380b73c121b0c3ceb0437bc2b08323e9d7eee3ec422acbdb42f1a3c0000000000000000e356b53b84dea9bcb681173d91bd263d0872cbbd2075633d27f72bbb542ae43cb38a5abe77c55a3ec32caebcdd59f2bc24b214bcac824b3d30a66e3da337dc3e58d79abc91725dbb0000000000000000b0c8b23a21029dbbf9aeda3af036413bcc13b8bb7996bd3ad4d102bb84e83d3c84ee563c2192813c6c2a3e3cc338f3bae9c4aa38d0fc933b6fcd5e3ef2486a3e8a783b3bfd91633a0000000000000000f561693acf3e02bc31cf263c3985bf3ca12e59bc23e9633a14e6debaa5304c3cb09c9f3c2cae663d1f91133c9e2c29bb10e47a3ae9488b3c60cf1d3e9b30503ea571883cf202613a000000000000000003550c3a6bdf2bbc4335f7bb7291143e70cebbbbe034adb86c591c3bacb210bc2279e0bb5f341a3ece3278bc5c71cebb0ea89a3bee8b203d8e13323d0d4af13d60525e3d51c73d3b00000000000000008a4dbd3984ce2fbbb782a13bea14a53b3fd71bbb9d70c439cdc3e1ba72c1f53b51b186bcac9f82bc571feb3b1ce0c8ba9c615a3b2999a6bcd71d8b3eea6f8e3e7e74abbc2c825b3b00000000000000009e7a90396e130ebcf0f3a83be2d1f93b14ae13bcbd58a639c82673ba4884a73bdb96803c092bbc3c42b7993bc213ceba2aa1773af7f4cfbb0e88673e3fab783e2f6bcabb35c97f3a00000000000000005c9bcf387e1083bc3d6c923c5d1d543d62a59fbc13c3fc37688fb9ba3d0c0eba5cded83ce4ca5d3d9d825fb9ab3256bb5739fa3a530a9c3c70012a3e9f81393e5363a63cde87073b000000000000000026eec739ca587ebb1d69fc3bbc4def3b933755bbc114a039464217bb90c0893b28bb06bdd5da02bd39733d3ba27ee0baddc49b3b2f6107bd16f39a3e698c9d3eb79108bd4b7a933b000000000000000083c52639930ee7bb255fd33b5d24093c3bf7d7bbdce63539d96f8bba9465993b5e2396bcd02c51bca833743ab62e75ba3bee353b6455ecbc896d903ea18e973e7a61f2bc459e673b0000000000000000179792372b016bbc9bbd913bb7cd933c31ab85bc1c6ea038f59deb3925913bbb59d4b43cc6881f3d88d914bc0adaaeba1549833a765008bc9fdd673e652b7c3e1f6beebbf080ea3a0000000000000000d2053d3aa6a144bbf0ac2d3c9dda3c3ce4ca4abbc2832c3a3d4df3ba8724053a10e146bdd9e13dbd17861cbbe62c3bba9b95063cbd363fbd547fa73e94f0a93e41f33ebdb1c7023c0000000000000000a0757939924bacbb6177c13b0f06553c827fe1bb7cb2fab7403f9aba68c1233b55240ebd19c7d5bca8a0a2bbb3ba2c3aeda28c3b62de15bd52e19b3e8c5ea23ed2f516bd41758f3b0000000000000000ba0f44b9f70e1fbcb02bce3a9affb33cba7082bc21b380b92e79e43971b466ba22c9f1bb89cf033cf2601fbcad68e3b85f21193b7c4fc0bc7202883ef3c2923e3799bbbc40897e3b00000000000000001e5b023adebeb9ba7cb3403c40a06f3cb52b07bbd2558039ea1309bb967f6c3b2d4376bd12816dbde651833aefc6ddb9e870303cdbf962bda56aad3e990fb13efc656dbd76072b3c00000000000000000efcceb7a863daba57027b3b814e9c3ccf38ebbb8c56abb9824fc6ba10b8503bd5a051bd3a9f12bded4d06bcd0730f3bf5f4d83b0ebf31bdc36fa33eb038ab3e7fa43cbdd1bfde3b000000000000000074767fb9accb07bbbfa98abcece6433dce76d6bc025e5aba791a8cb9b0999f3b3c4d06bdbfde5b3bbe907dbc247dec3a84d82b3b929fc0bccf398e3e96239a3e3fdbcebc8fc28a3b0000000000000000e3f685bb286f9c3b8ae9d43aa985ef3bef39503bfd8b8dbb7e99d4b713b1933c29fe6abd61dc60bd380b683c0d59df3a01eabc3b9b316abd2ed9a93e51beaf3e920279bd5206ea3b000000000000000090e17abaef44a6b90d27443aba85b03c46c307bc666855ba43ffbdbab42e4c3c70e081bdbb5f18bd98e399bba4a94d3bfe87b93bfd433cbd1b12a33ecadeb13e633a5ebd1460013c0000000000000000613b03b958c7c63bb02945bd33a5ba3da94b3ebdb6d72a3a6f7d85ba15c0963ccbd88abd9a1e823c0541c6bce1dd093b697de53ad6f999bcc7968d3e68d2a03eb6f6cabca8ec983b0000000000000000968fffb6165276bb17a9683c4b0ead3cb6c3d7bb092f4a3a84e0b1baa5d9e63b563891bd7c5a85bd2d8bfab9ee3d9f3aaf003d3ccd6176bd442faf3e49a8b93e624c87bd0d78613c0000000000000000607e26ba88be01bbf9c0e23bac08e33c254359bca210093bef62daba5eda393c3c89a6bd80750dbdcd355bbcbe46453b155fab3b664721bd0feaa03e9011b93e2b0465bd93e5233c0000000000000000a34e1a3a82113e3c82ef92bdbbb30b3e94faa1bd36b9333cf24b1dbbc83b113d4c90fcbd50c6533d10cafabc73e65dbba0e0dab804b563bb66fe843e78a0a73e215fb8bca716343b0000000000000000581c9f3ae32db9bbdf51733cfe95b83c4dae17bc18bf5a3b9d4266bae510843a5db688bd5b3575bdb51c14bc72a03f3bf6342f3c9f5c55bd6e04aa3e3f7dba3efbfe7fbde8d6573c00000000000000006ca6f83a38f2fbbb75c1603c83e9e23cbf6cadbc0f22163cfe206cbb9d60343c9e4eb6bd6e26bcbc109cb0bc69537b3b1a35893b15b7e9bc44ea983e2fd6be3e26776ebdc975213c00000000000000007ba59f3a15fa593c9e6985bd79b4143ebcefc8bd0f2ae63ce97cc7bbb7303c3dc64533be5ed9a83daabe2abd33250dbcd42825bb5c61653cffff6e3ead45b93e1a48e8bc655bd838000000000000000017850b3cad447dbccf73b63cb6c6e13c0d0a21bceeb63d3b10de02bcc949a73c4363a4bd3e8d9abd86abdb3bfa99343b3e71bb3c3425a6bd4665b23e78c0bf3e3f96bfbd45fdda3c0000000000000000a7b6f23b59a965bced34a73cc436da3b7340a9bc3ecc773c55b7d5384481b2ba55ce8dbd94a9a63c1f5402bddb1d323c796e7e3c6de94bbd37fe8a3e6157bc3e86458fbd6292ac3c0000000000000000e7d007bce00f613c896f0dbd60fc7a3d708968bd7c861d3d3c4b5cbb517b193da96e50bec0235d3e02e3d7bdcb17043c406110bc2a306a3d89d5f53da0aeda3e0e4081bd4f1d953b00000000000000007996bd3acc13b8bbf036413bfaaeda3a21029dbbb0c8b23ac338f3ba6c2a3e3c2192813c84ee563c84e83d3cd3d102bbfd91633a8a783b3bf2486a3e6fcd5e3ed0fc933be9c4aa38000000000000000023e9633aa12e59bc3985bf3c31cf263ccf3e02bcf561693a9e2c29bb1f91133c2cae663db09c9f3ca5304c3c14e6debaf202613aa571883c9b30503e60cf1d3ee9488b3c11e47a3a0000000000000000de34adb870cebbbb7291143e4435f7bb6bdf2bbc03550c3a5c71cebbce3278bc5e341a3e2479e0bbacb210bc6b591c3b51c73d3b60525e3d0d4af13d8e13323dee8b203d0ea89a3b00000000000000009d70c4393fd71bbbea14a53bb782a13b84ce2fbb8a4dbd391ce0c8ba571feb3bac9f82bc51b186bc72c1f53bcdc3e1ba2c825b3b7e74abbcea6f8e3ed71d8b3e2999a6bc9c615a3b0000000000000000bc58a63914ae13bce2d1f93bf0f3a83b6e130ebc9e7a9039c213ceba42b7993b092bbc3cdb96803c4884a73bc82673ba34c97f3a2f6bcabb3fab783e0e88673ef7f4cfbb2aa1773a000000000000000014c3fc3762a59fbc5d1d543d3d6c923c7e1083bc5c9bcf38ab3256bb9f825fb9e4ca5d3d5cded83c3d0c0eba688fb9bade87073b5363a63c9f81393e70012a3e530a9c3c5739fa3a0000000000000000c114a039933755bbbc4def3b1d69fc3bca587ebb26eec739a27ee0ba39733d3bd5da02bd28bb06bd90c0893b464217bb4b7a933bb79108bd698c9d3e16f39a3e2f6107bdddc49b3b0000000000000000eae6353936f7d7bb5624093c265fd33b8b0ee7bb90c52639bb2e75ba0b34743aca2c51bc602396bc9d65993beb6f8bba419e673b7f61f2bca18e973e8a6d903e6655ecbc44ee353b00000000000000001c6ea03831ab85bcb7cd933c9bbd913b2b016bbc199792370adaaeba88d914bcc6881f3d59d4b43c25913bbbf59deb39f080ea3a1f6beebb652b7c3e9fdd673e765008bc1549833a0000000000000000c2832c3ae4ca4abb9dda3c3cf0ac2d3ca6a144bbd2053d3ae62c3bba17861cbbd9e13dbd10e146bd8724053a3d4df3bab1c7023c41f33ebd94f0a93e547fa73ebd363fbd9b95063c00000000000000007cb2fab7827fe1bb0f06553c6177c13b924bacbba0757939b3ba2c3aa8a0a2bb19c7d5bc55240ebd68c1233b403f9aba41758f3bd2f516bd8c5ea23e52e19b3e62de15bdeda28c3b00000000000000001db380b9bd7082bc9bffb33c312bce3af40e1fbce30f44b93968e3b8f1601fbc8dcf033ce6c8f1bbc8b166ba1579e4392e897e3b2599bbbcf2c2923e7202883e9e4fc0bc7121193b0000000000000000d2558039b52b07bb40a06f3c7cb3403cdebeb9ba1e5b023aefc6ddb9e651833a12816dbd2d4376bd967f6c3bea1309bb76072b3cfc656dbd990fb13ea56aad3edbf962bde870303c00000000000000004a56abb97438ebbb744e9c3c17027b3b7163dabae8fcceb730730f3bef4d06bc369f12bddaa051bdf6b8503bb94fc6ba1dc0de3b91a43cbdb038ab3ec56fa33e1cbf31bd0cf5d83b0000000000000000025e5abace76d6bcece6433dbfa98abcaccb07bb74767fb9247dec3abe907dbcbfde5b3b3c4d06bdb0999f3b791a8cb98fc28a3b3fdbcebc96239a3ecf398e3e929fc0bc84d82b3b0000000000000000fd8b8dbbef39503ba985ef3b8ae9d43a286f9c3be3f685bb0d59df3a380b683c61dc60bd29fe6abd13b1933c7e99d4b75206ea3b920279bd51beaf3e2ed9a93e9b316abd01eabc3b0000000000000000666855ba46c307bcba85b03c0d27443aef44a6b990e17abaa4a94d3b98e399bbbb5f18bd70e081bdb42e4c3c43ffbdba1460013c633a5ebdcadeb13e1b12a33efd433cbdfe87b93b0000000000000000b6d72a3aa94b3ebd33a5ba3db02945bd58c7c63b613b03b9e1dd093b0541c6bc9a1e823ccbd88abd15c0963c6f7d85baa8ec983bb6f6cabc68d2a03ec7968d3ed6f999bc697de53a0000000000000000092f4a3ab6c3d7bb4b0ead3c17a9683c165276bb968fffb6ee3d9f3a2d8bfab97c5a85bd563891bda5d9e63b84e0b1ba0d78613c624c87bd49a8b93e442faf3ecd6176bdaf003d3c0000000000000000a210093b254359bcac08e33cf9c0e23b88be01bb607e26babe46453bcd355bbc80750dbd3c89a6bd5eda393cef62daba93e5233c2b0465bd9011b93e0feaa03e664721bd155fab3b000000000000000036b9333c94faa1bdbbb30b3e82ef92bd82113e3ca34e1a3a73e65dbb10cafabc50c6533d4c90fcbdc83b113df24b1dbba716343b215fb8bc78a0a73e66fe843e04b563bba0e0dab8000000000000000018bf5a3b4dae17bcfe95b83cdf51733ce32db9bb581c9f3a72a03f3bb51c14bc5b3575bd5db688bde510843a9d4266bae8d6573cfbfe7fbd3f7dba3e6e04aa3e9f5c55bdf6342f3c00000000000000000f22163cbf6cadbc83e9e23c75c1603c38f2fbbb6ca6f83a69537b3b109cb0bc6e26bcbc9e4eb6bd9d60343cfe206cbbc975213c26776ebd2fd6be3e44ea983e15b7e9bc1a35893b00000000000000000f2ae63cbcefc8bd79b4143e9e6985bd15fa593c7ba59f3a33250dbcaabe2abd5ed9a83dc64533beb7303c3de97cc7bb655bd8381a48e8bcad45b93effff6e3e5c61653cd42825bb0000000000000000eeb63d3b0d0a21bcb6c6e13ccf73b63cad447dbc17850b3cfa99343b86abdb3b3e8d9abd4363a4bdc949a73c10de02bc45fdda3c3f96bfbd78c0bf3e4665b23e3425a6bd3e71bb3c00000000000000003ecc773c7340a9bcc436da3bed34a73c59a965bca7b6f23bdb1d323c1f5402bd94a9a63c55ce8dbd4481b2ba55b7d5386292ac3c86458fbd6157bc3e37fe8a3e6de94bbd796e7e3c00000000000000007c861d3d708968bd60fc7a3d896f0dbde00f613ce7d007bccb17043c02e3d7bdc0235d3ea96e50be517b193d3c4b5cbb4f1d953b0e4081bda0aeda3e89d5f53d2a306a3d406110bc000000000000000048a6ca3af3dfbbbba9a6443b8241703a7cab89bbc907a43a42acedbaad473b3c9146903c9586273cca0e483ca5b0fbba09ba5e3a7ecbc33a0ccf773e530b533e6afca43bb255b2b50000000000000000f336c13a75f29abc55ceed3c6285163bebca0bbc85f9a73a94ff57bb8c863a3a12a4d93db8f3c73be0042c3c5aa9c138cb3857bac592893cdbab663e5ec0e73dc2588c3c4be4be3a00000000000000000ff6d5b78463d7bc7314f33d7f4833bcd73d81bbe3953239a9a4dcbb06a3ed3b80702a3ee2670ab9ffe1be3bc7e5df39416d703b05e1eb3ce1a10c3e6368883d30fd183c2888663b00000000000000000816eb39755306bb0bd29e3bd5439b3b53bc27bb6c12a739a48cccbaaa46f33bc05085bc518f8fbc4a9cf93b0ef3f5bae0a2683bd473b2bc1e11923ee35d883efe25a5bc97c4523b0000000000000000c24b0b3a0ab616bc89dcf53be102a73a31a4ecbb19f2a63925b436bb8a09ef3b1ce5dc3c7fcff63b5eaef63b71ef31babf4f883a54360cbc1896873ea4d0583e97de0cbc1b90043a00000000000000009e285b39d6bec3bc1c57633dac9ef5bb89c95dbc918cab39cf8fe5bb5c98cb3bd7b7bc3dbf48b63c9f9b3c3c80e7afba2cc9b3395764783c6ee0423e3ed1143e46d8513c4f42983a00000000000000006cd88639d0b41bbb9e08e63bc18ff73b593b81bba28ee33953fe8fbae664c33a5cbe01bd77c10dbdf5a2b73bfeee3ebba7aa8f3b6b080bbd1a46a03e46ea983ee31107bd0ce0a63b0000000000000000e0cb8f398acda0bb3313023c433a923b861acfbb8255723985536eba8e05c6ba5f783bbc4c1cd8bc99db143c0d99b6bad32e8e3bb74903bdee28a13e095f8b3ec2e4fabc5d92123b0000000000000000b2a1463a89f95ebc1a37903c1bb10fbcc4823ebc1d7326b8b86fb2bb2c3208bc84513b3d9e83813b35a5053c8b1e133b1c57883b70c728bc98cf8d3ed6ca5c3e2a457cbc6273deba0000000000000000a750123ad4aa3fbba600473c8ea0253cb66c6dbbe3fb7b3a48c49d39175f94bbf3603abd30b44ebdef085b3bde503fbb59ec003c0f0243bd96f2ac3ea836a53ea8fd3fbd93520e3c0000000000000000c33492b9cd0ed2bb3951873ca114ea3acb2984bbe843243aca11403be12e3fbc804bc0bc1e903dbd36e02f3c9b8f4ebb57e39f3b577924bdb040ac3e63c7973e8b3d23bd6c63a23b0000000000000000b230a639e45c19bcc338de3c3dc844bc95110abc8a42b0b901ea0bbbb82bd4bc3d02fc3bde5cedbc783eb13c035eef3a007f363c628fb0bcb4bba93e47ad803e979925bd0e8761bb00000000000000009d4d303a41366abbe93b8e3cdae12d3c06e30abb7f063d3a44878f399d1e38bb37b867bd2b4f81bd0849d83b10cc47bb3038463c22a275bdb89bb53e5c89aa3e924463bdb18b2d3c000000000000000011cb85b9f51148bc8ea6ee3c84ff42bb6da425baabf54b3ab7d6d23b1e928cbcca32d8bc5cc98bbd7a6c6f3c0afb94bb88dbfb3b52b856bd6025b63e00ae9c3ee49a2abde676c73b0000000000000000231cbeba8b2503bd1a01823dccc003bd4da54e3b11372c3a641b173cc667fabc8448783cf23190bd3c06d63c05e26dbbb97fc43b6a9b11bd7d71b13e8eff853ecf5ac5bc24be0fbb0000000000000000a65f94b8b53092bb8497a43c118d073ce13bd7ba1c76abb936c4f13a978f1cbbb7606cbd2bcf8bbdd8ad4b3cd0af31bb9981623c00be86bd2ad9ba3eff00a93e0c296cbd5b3b1c3c0000000000000000fa661e3b407699bcbff51c3d97c260bb5f1ae9ba98c97a3a4ee9e13b6886bdbc8f9bb0bc57afb7bdedf4c33c1637a8bb8c982b3cd3c971bde743c13e0f85973e576417bd7980483b00000000000000006fc0113c902d84bdff44d03dab813abd8eb1913b9d25c53a2297a33bfb750dbd8883253d0f23e1bdd05b0e3d189c9cbbcf92f3ba54e1b3bc1ab4b43e23fa763ea9a692bb5c6952bb00000000000000001fb9553baa4331bc0ef2e43c14f5533c0f73c1bbaa6eeb3af95f383bd1a420bcaaf07cbdf6fa9bbdb574373c11ab88bb2b0b8f3cb43c94bd2a65c43e4fcba63e183167bd73d42e3c00000000000000004c4e233c4659f6bc8bfd343db1ba953b9a36b0bb6076ea3a4627ac3b9ec1fcbca499efbb49deeabd0d1ce93c33ca9ebbeff3463cbfea81bd9eb2ce3e784e8a3ebe3bb1bce14002bb00000000000000004457d03c09ebc6bdfa1bf03dcd3e0cbd91bc00b9245a163b4cc434bca755e5bcd609ad3de6e217beb6060b3da00d66bb7367ddbb929a6fba363db53e5b194e3ebe426e3c9ca14fbb0000000000000000a8da8f3b608c46bcda45e13c71ba4e3cb360cfbbaf206d3ada23ed3b4e869bbc36df5abd1f3294bd0131203ce37258bb49617c3c28e491bd587aca3e948b9a3ebe7f39bdddac013c000000000000000096e28c3cca0c15bd45081a3d3e4b733cc4c735bc034b823bdec3fc3b9f2a17bd614e383c13adffbddd09fd3c1f7401bc8e24143c92a88dbd8cd9dc3e6e006d3eee47c4bb873546bb000000000000000049b2243d9b68dfbd3e37df3d4f4316bc7574a3bb0efc523b525bc6bc31b9b4bcb6f3e13d26063cbe4138f03c7c0b15bb07f8c4bbac837dbbbc7ec33e24a8283e1503023d9091a5bb000000000000000061c8743bb8a30ebcd6010a3dc7d0a73c316e88bcab6a0e3c64a7283c21c20abc6f6691bd36aca4bd81069a3c0dd1b8bb3928d83c4e3fd4bd56fdce3e7d89a13e502182bdf38f843c00000000000000003952b73c5c3022bda12d093ce7990c3d9b61bfbc8bea323c1380b73cd5ba03bd4698243d0f2bebbd76b5a13cf4ad30bcb42f1a3cc422acbd9d7eee3e2b08323eeb0437bc121b0c3c00000000000000002075633d0872cbbd91bd263db681173d84dea9bce356b53bdd59f2bcc32caebc77c55a3eb38a5abe542ae43c27f72bbb91725dbb58d79abca337dc3e30a66e3dac824b3d24b214bc0000000000000000e6e6df3af10badbbca16073b4d2d613af08360bbbd54a53a414022bbdfc64b3c310b8a3c6058063cc72e433c085f05bb18e52e3a647784395168833ee502483e5fb7a83b30e9fdb8000000000000000046a5ed3a01a489bc7ac00b3c4901a3bb2dbbabbb0b70cf3a55d52bbb12ad5dbaf627063e5d81d23bbe7a833cc0a16fbaaaf4cfba46dbf13be3d5863e288ea83d41d2643cb08e163a0000000000000000eb39c7380255e5bb1533963c51824abc3e4e82bb947d78397df528bb7c3669bbfaa0693e64cf583bdcecc63c3920a939592811bb8a92223b250f5a3e7bc2253d067c183b9d9ca6ba0000000000000000fcea023ab4c6e9bab93f933b3695993b5e662bbb2886ba39ba15c9ba244e003c05858ebc28bb97bc039ffd3b0ec8fdbae8b7733b06f3bcbc3cf4953e4bce853ef1eca4bc7192613b0000000000000000f6625f3a47ed0fbc10e48b3ba74dbcba63bdbcbb5605d3395ca68ebb43ef3a3c2accdf3c3060c5ba2a9b363c147b73ba33b6bc3ae54752bcf331953ed70e4c3e123d44bcc4e7953800000000000000006250253adc6966bc41f9853ca48758bc45622bbc8bf0303ad5d41dbcd05b973cc0e3093e39180a3c00caa93ce68955ba99a50fbb3df6683b23705e3eebd2063e6de73abbb1f95b3a00000000000000002ade43395c71a3bad8ddbc3b7e4c023cf0a48ebb6ba20b3a333706bad983083abd1a01bd0cca12bd4301e73ba03b77bb6383873b58570ebd41fba23efc0d973e09b308bdb270c03b00000000000000003897ce39765834bb40f0af3bf49fa13b31aec7bb982dd339b9cd70babe4a0fbbbfcc5fbc66d80cbd9e12553cecb111bb798f963be2eb0fbdbdd7aa3e83b7873e7e6607bd0762423b000000000000000066ccb23a8c0c20bc86251d3ca1eb42bca34e1dbce7e0d6b7860515bc81fbdeba00684e3de5112cbc8b1a8e3c2ee34d3bb87dc13b036685bcab7d9d3ea4554c3eff30b7bc10116fbb00000000000000008e7aea39e71622bbb17f463c63c0233c680089bbce4c903abc99b63a178acabb4c393abd4e3c56bd83b6bc3b564777bbd958f33b5f3c47bd9a26b03ec047a33e2d6243bdcb291c3c00000000000000003167edb9ef1f90bb32bb773cb891533be8449ebb47e4853a4136b53b701c87bc1642c7bce63d64bd6aa08d3c76ac95bb8c969d3b904e36bdfa42b63e5266943efdae32bddbe3c73b000000000000000052a686394a17743733e5bd3c83dc1abcfd4059bce4424fb9c8caa0ba231320bd586e26bb99892abd0e60213da7a47b3b0c9a783c90bf90bcda2cbf3eda876f3e914065bd2f5505bc00000000000000000ac9ef39235f6ebbabfe943c9d1d2d3c29204fbbc50c793a73a9b43aeda1babb5a4064bda37f84bd37b90d3c0ac067bb74bd573c38e27dbda080b93e5bcca73e5dd561bd75a8263c0000000000000000e9dd273920b954bc34e1f13c831784b9664150bb4c8ed63a9ac72f3c37e1d0bce632b5bc9a4ba0bde3eaae3c7a14c6bb36b9eb3bd0d869bddf4dc13e5d3b953e0fe121bd8e17af3b0000000000000000e579c8b79379a7bc5e6b293d026f69bc67c480bbcd38473add99873c1a6638bd57d8243c097f9abde75c093d87ffe6bab09f753bc4f51ebdde38c73ed098753ea16cf5bc94cfaebb000000000000000037c7e93abb13f0bbc5f4cd3c442f243c2e8298bb0e15a43a35f10f3b05d11ebc18246ebdd32496bd87d9693cd14996bbfd4a8b3c57748dbdda24c23ee38ba53ec8456bbdea59243c0000000000000000e684c73b8a1dc9bcdc712f3d41a3803ab492dcbbf790173b7183253cf14c1dbda40b1fbc7302d0bd937eea3ce2069ebbddd81c3ceed36ebd5fe8ce3edf36893ee801e2bc565579ba0000000000000000093b453c9e5c49bd74fd5b3d229f09bcbf4a87bb0870843aef39353c13c04cbddb775e3dcf9fdcbd6bd6cb3c708087ba46aee5bb6920f1bc9788c73e6e2f583e9893293bbad768bb0000000000000000bf8f4d3b79ff1cbc2eb4ea3c2a18493c343ccdbb2f5e113bbcfba73b4c3d88bc53f974bd013e9fbd1863703c29f8b9bbeab99b3c18209cbd59dfcc3e4c009f3e711a59bda34e163c00000000000000002397743c84ac1fbd65274e3d0457123c8cf63ebc277f743b11d0063cc81b43bd8fa2fe3b7edaf4bdf474e33c2a9439bb1fc0ce3b1bd763bd56dedf3e0494633e4926abbb3ec3c3bb00000000000000004767c83ca64395bd96d7503d6cfb033c08e5f6bb6867113a5163a8bb18f756bde8a8e53d1bfe01be608b6c3c86c3fd3af25b1ebc2c5cc4ba0f9ec73e30551f3e6e4aa13c8d65d0ba000000000000000098ad673b90662bbce22be83ca3c6383c947cf4bb1e2d193b7ca5423c67afe2bc548750bdde5a94bd6a2e733cb5a2cdbbbbb3773c52559abd773ed63e17be8e3eb76126bd8218d93b000000000000000005a6ae3c052342bd7c593d3daaba8b3ca11389bcf302d53b2435253c0bc250bd1324c33c815cf4bd6cc0bc3c58187bbb6c6aa2ba75685fbd3ab6f13e122e2a3ea3374b3c5b649abb00000000000000003b56113d940fb0bd54ea333dd9fdc03cf0b424bc277ec939bd509fbc6b1d3ebd7211153eb97910bec665d93b1711833b1662f6bb05ccf23b7b76c93eb31dfa3d10ece93c992328ba0000000000000000ad87c63b45f4c2bb40b00e3d3b617c3c7e5859bcc513493cc046413c7c2471bc2633a1bd2f218fbd96455e3cad322ebcf547d03c0ec3e0bdca0fde3e043b913effdd51bd7fb68e3c000000000000000038e7be3c820150bde428e23c42acc23c11f8b7bc8277173cadf0c33c4bbc1ebdc10ac23cdd4dbbbd56083b3cd6a1b4ba9de6ec3a59af88bdcc18093f85f0a33de8e3843c204ca3bb0000000000000000f389343da148bfbdaa86503cc569233d05355fbcef30ee3a0928cbbcf8d209bdd5d4503e0bf4e6bd6e3624bba3db6b3b41a2bbbb13b3f43bfdbcd23e3104033d7b83e93c5b44623a00000000000000003a2c063baf1c88bb62f9063ab3740c396df528bb54a99d3afa5e48bbf00f663c0f5b653c6f0be83b778d473c8dc10ebbc678923a1959cdba90a98a3e4ae53e3e6a12a13b70fd77ba000000000000000033ff873a7088e43ac11c8cbbd444c2bbc3935ebbfe80d83a1d52e4baefd4313b5b289c3d484db53bb2dfa73ca5d529bb6c6cbcba07f97dbb787da43e915dac3d1fc02b3c55e608bb0000000000000000f51c043a80761dbb7eb0213be5f83fbc74d2abba08d02d3ae5dc95bbf913ce3c0d15ff3d9cfda0bb1b47c93cc671f9baff9abc3a5841b5bc6d5bab3e02a0273d9d537fbb4d9a0abb0000000000000000e15a2a3a88c2cabaa5ed813ba5009a3bd08524bb3971d439d41ad5ba95a4103c098b9cbcf16d9fbc9de5023c0a5015bb712c793bcc54c5bc1967993e7eb3833e2c7da5bc2a7a6e3b00000000000000007283a03a7889f8bbf5a30a3b4af805bb305c92bbcff2e839e9e3b7bbb3778c3c87ce713c52ea0ebcb5d25f3c9369aebae013133b9e5f9fbc9d99a33e8cd2443e36d562bc3c8590b90000000000000000f634963a9d9278bb12c5283c9d7595bc7628f5bb13985b3a6ab443bc46cbed3c700a8f3d7dd19ab915ddf73c47b4b1ba26a292ba768740bc82dc923ebc71103efc513abc280800bb00000000000000009dfe5339bbfdb2b9e9ee9b3bc76d063c92fb9abb84a1333a91121ab998f320398e9f05bda5ce14bd97e8043c1a7490bb8430763bea0910bd1d86a53ee96c953e9c030bbde7bcda3b00000000000000009c5b84395bab62bacd6e013bd80ff43b9e20c8bb163e3c3a4e919eb97cc071b9d6789dbc973622bd0d12773c39036ebb43c2833beda31fbd5efbb23e0115853ed01d0ebdd701983b00000000000000002e7fa63aa9e10cbc8855133b36a00abc4190d9bbff8db83967ad2dbccd7c823cc338013d7362a7bc068ca23cb9d5353a4f826f3b72f9e1bce302ad3e35a6453e84bbbdbcb8ae81ba00000000000000008ff983396ed6c6bae256363c3a232c3c931da0bbffd0b23aaea6023b2bd9e1bbebea3bbd9cb159bd041bf23bde8c93bb37e4f13b9fbc4abd9171b23effdea13e550447bd3d63273c0000000000000000b1cc7aba53d366ba29ed1b3c8bec0a3cfe31dabb94aac93a5455f33b23b989bcab57ecbc406f77bd2e05a53c0503bdbbcbc6633bc6fa47bd76d2bd3ee551923e60523ebdab860b3c0000000000000000278335bbdf41003aa112223cda32a739c3fc34bc00c4913a7825d73b303cacbc2f0a0abc964a52bda35a0d3daecd92baf260653ba41616bd47b0c73ebcf16e3eb2284abdfe79013b00000000000000001b08c0399ce93bbb7f68913caa502d3cce686fbbc4b3993a79eddf3aeb6fe6bb360e68bd040584bdeec5203c88aa82bb2a17633ca56481bdfb71bc3eaed6a53e849c63bda911273c0000000000000000e4d16cba5dfcbcbbfd6e9f3c097cf83b9e46d2bb21b0123bb835503c650ce6bc65fbe4bc2bb29ebd2b07ba3cb2afc2bbd79fea3bba4b7fbdc193cb3ea3388f3e750022bd6b5fab3b0000000000000000de85a5bb01af17bbf9148b3cd5a365393af8e2bb813fb23a9b04bc3c96b22bbd245cfbbbde0791bdf310093d11eb14bbef7fc43903dc5bbdb185d83e5842693edbe807bde09210bb0000000000000000cb21113b4a97d1bbafd2cc3c8c5f363c76c3bebbb84de03a3af61d3bc69561bc259a71bdf0a097bd059d843c7b43b2bb9098993c20d38fbdec3ec73ebbeba13e71d16cbd1b9f1e3c00000000000000004ecb8d3bffbf56bc7fe2e63c35d3213c15fa1bbc9454063b1e0f663ca0414bbd9d6938bc1b3cc1bdbd3cd23cb7200bbb310f213cf9d97fbd868edc3e2d037a3e9ae3babc0ab06ebb000000000000000041efe63aee881ebc2cd5503caf66ee3bec63dcbbfeef723a9a81d53c55f68bbd25caf03c1d4dadbd12adba3c183bcb39b37600bc680446bd36b0e43e9ff53c3ea30a4dbbbc807cbb00000000000000008c700e3bfa6dd1bb3b36e03c0ca4493c3c47e8bb174b223b125eef3bb3e4b7bc758776bdd12e9cbd8545903c811cddbbba399f3c09339ebdd5ded33e4d57983e2c2456bd543e0d3c000000000000000021192a3cc247a9bc0c90fd3c096b7b3c5ef344bc5c680f3becd9883c58d88cbd6664b93b9700c6bd1bcd953cfbf43d3a2811083b9fe861bd2e34f23e9c793a3e0f300b3bb9c1cebb0000000000000000c04d343c811089bca7cf06bb981b893c3eddd2bb9a40ce383c83923c12fdb7bdca67a33d5376a8bd67a5de3b54df1b3b3a7168bc88b5c9bc40b3eb3e1c5dfd3d8ffa8c3c970f31390000000000000000bc4eb13a3e87b2bb005ad13c240e493c9de914bc317c573b6adc7d3cd54610bd197054bd7b428ebd5edf903c3ddf04bcb10e6c3cf8d39bbd7066df3e0f99853e10fe1bbd8a5ec63b000000000000000077ee853c7b91d9bc9270db3c418d9a3c540964bcf491393bcf6e8b3cdfd7a4bda773bf3c8a8bacbd3baf183c96db953afed5cfbbf5a634bd7e1a023fe9dbef3d4b3b923c7e4e52bb00000000000000001e3aac3c98c3dbbc89a606bcdbd6b13c4b10bfbbe16f01ba58cda73bb78fbdbdc14bdf3d0b15a4bd567938bb45216f3be16d53bcc0e74abcce12ef3e29afae3d57cde33c2d52ce3a0000000000000000ba15bd3b3e9eacb765faf83ccc11683cddce2dbc1ed2433c5504383c30599dbc34f9aabdd1fd70bdeae9133c5b3054bcc9a1cf3cfa2ce3bd1a54ea3e6080833edba62fbdb853873c000000000000000029d98c3ca538dfbc3857a73ce3ef853c616388bc2e44b53bcfb6c33cf111aebd232bb63ce8c74fbd0eb8edba61850d3bfe5b8dbb6cd40fbdccc20f3f9d95073d0610ab3c134e22bb000000000000000047e9dd3ce89b27bd138443bc558c823c0dbc05bb362be2b8347dfeba06adadbde511fc3de29101bdfc1427bcb140783a513b46bcc347893bfbad023f951240bcfbeaa43c6724b63b00000000000000001c4f173b9efa96bb74f4af39ebb4a1baa16d21bbd7dfae3a4a6368bb342c813c1178f53be3c9d13b21214d3c297509bb010af2397d5a5eba3314903e2d663a3e67a4b13b37a832ba00000000000000005147e53aab68353b87d4b5bbec4d9fbb9ec04abbbf33de3aef1599bb40a9943cb97f063da1c5b43bb0eca13c279213bb7a49493a30f715bc228db53e4940b23dbe26173ce92194bb000000000000000040671e3a3edc0d3cc4179bbb0bce79bc1333fbba8ced4c3a75c6b6ba4569cf3cd6ab183d578ce23b5328ee3c2912a8ba864682bbaefcf6bcee81d03e7f522e3d8d84c83b9a78bfbb00000000000000003f0a373a6f87c3baa61e733b4ae49b3b7e2029bba1b1e63974d0d1ba52cb223cf135b1bc363da5bce8f2033c933a1bbb5649763bc7f9cbbce8899c3e56df813e22d7a4bc24e3863b00000000000000006a02ea3a3c0cfebba2cea23a77a826bab97567bb72ca093af35ce2bb106bcb3c6f8c60bb826a49bc53225f3c7b0103bb62333c3bc4e5c7bc00c5af3e6c3e3f3e5efb61bca05b4cb90000000000000000fcb5013b5ac99cbbb9952d3b35be70bc2795debba80f5f3a845f32bc72d3253d56e8483cba976cbb67530f3d9b88a4bae98f4fbbad9a99bc8416b53ed610093e4c8f32bce1f1c1bb000000000000000013e81e3947647d39ae286c3b7a54103ceb2ea3bbe1513d3ad9d0b139fee29639efca08bd3cee16bd88a8103c25b49dbbf4e5523be5ef10bda25ca73eb40a943e59380dbdbc7ffb3b0000000000000000c4413c3785fd853a072a91ba2cd02d3c8833d8bbf91a903a24fdfb392bb91f3bd579e0bcf93629bd5c7c823cdf23acbbe3470f3bb95c27bdcb31b93e5adc823efccc12bd394fef3b0000000000000000f296d53a131238bc0fd4d6ba235264bb71b6adbb1c56403abedb4bbc598b123d2d2b243b425bbcbc3384ab3c02dbc2ba2d97983a4ce907bd72dabb3ec3603d3ecc99c2bc07ca733a00000000000000005b6ebc39775befb967c21b3c98a43b3c40d4aebb5e0cce3afa63de3a1d9bd8bb98fd42bd9f5c57bd138a043c5ff3acbb0a11eb3b1d904cbd923fb43e4acba03e28204abd858f373c0000000000000000daebd3ba3d7e553bd326533b469f613c382508bca5280c3bbd1af53b54ff5bbc333717bd024675bd4d74a53c9f82e1bba2df0d3b4b5a51bd9736c23e3d78913e211b47bdc392353c0000000000000000364a71bb5defd83a5d0626bbd9011c3cded114bcfaa2083b0002923bb2adb73aee45b0bcd61455bda013d83c8fd5a2bbea061eba3c1a4dbd04e1c93ea404753ee61231bda8b30d3c0000000000000000e5ae8e393d33ddba3fa1893cc4f83a3cc97e98bb727fc33aeae3af3aef05e2bbc4df73bd07bb81bd5860363c0f9f93bb93746c3ce3c982bd8849bf3e03eea33e043568bd5a4f2c3c000000000000000017ff4dbb6cf34b3be4f5203c480f5f3cd41514bce7f1453b0c534c3c3661c7bc5d3c2ebdbe3c8cbd5c12b13c472ccbbba0b9ea3bcc0486bd52efd23e407f8b3e732830bdaed0e23b0000000000000000ae9708bce7891e3c81b8b7b99e8a4c3cdf9d1dbcd6a5113b3c6c983c4db8c5bc30f6ffbcf84179bd64f3d53c794b2cbb4284413be0b689bd7906df3e23076b3ec4e70bbdb50bb73a0000000000000000f983143b6f3e94bb8323c23c6215453c9af1e9bbd64c213be15e813afd8261bc25f380bd176b93bd0ce8963c14f4debb03e4a83c67ed91bd3c07cb3e3e779f3eba0d76bd3345243c000000000000000021c302bb64fd943b94674a3c0295683c31c928bcd2f81b3b8f3e893c634a42bd00de02bd999d98bdc0f0b53cbe780bbb81063e3cb1e08fbd8999e73e2a9c6c3ef934d8bcd4f121bb000000000000000079eefbbb6db87d3c1e13b4bbc9a65b3c1c3ef8bb32e5943ac679d73ca7885abd629895bcc99666bd3c50813ce149b03a8cfba13acb7292bdc9a2f43ed917393e57e905bc60c2a0bb0000000000000000533f5c3a3c07e5ba1a0bcb3c75d1533cfe1e01bc3d57433b8410d93b524bc0bc03f386bd395092bd60f2963c1dabf4bb649ead3cca40a1bd368bd93e04ad933e533459bd0c6b0c3c0000000000000000a5e796b804dba13bc7644f3ce1cb753c47881abcba01cc3ac294c53cd1938ebda656dbbce9b082bd2a6b423cdfb2173a2a5fa13b3cde8cbdfa5f003f35fb2c3e80d63fbbc53d97bb0000000000000000016c90bb02c5873ce3213bbcb0905e3c5593a8bba3d6a739acdcf33ccf0d9fbd261b303aaa7233bdcd526d3b0fd4113bb10d04bc136871bd28a5023fc916fd3ddbcb2b3ccf0ce1ba000000000000000089b3b4b8d9661a3b87d5a53c0152553ccf7d1fbc14a65b3bb630613cacba1ebd8c096fbdb52b7abd65778e3c3fb202bc11b6843cd0529bbd1801e63ee82d7f3e0d9c1fbdf3a4c63b0000000000000000deab9f3bbae2ae3b795b043cca155d3c18b516bcb38dbc3abe6fdb3ca223b7bd912c66bcf42441bd525b953b3fd37a3a060368bb775167bd4f48093f3027e13da84b273c451109bb0000000000000000dcc93b3b5108153cb9ae15bc407e3d3ca50452bb0cc223b975d3d53c562db7bddb49603c81fe16bd3ee61bbbb7d7043b7ebe5abc70393abdeaa9083f998ea13de2b8aa3c6a058e3a0000000000000000ced3603b083d103c553ba93cd4d1a33c8e323ebcaaa61f3c2ad5383c1c4aa7bcfb51b2bdd0e955bde2d1853b4de04fbc5bffba3c220fe0bda239f13ec82f783ea0241cbd9ae48c3c00000000000000009acef53bcaec243c17a3703bb5ad413c0e7e31bcd9ed023b72ddd23cac36c8bd4ce1dcbb500dd6bc01a257bba7c21e3bf5061ab9ad3f33bd1b1c103fedf84b3d72515e3c07f85fba00000000000000000a4c3e3c95e203bb1dda78bbce4e833b1c9a46b97f4b78b91920883c3514c8bdc921b83c39dd56bc487868bb8e705939a6685abc757b91bcd56c113f120c223c517b823c6b493c3b000000000000000063172a3b0eb195bbdebd833992414fba5df822bbba99ac3a086a86bb0f168e3ceedb693b6b9bbd3b6f2f4c3ca5031cbb33d55b39e429013af3d3923eb81e363e534dcd3b37911aba0000000000000000fa53843b264384bb61c996bb972725bbcb1629bb3d47cd3a68f4debb59f7ff3ca0a2203c4672ac3b53be8c3c76a037bb887377393971c9bb44a1bb3ecf09b73d5f160b3cd0a888bb00000000000000007f4e233bf6ae03bb7a5764ba12e6a3bb34b86bba5998eb39c2317fbb23641a3d2a0d583b9f3e45bb7466693c79b2d2b9d4856a3a12ab9dbbdac5df3e9038d33c579f8e3b36d0afbb0000000000000000c8555d3a9072c6ba8461703b0c14953b622823bbc02bf7394f47cebad853333cca9fc2bc791ea6bc44e0043c1fb51fbb4b3b7a3bc0efccbcf35c9e3e83a8803e1146a5bc0a288b3b0000000000000000cfda283bfbfc0abc3877c53a131ba33970f932bbda80163a7daa0abc44e3003d78099dbc677f4dbcc66f4e3c975d21bb6ab32b3b18afd1bcea8db83e7039383e16b653bcf1e9b7390000000000000000bd316c3b235f2fbca6d30dbb96a5dbbbe43813bbd2d1dc39438941bcad26683d30540cbc219c79bb35b8af3c30b2adba03080dbb46db91bc43e5cd3eaea7bd3de8ee84bb4808b6bb00000000000000002d54af3875f06e3a8fdf3e3be832133c7f83aabb4657553ac0ea583a48acc83940890dbdac3214bdee74163c0442a8bbb920403b22a311bd257da83ed613933e404510bd77f50a3c0000000000000000dbd659b78211ff3aa3ea20bb50bd433cfac5e5bb7975bd3aabbfbd3a69d0c23b74b715bd99b01ebde235823c4b13d9bbb04f2cba76a029bd6d03be3e05c47f3e560115bd0142293c0000000000000000ab0c353b221653bcf1ebb1b9e5d085b9316e6cbb207d5b3abd2e5bbcb6f53c3d9976d0bca613a1bc360f943ce02b29bbc8b2803acdc60dbdaff9cc3e0df3263e78b1a3bcede8183a00000000000000002fdf2b3995fbe73953d7043ca25d473cd605c8bbcdb8f43a23a9ca3a4cb3c6bbd55f48bddb0454bd7b44163cd2b1c2bb40b6ee3b03a84abd751db53e30f49f3e7d9d4ebd6979413c0000000000000000d332fcbac96bbe3b6f62c1b95209843c144f19bc8d37333b4d16e93beae817bc28063cbd920963bd6097a53c70ea09bc05aad1380a514fbd479fc43e628f903e0ab451bd43be653c0000000000000000570430bb28755c3ad70680bbb527483cbe5b14bcd3ea323b2e16fc3907f97c3c29fa27bdf37c31bd8caaba3c1d9adbbbb594a4ba2bca4abd0e8ccf3e9d146a3e91a228bd24ab263c000000000000000078e3c539c14984ba771f833c0f8e413c5746b8bb8e24013bcd238c39193db8bb18d17fbd154d7dbde45c503ca1a9aabb5f1c7f3c1f8883bd87cac03ed93fa33e466971bdd112313c0000000000000000c17a78bb7287f03b1323d03b9e196e3ce53422bce22f7f3b506c273c4d6598bc6bc367bd67b26cbdc0dda93c66d103bc6335ce3bddae82bd48d2d63ea7c7883ee24d44bd1aba293c00000000000000006e0dacbb7b1af13bb58f783abccf483c680426bcc665593b59c5de3ba12c04ba0e6e75bd3f8535bd1db0ae3c208799bb9dddc93bcfe58ebd524ee23e84df673ed0f717bd8071a63b0000000000000000758fa33bf5fcffbb9e77d13c152b5f3c42383fbcc428a53b0df2c5bbcb6e6ebb53c892bdbad395bda25ae33c0f5e3fbca292cb3c900b99bde51acd3e677ba03e4b158bbd51f64b3c00000000000000001692d3bb0adc433c0de1373c2743123cfe4722bc4daa7d3bcff26e3c35800dbd6ad665bd046870bd0f97e53c7a9bcabb16856f3c48de92bdec87eb3ed2d26b3e54fd24bdd0adc03900000000000000008106c9bbccae343cf2d0783b4f46fb3bd0aae0bb6172003b5ad32a3cda435fbc77a188bd7c610abde498653cd0690bbad838503c4ff8adbdfd66f93eec433e3e1cc594bc28d376bb00000000000000005ae3803b30e272bbfee3d33cc7586a3c596144bcdf3caf3b5dede6ba4fdd67bc37e79bbdc3e98ebdecd6d23c36c83fbc85d8d53c585ba8bdf539dc3e688d943e6be07cbde3053e3c0000000000000000bd40ebbb4bf2833c18054e3cba11f73b376c08bc1c71583b1762b73ce67b66bdea3578bd38a72cbd5c25863cb35077bb03654d3cc95f9dbd5681033f17ca303e30b5a0bce0301dbb000000000000000009b2f4bb02d9743c342e233bef7fcb3b036cacbb4a19a83a0dbe933c2c5c0cbdfdbf7ebdf189c5bc9610003cbffd873a1405f53b9a9ea6bd1fcc053fee97113e3f50a1bb9b9994bb0000000000000000c3871fbad810063cf1a3933cafc7423c94b613bc51bd123b19a41c3cd05e21bd450589bd451e5abdc68b8b3c5e85f0bb36379c3c080799bd6942e93e94c57b3e5a4432bd6473ef3b0000000000000000d02884bb414fa73cd821e83bb9eac53b9fe1e3bbd7fc203be7f0e13ca404a2bd649058bd7ecfccbc67efed3b773c08bb36f39f3ba0a78abd86ab0c3f4f4af53d88f8b5bb10bfdcba0000000000000000ee8fbbbbc0fc813c74ffe73a43087b3b7ada5fbb2911873a1f7ab53c66e058bd3b6f55bdf4258abc67778b3b359a413af5b13e3a1e148fbda72b0c3f89f3d03d4e76823b72a644bb00000000000000007ef2443ac1b0513c8fdf793cb510b73cb00734bc4957023cae835d3c49f190bc0918b9bde1d54fbd1cbe63ba98e12fbc30ff973ce2ffd0bde725f13e55d6783e857527bd23fc9c3c0000000000000000656ce8b90886ac3c09b2be3bb51cf73b9da6cbbb98dbc43afae0ca3c73e098bd17193fbd981ca9bc3c25fd39abea86ba2105c03b25f279bdaf950f3f31efa83d5f04653a944721ba000000000000000039db8f38a31f263c9726253bbe3cf63a033405bba534673a5e947c3c21a785bd0078c7bc0dab3abc0e37323b04256ab88790b1ba061d20bdae4f0f3f83d73a3d5e28da3b21490ebb0000000000000000f691283b025689bbe61c853912e7d4b9c4e818bbe115ab3a44b598bb8a598e3cff10393a297ccb3b8683463c2c6d1fbb9e16a039b205773bc3a5923ea61e363e0808bc3b69c71dba0000000000000000351d843b15a1ddbbb8469039cda687bb9bb336bb0926cc3a0c9782bbd6ffff3c1d7ec3bb3d020a3cc6d98b3c458827bbf09994bb7874243c4f63bb3eba15b73dcd16ab3b5a6025bb0000000000000000361e3c3bc4df9fbbd41ce33abaded0bb232333b947d7a83976fe92bbfa812f3d37bfabbb9abc8c3b13466f3c9d70f8b98745a6ba97290a3bc3b9df3efeeed43c0c0454bb07ceb7bb00000000000000005d6a5c3a721dceba14427a3bd8338b3bf7a61fbbbce5f6394e4cc6babf56333c59eeccbcd646a5bc69d3043c391923bb9f69703b8c9ec2bcc45c9e3e6ca8803e1e1fa6bc6020953b000000000000000063dc283bf9ad0abcabcb2b3b2601b739ed5e21bbe168163ac2000bbcffe1003d55b2d1bc54c253bc06854e3c74fa32bb65a6c53aa50d9dbce18db83ec83b383ee88c4dbc4426a239000000000000000053a27c3b338848bc5081fcbaeb67bbbb6ec5a5bad523d1390bdc38bce0726d3d21b396bcbdff7cbb6f2eaf3c5fe60cbb666e07bb09b416bcd63ace3eabbbbc3d19f36fbbc189debb000000000000000013c6ae3829fc583ad31c403bdef50a3c443ea8bbc344553a8a006f3a998dc83922a211bddd4410bd7f71163cdc7faabbcddb3e3b31880dbd187da83e9613933e3b3214bd6833133c0000000000000000a9ed59b727bebd3a1e4e2cba9641293cf511d9bbcd72bd3acd0fff3a69d1c23b58a029bd4a0115bd9035823c97c4e5bbfbe920bb52b715bd6503be3e00c47f3e83b01ebddfbc433c00000000000000004652393bb47a5dbc07ec8e3ac010083ab87b27bbce86593a97a755bc0c1f3e3d4c890ebdedd0a2bcb38c933c85e969bb8ffb74b9d804d2bc5113cd3e53c7263ed536a0bcdc4ea6b90000000000000000e6dd2b3916aaca3aefb5ee3b5f79413c95b0c2bb86b4f43a6bffe739c1b3c6bbf5a74abd7b9d4ebdc543163cb204c8bb2ad7043cc85f48bd731db53e32f49f3ed90454bda15d473c00000000000000001833fcba6a16e93bb9a1d1383bbe653c78ea09bcde37333be76bbe3b0de917bc04514fbdfcb351bd4197a53c014f19bc6364c1b921063cbd479fc43e618f903e830963bd4609843c0000000000000000988e2ebbd352e539d57b9ebaa3fc253c35cfdabb3a1b323b6f82503a6b0f7e3c92024bbdc07128bdde50ba3c14c613bc3e367dbbd83328bd4093cf3ed8066a3e184c31bd8482473c000000000000000027d6c539fd418c39511b7f3c3013313c7daaaabbd025013b004284ba2b41b8bbf98783bdbb6871bdab5c503c3c47b8bbe11e833cc2d07fbdb2cac03e8d3fa33e874c7dbd7e8e413c0000000000000000cb7a78bb536c273c5f35ce3b17ba293c5fd103bcdb2f7f3b7987f03b4f6598bcddae82bde04d44bdb6dda93cdb3422bc0d23d03b6ac367bd48d2d63ea7c7883e65b26cbd9c196e3c0000000000000000b893abbb96c8dd3bd40acb3b0aa5a53b1b2e99bb0bea583b0c35f03b91eef4b903f88ebdffd717bd6c82ae3cf9ac25bc308a803a9a9175bd7952e23e82d7673ee86635bdcb48483c0000000000000000748fa33b10f2c5bba592cb3c3cf64b3ce05d3fbcab28a53beffcffbb9e6e6ebb930b99bd44158bbd715ae33c43383fbc9677d13c54c892bde61acd3e667ba03eb6d395bd342b5f3c00000000000000001692d3bbcff26e3c16856f3cd0adc0397a9bcabb4daa7d3b0adc433c35800dbd48de92bd54fd24bd0f97e53cfe4722bc0de1373c6ad665bdec87eb3ed2d26b3e046870bd2743123c0000000000000000d748c8bb54372a3c7da8503cfa6e77bbe2fa0aba9645003bd7f1333c3a535ebcbc0baebdf8a094bcfb77653cec52e0bbd87e7b3b57b788bd646bf93ee13c3e3e6b4a0abdfb76fa3b00000000000000005ae3803b5dede6ba85d8d53ce3053e3c36c83fbcdf3caf3b30e272bb4fdd67bc585ba8bd6be07cbdecd6d23c596144bcfee3d33c37e79bbdf539dc3e688d943ec3e98ebdc7586a3c0000000000000000bd40ebbb1762b73c03654d3ce0301dbbb35077bb1c71583b4bf2833ce67b66bdc95f9dbd30b5a0bc5c25863c376c08bc18054e3cea3578bd5681033f17ca303e38a72cbdba11f73b0000000000000000f68ef4bb43b2933ce727f53be6a594bb39ff873a2707a83a7eb7743cbc520cbd2da1a6bd8b3da1bbd30e003cf45aacbb49a0233bc8c67ebd6ecc053f0997113ea984c5bca257cb3b0000000000000000c3871fba19a41c3c36379c3c6473ef3b5e85f0bb51bd123bd810063cd05e21bd080799bd5a4432bdc68b8b3c94b613bcf1a3933c450589bd6942e93e94c57b3e451e5abdafc7423c0000000000000000d02884bbe7f0e13c36f39f3b10bfdcba773c08bbd7fc203b414fa73ca404a2bda0a78abd88f8b5bb67efed3b9fe1e3bbd821e83b649058bd86ab0c3f4f4af53d7ecfccbcb9eac53b00000000000000000d80bbbb9275b53c7a0b3f3a62b044bbd4a8413a9904873a77f5813c02dd58bd01158fbd457d823b66778b3b44cf5fbb505be83a4d7155bdc42b0c3fd9f2d03df2248abc01ef7a3b0000000000000000d02f443ab88b5d3c3cfb973c12fd9c3cd2e92fbce35d023cfab7513c09ed90bca2ffd0bd747427bda44063ba361034bc0bd7793cb217b9bdd825f13ec9d5783e68d44fbd3711b73c0000000000000000656ce8b9fae0ca3c2105c03b944721baabea86ba98dbc43a0886ac3c73e098bd25f279bd5f04653a3c25fd399da6cbbb09b2be3b17193fbdaf950f3f31efa83d981ca9bcb51cf73b000000000000000033a492389a907c3c2380b1baec490ebbbd6e6bb8f13d673a1318263c8ca685bd4d1d20bdc32cda3b7539323b433005bbea35253bcc79c7bcbe4f0f3fb2d63a3d8bab3abc8322f63a00000000000000001c4f173b4a6368bb010af23937a832ba297509bbd7dfae3a9efa96bb342c813c7b5a5eba67a4b13b21214d3ca16d21bb75f4af391178f53b3314903e2d663a3ee3c9d13bebb4a1ba00000000000000005c47e53a081699bb4249493ae12194bb199213bbb833de3a5668353b42a9943c2ef715bcbe26173cafeca13cbac04abb8ad4b5bbbb7f063d228db53e4a40b23db9c5b43be74d9fbb000000000000000041671e3a76c6b6ba864682bb9a78bfbb2a12a8ba8ced4c3a3edc0d3c4569cf3caefcf6bc8c84c83b5328ee3c1233fbbac4179bbbd6ab183dee81d03e7f522e3d578ce23b0bce79bc0000000000000000410a373a76d0d1ba5549763b26e3863b943a1bbba1b1e6397487c3ba51cb223cc7f9cbbc22d7a4bce8f2033c7d2029bba71e733bf135b1bce8899c3e56df813e373da5bc4ae49b3b00000000000000006a02ea3af35ce2bb62333c3ba05b4cb97b0103bb72ca093a3c0cfebb106bcb3cc4e5c7bc5efb61bc53225f3cb97567bba2cea23a6f8c60bb00c5af3e6c3e3f3e826a49bc77a826ba0000000000000000fcb5013b845f32bce98f4fbbe1f1c1bb9b88a4baa80f5f3a5ac99cbb72d3253dad9a99bc4c8f32bc67530f3d2795debbb9952d3b56e8483c8416b53ed610093eba976cbb35be70bc000000000000000006e81e39d9d0b139efe5523bbb7ffb3b20b49dbbdb513d3a9c647d397ae29639e5ef10bd57380dbd88a8103ceb2ea3bbac286c3bedca08bda25ca73eb30a943e3eee16bd7a54103c0000000000000000c5413c3724fdfb39e3470f3b394fef3bdf23acbbf91a903a85fd853a2bb91f3bb95c27bdfccc12bd5c7c823c8833d8bb072a91bad579e0bccb31b93e5adc823ef93629bd2cd02d3c0000000000000000b096d53abfdb4bbc5d97983a5fc9733a41dbc2ba3b56403a121238bc518b123d46e907bdd699c2bc4284ab3c61b6adbb3fd3d6ba502b243b73dabb3ec2603d3e475bbcbc895264bb0000000000000000596ebc39fa63de3a0a11eb3b858f373c5ef3acbb5e0cce3a765befb91d9bd8bb1d904cbd28204abd138a043c40d4aebb67c21b3c98fd42bd923fb43e4acba03e9f5c57bd98a43b3c0000000000000000daebd3babd1af53ba2df0d3bc392353c9f82e1bba5280c3b3d7e553b54ff5bbc4b5a51bd211b47bd4d74a53c382508bcd326533b333717bd9736c23e3d78913e024675bd469f613c0000000000000000364a71bb0002923bea061ebaa8b30d3c8fd5a2bbfaa2083b5defd83ab2adb73a3c1a4dbde61231bda013d83cded114bc5d0626bbee45b0bc04e1c93ea404753ed61455bdd9011c3c0000000000000000e5ae8e39eae3af3a93746c3c5a4f2c3c0f9f93bb727fc33a3d33ddbaef05e2bbe3c982bd043568bd5860363cc97e98bb3fa1893cc4df73bd8849bf3e03eea33e07bb81bdc4f83a3c000000000000000017ff4dbb0c534c3ca0b9ea3baed0e23b472ccbbbe7f1453b6cf34b3b3661c7bccc0486bd732830bd5c12b13cd41514bce4f5203c5d3c2ebd52efd23e407f8b3ebe3c8cbd480f5f3c0000000000000000b19708bc3d6c983c3d84413bb50bb73a824b2cbbd5a5113bea891e3c4eb8c5bcdfb689bdc4e70bbd65f3d53cdc9d1dbc50b8b7b934f6ffbc7906df3e23076b3ef84179bd9a8a4c3c0000000000000000fb83143be65e813a01e4a83c3845243c08f4debba14c213b703e94bbfe8261bc66ed91bdbb0d76bd09e8963c7af1e9bb8423c23c25f380bd3c07cb3e3e779f3e176b93bd5c15453c000000000000000021c302bb8f3e893c81063e3cd4f121bbbe780bbbd2f81b3b64fd943b634a42bdb1e08fbdf934d8bcc0f0b53c31c928bc94674a3c00de02bd8999e73e2a9c6c3e999d98bd0295683c000000000000000079eefbbbc679d73c8cfba13a60c2a0bbe149b03a32e5943a6db87d3ca7885abdcb7292bd57e905bc3c50813c1c3ef8bb1e13b4bb629895bcc9a2f43ed917393ec99666bdc9a65b3c0000000000000000533f5c3a8410d93b649ead3c0c6b0c3c1dabf4bb3d57433b3c07e5ba524bc0bcca40a1bd533459bd60f2963cfe1e01bc1a0bcb3c03f386bd368bd93e04ad933e395092bd75d1533c0000000000000000a5e796b8c294c53c2a5fa13bc53d97bbdfb2173aba01cc3a04dba13bd1938ebd3cde8cbd80d63fbb2a6b423c47881abcc7644f3ca656dbbcfa5f003f35fb2c3ee9b082bde1cb753c0000000000000000016c90bbacdcf33cb10d04bccf0ce1ba0fd4113ba3d6a73902c5873ccf0d9fbd136871bddbcb2b3ccd526d3b5593a8bbe3213bbc261b303a28a5023fc916fd3daa7233bdb0905e3c00000000000000000eafb4b89c30613c18b6843c19a5c63b35b202bcc4a55b3bdd661a3ba5ba1ebdd2529bbd179c1fbd62778e3cbc7d1fbc85d5a53c90096fbd1801e63eea2d7f3eb72b7abdfe51553c0000000000000000deab9f3bbe6fdb3c060368bb451109bb3fd37a3ab38dbc3abae2ae3ba223b7bd775167bda84b273c525b953b18b516bc795b043c912c66bc4f48093f3027e13df42441bdca155d3c0000000000000000dcc93b3b75d3d53c7ebe5abc6a058e3ab7d7043b0cc223b95108153c562db7bd70393abde2b8aa3c3ee61bbba50452bbb9ae15bcdb49603ceaa9083f998ea13d81fe16bd407e3d3c0000000000000000ced3603b2ad5383c5bffba3c9ae48c3c4de04fbcaaa61f3c083d103c1c4aa7bc220fe0bda0241cbde2d1853b8e323ebc553ba93cfb51b2bda239f13ec82f783ed0e955bdd4d1a33c00000000000000009acef53b72ddd23cf5061ab907f85fbaa7c21e3bd9ed023bcaec243cac36c8bdad3f33bd72515e3c01a257bb0e7e31bc17a3703b4ce1dcbb1b1c103fedf84b3d500dd6bcb5ad413c00000000000000000a4c3e3c1920883ca6685abc6b493c3b8e7059397f4b78b995e203bb3514c8bd757b91bc517b823c487868bb1c9a46b91dda78bbc921b83cd56c113f120c223c39dd56bcce4e833b00000000000000003a2b063b296e48bb23b3923ac30a78ba50c90ebbbfa99d3a3e1988bb410e663c0391cdba400ea13b6e8a473c9ffa28bbb0ad063a2654653ce7a98a3ef1e53e3e0bfde73baf0e0f39000000000000000093fe873a5d53e4bad36bbcbabae708bbf2d529bb7b81d83abd89e43a46d5313b09f87dbb1fc02b3cb0dfa73c71935ebbae1c8cbb52289c3d7a7da43e8f5dac3de74db53b9445c2bb0000000000000000f51c043ae5dc95bbff9abc3a4d9a0abbc771f9ba08d02d3a80761dbbf913ce3c5841b5bc9e537fbb1b47c93c73d2abba7eb0213b0d15ff3d6d5bab3e02a0273d9cfda0bbe5f83fbc0000000000000000be5a2a3a9e1ad5ba322c793b3f7a6e3b035015bb3371d4397fc2caba9ba4103cc154c5bc287da5bc9de5023cbf8524bbb3ed813bf98a9cbc1867993e7cb3833ee36d9fbc82009a3b00000000000000004283a03a28e4b7bb1614133bec8590b9aa69aeba03f3e839a889f8bbb9778c3c9b5f9fbc29d562bcbed25f3c3d5c92bb04a40a3b97ce713c9c99a33e8cd2443e41ea0ebc16f805bb0000000000000000f634963a6ab443bc26a292ba280800bb47b4b1ba13985b3a9d9278bb46cbed3c768740bcfc513abc15ddf73c7628f5bb12c5283c700a8f3d82dc923ebc71103e7dd19ab99d7595bc000000000000000069fe533989121ab98930763be9bcda3b1d7490bb71a1333adafdb2b9c2f42039ea0910bd9e030bbd97e8043c92fb9abbeaee9b3b909f05bd1c86a53ee96c953ea3ce14bdc76d063c00000000000000009c5b84394e919eb943c2833bd701983b39036ebb163e3c3a5bab62ba7bc071b9eda31fbdd01d0ebd0d12773c9e20c8bbcd6e013bd6789dbc5efbb23e0115853e973622bdd70ff43b0000000000000000197fa63a64ad2dbc4c826f3bb2ae81baabd5353a2b8eb839a9e10cbcce7c823c72f9e1bc85bbbdbc068ca23c4290d9bb8b55133bc338013de302ad3e35a6453e7362a7bc37a00abc00000000000000008ff98339aea6023b37e4f13b3d63273cde8c93bbffd0b23a6ed6c6ba2bd9e1bb9fbc4abd550447bd041bf23b931da0bbe256363cebea3bbd9171b23effdea13e9cb159bd3a232c3c0000000000000000b1cc7aba5455f33bcbc6633bab860b3c0503bdbb94aac93a53d366ba23b989bcc6fa47bd60523ebd2e05a53cfe31dabb29ed1b3cab57ecbc76d2bd3ee551923e406f77bd8bec0a3c0000000000000000278335bb7825d73bf260653bfe79013baecd92ba00c4913adf41003a303cacbca41616bdb2284abda35a0d3dc3fc34bca112223c2f0a0abc47b0c73ebcf16e3e964a52bdda32a73900000000000000001b08c03979eddf3a2a17633ca911273c88aa82bbc4b3993a9ce93bbbeb6fe6bba56481bd849c63bdeec5203cce686fbb7f68913c360e68bdfb71bc3eaed6a53e040584bdaa502d3c0000000000000000e4d16cbab835503cd79fea3b6b5fab3bb2afc2bb21b0123b5dfcbcbb650ce6bcba4b7fbd750022bd2b07ba3c9e46d2bbfd6e9f3c65fbe4bcc193cb3ea3388f3e2bb29ebd097cf83b0000000000000000db85a5bb9a04bc3ca780c439e79210bb0deb14bb823fb23af7ae17bb95b22bbd04dc5bbddce807bdf210093d3cf8e2bbf4148b3c115cfbbbb185d83e5842693ede0791bdf3a465390000000000000000cb21113b3af61d3b9098993c1b9f1e3c7b43b2bbb84de03a4a97d1bbc69561bc20d38fbd71d16cbd059d843c76c3bebbafd2cc3c259a71bdec3ec73ebbeba13ef0a097bd8c5f363c00000000000000004ecb8d3b1e0f663c310f213c0ab06ebbb7200bbb9454063bffbf56bca0414bbdf9d97fbd9ae3babcbd3cd23c15fa1bbc7fe2e63c9d6938bc868edc3e2d037a3e1b3cc1bd35d3213c000000000000000041efe63a9a81d53cb37600bcbc807cbb183bcb39feef723aee881ebc55f68bbd680446bda30a4dbb12adba3cec63dcbb2cd5503c25caf03c36b0e43e9ff53c3e1d4dadbdaf66ee3b00000000000000008c700e3b125eef3bba399f3c543e0d3c811cddbb174b223bfa6dd1bbb3e4b7bc09339ebd2c2456bd8545903c3c47e8bb3b36e03c758776bdd5ded33e4d57983ed12e9cbd0ca4493c000000000000000021192a3cecd9883c2811083bb9c1cebbfbf43d3a5c680f3bc247a9bc58d88cbd9fe861bd0f300b3b1bcd953c5ef344bc0c90fd3c6664b93b2e34f23e9c793a3e9700c6bd096b7b3c0000000000000000c04d343c3c83923c3a7168bc970f313954df1b3b9a40ce38811089bc12fdb7bd88b5c9bc8ffa8c3c67a5de3b3eddd2bba7cf06bbca67a33d40b3eb3e1c5dfd3d5376a8bd981b893c0000000000000000654eb13a87dc7d3ca30e6c3c665ec63b48df04bc817c573b3b87b2bbdc4610bdf7d39bbd06fe1bbd60df903cb1e914bc025ad13c167054bd7066df3e0e99853e7a428ebd270e493c000000000000000077ee853ccf6e8b3cfed5cfbb7e4e52bb96db953af491393b7b91d9bcdfd7a4bdf5a634bd4b3b923c3baf183c540964bc9270db3ca773bf3c7e1a023fe9dbef3d8a8bacbd418d9a3c00000000000000001c3aac3c63cda73bdf6d53bc2452ce3a47216f3be16f01ba94c3dbbcb88fbdbdcbe74abc54cde33c527938bb5010bfbb8ca606bcc04bdf3dce12ef3e2aafae3d0a15a4bdded6b13c0000000000000000ba15bd3b5504383cc9a1cf3cb853873c5b3054bc1ed2433c3e9eacb730599dbcfa2ce3bddba62fbdeae9133cddce2dbc65faf83c34f9aabd1a54ea3e6080833ed1fd70bdcc11683c000000000000000029d98c3ccfb6c33cfe5b8dbb134e22bb61850d3b2e44b53ba538dfbcf111aebd6cd40fbd0610ab3c0eb8edba616388bc3857a73c232bb63cccc20f3f9d95073de8c74fbde3ef853c000000000000000047e9dd3c347dfeba513b46bc6724b63bb140783a362be2b8e89b27bd06adadbdc347893bfbeaa43cfc1427bc0dbc05bb138443bce511fc3dfbad023f951240bce29101bd558c823c0000000000000000dfe8df3aaf2f22bbd66e2e3af071fdb8975605bb4054a53ab70fadbb4bc84b3c7b3c8539fbbaa83bc031433c517e60bb3229073b9a0e8a3cfb67833e3d02483ee660063cc383603a0000000000000000d1a5ed3aaed42bbb81f5cfbab993163adba06fba796fcf3a0ea489bc28af5dbaa1daf13b2ed2643cd07a833c38bbabbb62c00b3cf827063ee1d5863e2a8ea83dc680d23b5300a3bb0000000000000000ea39c7387df528bb592811bb9d9ca6ba3920a939947d78390255e5bb7c3669bb8a92223b057c183bdcecc63c3e4e82bb1533963cfaa0693e250f5a3e7bc2253d64cf583b51824abc00000000000000001eeb023af215c9ba2ab8733b5992613b1bc8fdba2d86ba39b6c6e9ba1f4e003c11f3bcbcf6eca4bc039ffd3b70662bbba83f933b16858ebc3df4953e4cce853e38bb97bc5b95993b000000000000000045635f3a1ca68ebbadb5bc3a0cea9538e07a73ba1505d3392aed0fbc39ef3a3cea4752bc253d44bc1f9b363c50bdbcbb04e48b3b21ccdf3cf431953ed70e4c3ef960c5ba264ebcba00000000000000006250253ad5d41dbc98a50fbbb1f95b3ae68955ba8bf0303adc6966bcd05b973c3df6683b6de73abb00caa93c45622bbc41f9853cc0e3093e23705e3eebd2063e39180a3ca58758bc00000000000000002ade4339333706ba6383873bb270c03ba03b77bb6ba20b3a5c71a3bad983083a58570ebd09b308bd4301e73bf0a48ebbd8ddbc3bbd1a01bd41fba23efc0d973e0cca12bd7e4c023c00000000000000003897ce39b9cd70ba798f963b0762423becb111bb982dd339765834bbbe4a0fbbe2eb0fbd7e6607bd9e12553c31aec7bb40f0af3bbfcc5fbcbdd7aa3e83b7873e66d80cbdf49fa13b000000000000000066ccb23a860515bcb87dc13b10116fbb2ee34d3be8e0d6b78c0c20bc81fbdeba036685bcff30b7bc8b1a8e3ca34e1dbc86251d3cff674e3dab7d9d3ea4554c3ee5112cbca1eb42bc00000000000000008e7aea39bc99b63ad958f33bcb291c3c564777bbce4c903ae71622bb178acabb5f3c47bd2d6243bd83b6bc3b680089bbb17f463c4c393abd9a26b03ec047a33e4e3c56bd63c0233c00000000000000003167edb94136b53b8c969d3bdbe3c73b76ac95bb47e4853aef1f90bb701c87bc904e36bdfdae32bd6aa08d3ce8449ebb32bb773c1642c7bcfa42b63e5266943ee63d64bdb891533b000000000000000052a68639c8caa0ba0c9a783c2f5505bca7a47b3be4424fb944177437231320bd90bf90bc914065bd0e60213dfd4059bc33e5bd3c586e26bbda2cbf3eda876f3e99892abd83dc1abc00000000000000000ac9ef3973a9b43a74bd573c75a8263c0ac067bbc50c793a235f6ebbeda1babb38e27dbd5dd561bd37b90d3c29204fbbabfe943c5a4064bda080b93e5bcca73ea37f84bd9d1d2d3c0000000000000000e9dd27399ac72f3c36b9eb3b8e17af3b7a14c6bb4c8ed63a20b954bc37e1d0bcd0d869bd0fe121bde3eaae3c664150bb34e1f13ce632b5bcdf4dc13e5d3b953e9a4ba0bd831784b90000000000000000e579c8b7dd99873cb09f753b94cfaebb87ffe6bacd38473a9379a7bc1a6638bdc4f51ebda16cf5bce75c093d67c480bb5e6b293d57d8243cde38c73ed098753e097f9abd026f69bc000000000000000037c7e93a35f10f3bfd4a8b3cea59243cd14996bb0e15a43abb13f0bb05d11ebc57748dbdc8456bbd87d9693c2e8298bbc5f4cd3c18246ebdda24c23ee38ba53ed32496bd442f243c0000000000000000e684c73b7183253cddd81c3c565579bae2069ebbf790173b8a1dc9bcf14c1dbdeed36ebde801e2bc937eea3cb492dcbbdc712f3da40b1fbc5fe8ce3edf36893e7302d0bd41a3803a0000000000000000093b453cef39353c46aee5bbbad768bb708087ba0870843a9e5c49bd13c04cbd6920f1bc9893293b6bd6cb3cbf4a87bb74fd5b3ddb775e3d9788c73e6e2f583ecf9fdcbd229f09bc0000000000000000bf8f4d3bbcfba73beab99b3ca34e163c29f8b9bb2f5e113b79ff1cbc4c3d88bc18209cbd711a59bd1863703c343ccdbb2eb4ea3c53f974bd59dfcc3e4c009f3e013e9fbd2a18493c00000000000000002397743c11d0063c1fc0ce3b3ec3c3bb2a9439bb277f743b84ac1fbdc81b43bd1bd763bd4926abbbf474e33c8cf63ebc65274e3d8fa2fe3b56dedf3e0494633e7edaf4bd0457123c00000000000000004767c83c5163a8bbf25b1ebc8d65d0ba86c3fd3a6867113aa64395bd18f756bd2c5cc4ba6e4aa13c608b6c3c08e5f6bb96d7503de8a8e53d0f9ec73e30551f3e1bfe01be6cfb033c000000000000000098ad673b7ca5423cbbb3773c8218d93bb5a2cdbb1e2d193b90662bbc67afe2bc52559abdb76126bd6a2e733c947cf4bbe22be83c548750bd773ed63e17be8e3ede5a94bda3c6383c000000000000000005a6ae3c2435253c6c6aa2ba5b649abb58187bbbf302d53b052342bd0bc250bd75685fbda3374b3c6cc0bc3ca11389bc7c593d3d1324c33c3ab6f13e122e2a3e815cf4bdaaba8b3c00000000000000003b56113dbe509fbc1862f6bb8b2328ba1711833b1e7ec939950fb0bd6b1d3ebd0cccf23b11ece93cc065d93befb424bc54ea333d7211153e7b76c93eb31dfa3db97910bed8fdc03c0000000000000000ad87c63bc046413cf547d03c7fb68e3cad322ebcc513493c45f4c2bb7c2471bc0ec3e0bdffdd51bd96455e3c7e5859bc40b00e3d2633a1bdca0fde3e043b913e2f218fbd3b617c3c000000000000000038e7be3cadf0c33c9de6ec3a204ca3bbd6a1b4ba8277173c820150bd4bbc1ebd59af88bde8e3843c56083b3c11f8b7bce428e23cc10ac23ccc18093f85f0a33ddd4dbbbd42acc23c0000000000000000f389343d0928cbbc41a2bbbb5b44623aa3db6b3bef30ee3aa148bfbdf8d209bd13b3f43b7b83e93c6e3624bb05355fbcaa86503cd5d4503efdbcd23e3104033d0bf4e6bdc569233d000000000000000048a6ca3a42acedba09ba5e3a5b55b2b5a5b0fbbac907a43af3dfbbbbad473b3c7ecbc33a6afca43bca0e483c7cab89bba9a6443b9146903c0ccf773e530b533e9586273c8241703a0000000000000000f336c13a94ff57bbcb3857ba4be4be3a56a9c13885f9a73a75f29abc8c863a3ac592893cc2588c3ce0042c3cebca0bbc55ceed3c12a4d93ddbab663e5ec0e73db8f3c73b6285163b00000000000000000ff6d5b7a9a4dcbb416d703b2888663bc7e5df39e39532398463d7bc06a3ed3b05e1eb3c30fd183cffe1be3bd73d81bb7314f33d80702a3ee1a10c3e6368883de6670ab97f4833bc00000000000000000816eb39a48cccbae0a2683b97c4523b0ef3f5ba6c12a739755306bbaa46f33bd473b2bcfe25a5bc4a9cf93b53bc27bb0bd29e3bc05085bc1e11923ee35d883e518f8fbcd4439b3b0000000000000000c24b0b3a25b436bbbf4f883a1b90043a72ef31ba19f2a6390ab616bc8a09ef3b54360cbc97de0cbc5eaef63b31a4ecbb89dcf53b1ce5dc3c1896873ea4d0583e7fcff63be102a73a00000000000000009f285b39cf8fe5bb2fc9b3394f42983a80e7afba918cab39d6bec3bc5c98cb3b5764783c46d8513c9f9b3c3c89c95dbc1c57633dd7b7bc3d6ee0423e3ed1143ebf48b63cac9ef5bb00000000000000006cd8863953fe8fbaa7aa8f3b0ce0a63bfeee3ebba28ee339d0b41bbbe664c33a6b080bbde31107bdf5a2b73b593b81bb9e08e63b5cbe01bd1a46a03e46ea983e77c10dbdc18ff73b0000000000000000e7cb8f398a536ebad12e8e3b6592123b2499b6ba9255723985cda0bb5a05c6bab94903bdc4e4fabc9edb143c7e1acfbb2c13023c59783bbcee28a13e095f8b3e4d1cd8bc433a923b0000000000000000b2a1463ab86fb2bb1c57883b6273deba8b1e133b1d7326b889f95ebc2c3208bc70c728bc2a457cbc35a5053cc4823ebc1a37903c84513b3d98cf8d3ed6ca5c3e9e83813b1bb10fbc0000000000000000a750123a48c49d3959ec003c93520e3cde503fbbe3fb7b3ad4aa3fbb175f94bb0f0243bda8fd3fbdef085b3bb66c6dbba600473cf3603abd96f2ac3ea836a53e30b44ebd8ea0253c0000000000000000c33492b9ca11403b57e39f3b6c63a23b9b8f4ebbe843243acd0ed2bbe12e3fbc577924bd8b3d23bd36e02f3ccb2984bb3951873c804bc0bcb040ac3e63c7973e1e903dbda114ea3a0000000000000000cb30a639fbe90bbbf97e363ced8661bbdf5def3a9b42b0b9eb5c19bcaf2bd4bc478fb0bcb09925bd943eb13c8e110abcc638de3c4802fc3bb3bba93e48ad803ec55cedbc64c844bc00000000000000009d4d303a44878f393038463cb18b2d3c10cc47bb7f063d3a41366abb9d1e38bb22a275bd924463bd0849d83b06e30abbe93b8e3c37b867bdb89bb53e5c89aa3e2b4f81bddae12d3c0000000000000000fdca85b94fd6d23bf7dbfb3bf576c73b1efb94bbb8f54b3abf1148bc1e928cbc66b856bdf49a2abdb96c6f3c3ca425ba7ea6ee3cc632d8bc6025b63e02ae9c3e5dc98bbdb2ff42bb0000000000000000231cbeba641b173cb97fc43b24be0fbb05e26dbb11372c3a8b2503bdc667fabc6a9b11bdcf5ac5bc3c06d63c4da54e3b1a01823d8448783c7d71b13e8eff853ef23190bdccc003bd0000000000000000a65f94b836c4f13a9981623c5b3b1c3cd0af31bb1c76abb9b53092bb978f1cbb00be86bd0c296cbdd8ad4b3ce13bd7ba8497a43cb7606cbd2ad9ba3eff00a93e2bcf8bbd118d073c0000000000000000fa661e3b4ee9e13b8c982b3c7980483b1637a8bb98c97a3a407699bc6886bdbcd3c971bd576417bdedf4c33c5f1ae9babff51c3d8f9bb0bce743c13e0f85973e57afb7bd97c260bb00000000000000006fc0113c2297a33bcf92f3ba5c6952bb189c9cbb9d25c53a902d84bdfb750dbd54e1b3bca9a692bbd05b0e3d8eb1913bff44d03d8883253d1ab4b43e23fa763e0f23e1bdab813abd00000000000000001fb9553bf95f383b2b0b8f3c73d42e3c11ab88bbaa6eeb3aaa4331bcd1a420bcb43c94bd183167bdb574373c0f73c1bb0ef2e43caaf07cbd2a65c43e4fcba63ef6fa9bbd14f5533c00000000000000004c4e233c4627ac3beff3463ce14002bb33ca9ebb6076ea3a4659f6bc9ec1fcbcbfea81bdbe3bb1bc0d1ce93c9a36b0bb8bfd343da499efbb9eb2ce3e784e8a3e49deeabdb1ba953b00000000000000004457d03c4cc434bc7367ddbb9ca14fbba00d66bb245a163b09ebc6bda755e5bc929a6fbabe426e3cb6060b3d91bc00b9fa1bf03dd609ad3d363db53e5b194e3ee6e217becd3e0cbd0000000000000000a8da8f3bda23ed3b49617c3cddac013ce37258bbaf206d3a608c46bc4e869bbc28e491bdbe7f39bd0131203cb360cfbbda45e13c36df5abd587aca3e948b9a3e1f3294bd71ba4e3c000000000000000096e28c3cdec3fc3b8e24143c873546bb1f7401bc034b823bca0c15bd9f2a17bd92a88dbdee47c4bbdd09fd3cc4c735bc45081a3d614e383c8cd9dc3e6e006d3e13adffbd3e4b733c000000000000000049b2243d525bc6bc07f8c4bb9091a5bb7c0b15bb0efc523b9b68dfbd31b9b4bcac837dbb1503023d4138f03c7574a3bb3e37df3db6f3e13dbc7ec33e24a8283e26063cbe4f4316bc000000000000000061c8743b64a7283c3928d83cf38f843c0dd1b8bbab6a0e3cb8a30ebc21c20abc4e3fd4bd502182bd81069a3c316e88bcd6010a3d6f6691bd56fdce3e7d89a13e36aca4bdc7d0a73c00000000000000003952b73c1380b73cb42f1a3c121b0c3cf4ad30bc8bea323c5c3022bdd5ba03bdc422acbdeb0437bc76b5a13c9b61bfbca12d093c4698243d9d7eee3e2b08323e0f2bebbde7990c3d00000000000000002075633ddd59f2bc91725dbb24b214bc27f72bbbe356b53b0872cbbdc32caebc58d79abcac824b3d542ae43c84dea9bc91bd263d77c55a3ea337dc3e30a66e3db38a5abeb681173d00000000000000007996bd3ac338f3bafc91633aedc4aa38d4d102bbb0c8b23acc13b8bb6c2a3e3c8a783b3bd0fc933b84e83d3c20029dbbf036413b2192813cf2486a3e6fcd5e3e84ee563cfaaeda3a000000000000000023e9633a9e2c29bbf202613a11e47a3a14e6debaf561693aa12e59bc1f91133ca571883ce9488b3ca5304c3cd03e02bc3985bf3c2cae663d9b30503e60cf1d3eb09c9f3c31cf263c0000000000000000e034adb85c71cebb50c73d3b0ea89a3b6b591c3b03550c3a70cebbbbce3278bc5f525e3dee8b203dacb210bc6bdf2bbc7291143e5f341a3e0d4af13d8e13323d2479e0bb4335f7bb00000000000000009d70c4391ce0c8ba2c825b3b9c615a3bcdc3e1ba8a4dbd393fd71bbb571feb3b7e74abbc2999a6bc72c1f53b84ce2fbbea14a53bac9f82bcea6f8e3ed71d8b3e51b186bcb782a13b0000000000000000bc58a639c213ceba34c97f3a2aa1773ac82673ba9e7a903914ae13bc42b7993b2f6bcabbf7f4cfbb4884a73b6e130ebce2d1f93b092bbc3c3fab783e0e88673edb96803cf0f3a83b000000000000000010c3fc37ab3256bbde87073b5639fa3a688fb9ba5c9bcf3862a59fbc9b825fb95363a63c530a9c3c3c0c0eba7e1083bc5d1d543de4ca5d3d9f81393e70012a3e5cded83c3d6c923c0000000000000000c114a039a27ee0ba4b7a933bddc49b3b464217bb26eec739933755bb39733d3bb79108bd2f6107bd90c0893bca587ebbbc4def3bd5da02bd698c9d3e16f39a3e28bb06bd1d69fc3b0000000000000000dce63539b62e75ba459e673b3bee353bd96f8bba83c526393bf7d7bba833743a7a61f2bc6455ecbc9465993b930ee7bb5d24093cd02c51bca18e973e896d903e5e2396bc255fd33b00000000000000001c6ea0380adaaebaf080ea3a1549833af49deb391897923731ab85bc88d914bc1f6beebb765008bc25913bbb2b016bbcb7cd933cc6881f3d652b7c3e9fdd673e59d4b43c9bbd913b0000000000000000c2832c3ae62c3bbab1c7023c9b95063c3d4df3bad2053d3ae4ca4abb17861cbb41f33ebdbd363fbd8724053aa6a144bb9dda3c3cd9e13dbd94f0a93e547fa73e10e146bdf0ac2d3c00000000000000007cb2fab7b3ba2c3a41758f3beda28c3b403f9abaa0757939827fe1bba8a0a2bbd2f516bd62de15bd68c1233b924bacbb0f06553c19c7d5bc8c5ea23e52e19b3e55240ebd6177c13b000000000000000021b380b9ad68e3b840897e3b5f21193b2d79e439ba0f44b9ba7082bcf2601fbc3799bbbc7c4fc0bc71b466baf70e1fbc9affb33c89cf033cf3c2923e7202883e22c9f1bbb02bce3a0000000000000000d2558039efc6ddb976072b3ce870303cea1309bb1e5b023ab52b07bbe651833afc656dbddbf962bd967f6c3bdebeb9ba40a06f3c12816dbd990fb13ea56aad3e2d4376bd7cb3403c00000000000000008c56abb9d0730f3bd1bfde3bf5f4d83b824fc6ba0efcceb7cf38ebbbed4d06bc7fa43cbd0ebf31bd10b8503ba863daba814e9c3c3a9f12bdb038ab3ec36fa33ed5a051bd57027b3b0000000000000000025e5aba247dec3a8fc28a3b84d82b3b791a8cb974767fb9ce76d6bcbe907dbc3fdbcebc929fc0bcb0999f3baccb07bbece6433dbfde5b3b96239a3ecf398e3e3c4d06bdbfa98abc0000000000000000fd8b8dbb0d59df3a5206ea3b01eabc3b7e99d4b7e3f685bbef39503b380b683c920279bd9b316abd13b1933c286f9c3ba985ef3b61dc60bd51beaf3e2ed9a93e29fe6abd8ae9d43a0000000000000000666855baa4a94d3b1460013cfe87b93b43ffbdba90e17aba46c307bc98e399bb633a5ebdfd433cbdb42e4c3cef44a6b9ba85b03cbb5f18bdcadeb13e1b12a33e70e081bd0d27443a0000000000000000b6d72a3ae1dd093ba8ec983b697de53a6f7d85ba613b03b9a94b3ebd0541c6bcb6f6cabcd6f999bc15c0963c58c7c63b33a5ba3d9a1e823c68d2a03ec7968d3ecbd88abdb02945bd0000000000000000092f4a3aee3d9f3a0d78613caf003d3c84e0b1ba968fffb6b6c3d7bb2d8bfab9624c87bdcd6176bda5d9e63b165276bb4b0ead3c7c5a85bd49a8b93e442faf3e563891bd17a9683c0000000000000000a210093bbe46453b93e5233c155fab3bef62daba607e26ba254359bccd355bbc2b0465bd664721bd5eda393c88be01bbac08e33c80750dbd9011b93e0feaa03e3c89a6bdf9c0e23b000000000000000036b9333c73e65dbba716343ba0e0dab8f24b1dbba34e1a3a94faa1bd10cafabc215fb8bc04b563bbc83b113d82113e3cbbb30b3e50c6533d78a0a73e66fe843e4c90fcbd82ef92bd000000000000000018bf5a3b72a03f3be8d6573cf6342f3c9d4266ba581c9f3a4dae17bcb51c14bcfbfe7fbd9f5c55bde510843ae32db9bbfe95b83c5b3575bd3f7dba3e6e04aa3e5db688bddf51733c00000000000000000f22163c69537b3bc975213c1a35893bfe206cbb6ca6f83abf6cadbc109cb0bc26776ebd15b7e9bc9d60343c38f2fbbb83e9e23c6e26bcbc2fd6be3e44ea983e9e4eb6bd75c1603c00000000000000000f2ae63c33250dbc655bd838d42825bbe97cc7bb7ba59f3abcefc8bdaabe2abd1a48e8bc5c61653cb7303c3d15fa593c79b4143e5ed9a83dad45b93effff6e3ec64533be9e6985bd0000000000000000eeb63d3bfa99343b45fdda3c3e71bb3c10de02bc17850b3c0d0a21bc86abdb3b3f96bfbd3425a6bdc949a73cad447dbcb6c6e13c3e8d9abd78c0bf3e4665b23e4363a4bdcf73b63c00000000000000003ecc773cdb1d323c6292ac3c796e7e3c55b7d538a7b6f23b7340a9bc1f5402bd86458fbd6de94bbd4481b2ba59a965bcc436da3b94a9a63c6157bc3e37fe8a3e55ce8dbded34a73c000000000000000093861d3ddc15043ccd20953b4c6010bcd6505cbbe6d007bc848968bdcee2d7bd364081bdf62f6a3d837b193d3410613c66fc7a3dbf235d3ea1aeda3e8ad5f53daa6e50be9b6f0dbd0000000000000000\n"
>+"";
>+
>+const size_t ravu_r3_compute_len = sizeof(ravu_r3_compute) - 1;
>diff --git a/modules/video_output/vulkan/shaders/shaders.h
>b/modules/video_output/vulkan/shaders/shaders.h
>new file mode 100644
>index 0000000000..91b0ef5b37
>--- /dev/null
>+++ b/modules/video_output/vulkan/shaders/shaders.h
>@@ -0,0 +1,39 @@
>+/*****************************************************************************
>+ * shaders.h: Built in GLSL shaders
>+
>*****************************************************************************
>+ * Copyright (C) 2020 Niklas Haas
>+ *
>+ * This program is free software; you can redistribute it and/or
>modify it
>+ * under the terms of the GNU Lesser General Public License as
>published by
>+ * the Free Software Foundation; either version 2.1 of the License, or
>+ * (at your option) any later version.
>+ *
>+ * This program is distributed in the hope that it will be useful,
>+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
>+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
>+ * GNU Lesser General Public License for more details.
>+ *
>+ * You should have received a copy of the GNU Lesser General Public
>License
>+ * along with this program; if not, write to the Free Software
>Foundation,
>+ * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
>+
>*****************************************************************************/
>+
>+#ifndef VLC_VULKAN_SHADERS_H
>+#define VLC_VULKAN_SHADERS_H
>+
>+extern const char fsrcnnx_8_0_4_1[];
>+extern const size_t fsrcnnx_8_0_4_1_len;
>+
>+extern const char krig_bilateral[];
>+extern const size_t krig_bilateral_len;
>+
>+extern const char ravu_r3_compute[];
>+extern const size_t ravu_r3_compute_len;
>+
>+extern const char ssim_downscaler[];
>+extern const size_t ssim_downscaler_len;
>+
>+extern const char ssim_super_res[];
>+extern const size_t ssim_super_res_len;
>+
>+#endif // VLC_VULKAN_SHADERS_H
>diff --git a/modules/video_output/vulkan/shaders/ssim_downscaler.c
>b/modules/video_output/vulkan/shaders/ssim_downscaler.c
>new file mode 100644
>index 0000000000..7cfd19dcea
>--- /dev/null
>+++ b/modules/video_output/vulkan/shaders/ssim_downscaler.c
>@@ -0,0 +1,307 @@
>+/*****************************************************************************
>+ * SSimDownscaler by Shiandow, adapted for mpv by igv
>+
>*****************************************************************************
>+ * Copyright (C) 2017 Shiandow
>+ * Copyright (C) 2020 igv
>+ *
>+ * This library is free software; you can redistribute it and/or
>modify it
>+ * under the terms of the GNU Lesser General Public License as
>published by the
>+ * Free Software Foundation; either version 3.0 of the License, or (at
>your
>+ * option) any later version.
>+ *
>+ * This library is distributed in the hope that it will be useful, but
>WITHOUT
>+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
>or
>+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General
>Public License
>+ * for more details.
>+ *
>+ * You should have received a copy of the GNU Lesser General Public
>License
>+ * along with this library.
>+
>*****************************************************************************/
>+
>+#include <stddef.h>
>+#include "shaders.h"
>+
>+const char ssim_downscaler[] =
>+"// SSimDownscaler by Shiandow\n"
>+"//\n"
>+"// This library is free software; you can redistribute it and/or\n"
>+"// modify it under the terms of the GNU Lesser General Public\n"
>+"// License as published by the Free Software Foundation; either\n"
>+"// version 3.0 of the License, or (at your option) any later
>version.\n"
>+"// \n"
>+"// This library is distributed in the hope that it will be useful,\n"
>+"// but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
>+"// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
>GNU\n"
>+"// Lesser General Public License for more details.\n"
>+"// \n"
>+"// You should have received a copy of the GNU Lesser General
>Public\n"
>+"// License along with this library.\n"
>+"\n"
>+"//!HOOK POSTKERNEL\n"
>+"//!BIND HOOKED\n"
>+"//!BIND PREKERNEL\n"
>+"//!SAVE L2\n"
>+"//!HEIGHT NATIVE_CROPPED.h\n"
>+"//!WHEN NATIVE_CROPPED.w POSTKERNEL.w >\n"
>+"//!COMPONENTS 3\n"
>+"//!DESC SSimDownscaler calc L2 pass 1\n"
>+"\n"
>+"#define factor ((input_size*POSTKERNEL_pt)[axis])\n"
>+"\n"
>+"#define axis 0\n"
>+"\n"
>+"#define offset vec2(0,0)\n"
>+"\n"
>+"#define MN(B,C,x) (x <= 1.0 ? ((2.-1.5*B-C)*x + (-3.+2.*B+C))*x*x +
>(1.-B/3.) : (((-B/6.-C)*x + (B+5.*C))*x +
>(-2.*B-8.*C))*x+((4./3.)*B+4.*C))\n"
>+"#define Kernel(x) MN(1.0/3.0, 1.0/3.0, abs(x))\n"
>+"#define taps 2.0\n"
>+"\n"
>+"vec4 hook() {\n"
>+" vec2 base = PREKERNEL_pt * (PREKERNEL_pos * input_size +
>tex_offset);\n"
>+"\n"
>+" // Calculate bounds\n"
>+" float low = floor((PREKERNEL_pos - taps*POSTKERNEL_pt) *
>input_size - offset + tex_offset + 0.5)[axis];\n"
>+" float high = floor((PREKERNEL_pos + taps*POSTKERNEL_pt) *
>input_size - offset + tex_offset + 0.5)[axis];\n"
>+"\n"
>+" float W = 0.0;\n"
>+" vec4 avg = vec4(0);\n"
>+" vec2 pos = base;\n"
>+"\n"
>+" for (float k = 0.0; k < high - low; k++) {\n"
>+" pos[axis] = PREKERNEL_pt[axis] * (k + low + 0.5);\n"
>+" float rel = (pos[axis] - base[axis])*POSTKERNEL_size[axis] +
>offset[axis]*factor;\n"
>+" float w = Kernel(rel);\n"
>+"\n"
>+" avg += w * pow(clamp(textureLod(PREKERNEL_raw, pos, 0.0) *
>PREKERNEL_mul, 0.0, 1.0), vec4(2.0));\n"
>+" W += w;\n"
>+" }\n"
>+" avg /= W;\n"
>+"\n"
>+" return avg;\n"
>+"}\n"
>+"\n"
>+"//!HOOK POSTKERNEL\n"
>+"//!BIND HOOKED\n"
>+"//!BIND L2\n"
>+"//!SAVE L2\n"
>+"//!WHEN NATIVE_CROPPED.h POSTKERNEL.h >\n"
>+"//!COMPONENTS 3\n"
>+"//!DESC SSimDownscaler calc L2 pass 2\n"
>+"\n"
>+"#define factor ((L2_size*POSTKERNEL_pt)[axis])\n"
>+"\n"
>+"#define axis 1\n"
>+"\n"
>+"#define offset vec2(0,0)\n"
>+"\n"
>+"#define MN(B,C,x) (x <= 1.0 ? ((2.-1.5*B-C)*x + (-3.+2.*B+C))*x*x +
>(1.-B/3.) : (((-B/6.-C)*x + (B+5.*C))*x +
>(-2.*B-8.*C))*x+((4./3.)*B+4.*C))\n"
>+"#define Kernel(x) MN(1.0/3.0, 1.0/3.0, abs(x))\n"
>+"#define taps 2.0\n"
>+"\n"
>+"vec4 hook() {\n"
>+" // Calculate bounds\n"
>+" float low = floor((L2_pos - taps*POSTKERNEL_pt) * L2_size -
>offset + 0.5)[axis];\n"
>+" float high = floor((L2_pos + taps*POSTKERNEL_pt) * L2_size -
>offset + 0.5)[axis];\n"
>+"\n"
>+" float W = 0.0;\n"
>+" vec4 avg = vec4(0);\n"
>+" vec2 pos = L2_pos;\n"
>+"\n"
>+" for (float k = 0.0; k < high - low; k++) {\n"
>+" pos[axis] = L2_pt[axis] * (k + low + 0.5);\n"
>+" float rel = (pos[axis] - L2_pos[axis])*POSTKERNEL_size[axis]
>+ offset[axis]*factor;\n"
>+" float w = Kernel(rel);\n"
>+"\n"
>+" avg += w * textureLod(L2_raw, pos, 0.0) * L2_mul;\n"
>+" W += w;\n"
>+" }\n"
>+" avg /= W;\n"
>+"\n"
>+" return avg;\n"
>+"}\n"
>+"\n"
>+"//!HOOK POSTKERNEL\n"
>+"//!BIND HOOKED\n"
>+"//!SAVE M\n"
>+"//!WHEN NATIVE_CROPPED.w POSTKERNEL.w >\n"
>+"//!COMPONENTS 3\n"
>+"//!DESC SSimDownscaler calc Mean\n"
>+"\n"
>+"#define locality 8.0\n"
>+"\n"
>+"#define offset vec2(0,0)\n"
>+"\n"
>+"#define Kernel(x) pow(1.0 / locality, abs(x))\n"
>+"#define taps 3.0\n"
>+"#define maxtaps taps\n"
>+"\n"
>+"vec4 ScaleH(vec2 pos) {\n"
>+" // Calculate bounds\n"
>+" float low = floor(-0.5*maxtaps - offset)[0];\n"
>+" float high = floor(+0.5*maxtaps - offset)[0];\n"
>+"\n"
>+" float W = 0.0;\n"
>+" vec4 avg = vec4(0);\n"
>+"\n"
>+" for (float k = 0.0; k < maxtaps; k++) {\n"
>+" pos[0] = POSTKERNEL_pos[0] + POSTKERNEL_pt[0] * (k + low +
>1.0);\n"
>+" float rel = (k + low + 1.0) + offset[0];\n"
>+" float w = Kernel(rel);\n"
>+"\n"
>+" avg += w * clamp(POSTKERNEL_tex(pos), 0.0, 1.0);\n"
>+" W += w;\n"
>+" }\n"
>+" avg /= W;\n"
>+"\n"
>+" return avg;\n"
>+"}\n"
>+"\n"
>+"vec4 hook() {\n"
>+" // Calculate bounds\n"
>+" float low = floor(-0.5*maxtaps - offset)[1];\n"
>+" float high = floor(+0.5*maxtaps - offset)[1];\n"
>+"\n"
>+" float W = 0.0;\n"
>+" vec4 avg = vec4(0);\n"
>+" vec2 pos = POSTKERNEL_pos;\n"
>+"\n"
>+" for (float k = 0.0; k < maxtaps; k++) {\n"
>+" pos[1] = POSTKERNEL_pos[1] + POSTKERNEL_pt[1] * (k + low +
>1.0);\n"
>+" float rel = (k + low + 1.0) + offset[1];\n"
>+" float w = Kernel(rel);\n"
>+"\n"
>+" avg += w * ScaleH(pos);\n"
>+" W += w;\n"
>+" }\n"
>+" avg /= W;\n"
>+"\n"
>+" return avg;\n"
>+"}\n"
>+"\n"
>+"//!HOOK POSTKERNEL\n"
>+"//!BIND HOOKED\n"
>+"//!BIND L2\n"
>+"//!BIND M\n"
>+"//!SAVE R\n"
>+"//!WHEN NATIVE_CROPPED.w POSTKERNEL.w >\n"
>+"//!COMPONENTS 3\n"
>+"//!DESC SSimDownscaler calc R\n"
>+"\n"
>+"#define locality 8.0\n"
>+"\n"
>+"#define offset vec2(0,0)\n"
>+"\n"
>+"#define Kernel(x) pow(1.0 / locality, abs(x))\n"
>+"#define taps 3.0\n"
>+"#define maxtaps taps\n"
>+"\n"
>+"mat2x4 ScaleH(vec2 pos) {\n"
>+" // Calculate bounds\n"
>+" float low = floor(-0.5*maxtaps - offset)[0];\n"
>+" float high = floor(+0.5*maxtaps - offset)[0];\n"
>+"\n"
>+" float W = 0.0;\n"
>+" mat2x4 avg = mat2x4(0);\n"
>+"\n"
>+" for (float k = 0.0; k < maxtaps; k++) {\n"
>+" pos[0] = L2_pos[0] + L2_pt[0] * (k + low + 1.0);\n"
>+" float rel = (k + low + 1.0) + offset[0];\n"
>+" float w = Kernel(rel);\n"
>+"\n"
>+" avg += w * mat2x4(pow(clamp(POSTKERNEL_tex(pos), 0.0, 1.0),
>vec4(2.0)), L2_tex(pos));\n"
>+" W += w;\n"
>+" }\n"
>+" avg /= W;\n"
>+"\n"
>+" return avg;\n"
>+"}\n"
>+"\n"
>+"vec4 hook() {\n"
>+" // Calculate bounds\n"
>+" float low = floor(-0.5*maxtaps - offset)[1];\n"
>+" float high = floor(+0.5*maxtaps - offset)[1];\n"
>+"\n"
>+" float W = 0.0;\n"
>+" mat2x4 avg = mat2x4(0);\n"
>+" vec2 pos = L2_pos;\n"
>+"\n"
>+" for (float k = 0.0; k < maxtaps; k++) {\n"
>+" pos[1] = L2_pos[1] + L2_pt[1] * (k + low + 1.0);\n"
>+" float rel = (k + low + 1.0) + offset[1];\n"
>+" float w = Kernel(rel);\n"
>+"\n"
>+" avg += w * ScaleH(pos);\n"
>+" W += w;\n"
>+" }\n"
>+" avg /= W;\n"
>+"\n"
>+" vec3 Sl = abs(avg[0].rgb - pow(M_texOff(0).rgb, vec3(2.0)));\n"
>+" vec3 Sh = abs(avg[1].rgb - pow(M_texOff(0).rgb, vec3(2.0)));\n"
>+" return vec4(mix(vec3(0.5), 1.0 / (1.0 + sqrt(Sh / Sl)),
>lessThan(vec3(5e-6), Sl)), 0.0);\n"
>+"}\n"
>+"\n"
>+"//!HOOK POSTKERNEL\n"
>+"//!BIND HOOKED\n"
>+"//!BIND M\n"
>+"//!BIND R\n"
>+"//!WHEN NATIVE_CROPPED.w POSTKERNEL.w >\n"
>+"//!DESC SSimDownscaler final pass\n"
>+"\n"
>+"#define locality 8.0\n"
>+"\n"
>+"#define offset vec2(0,0)\n"
>+"\n"
>+"#define Kernel(x) pow(1.0 / locality, abs(x))\n"
>+"#define taps 3.0\n"
>+"#define maxtaps taps\n"
>+"\n"
>+"#define Gamma(x) ( pow(x, vec3(1.0/2.0)) )\n"
>+"#define GammaInv(x) ( pow(clamp(x, 0.0, 1.0), vec3(2.0)) )\n"
>+"\n"
>+"mat3x3 ScaleH(vec2 pos) {\n"
>+" // Calculate bounds\n"
>+" float low = floor(-0.5*maxtaps - offset)[0];\n"
>+" float high = floor(+0.5*maxtaps - offset)[0];\n"
>+"\n"
>+" float W = 0.0;\n"
>+" mat3x3 avg = mat3x3(0);\n"
>+"\n"
>+" for (float k = 0.0; k < maxtaps; k++) {\n"
>+" pos[0] = POSTKERNEL_pos[0] + POSTKERNEL_pt[0] * (k + low +
>1.0);\n"
>+" float rel = (k + low + 1.0) + offset[0];\n"
>+" float w = Kernel(rel);\n"
>+" vec3 M = Gamma(M_tex(pos).rgb);\n"
>+" vec3 R = R_tex(pos).rgb;\n"
>+" R = 1.0 / R - 1.0;\n"
>+" avg += w * mat3x3(R*M, M, R);\n"
>+" W += w;\n"
>+" }\n"
>+" avg /= W;\n"
>+"\n"
>+" return avg;\n"
>+"}\n"
>+"\n"
>+"vec4 hook() {\n"
>+" // Calculate bounds\n"
>+" float low = floor(-0.5*maxtaps - offset)[1];\n"
>+" float high = floor(+0.5*maxtaps - offset)[1];\n"
>+"\n"
>+" float W = 0.0;\n"
>+" mat3x3 avg = mat3x3(0);\n"
>+" vec2 pos = POSTKERNEL_pos;\n"
>+"\n"
>+" for (float k = 0.0; k < maxtaps; k++) {\n"
>+" pos[1] = POSTKERNEL_pos[1] + POSTKERNEL_pt[1] * (k + low +
>1.0);\n"
>+" float rel = (k + low + 1.0) + offset[1];\n"
>+" float w = Kernel(rel);\n"
>+"\n"
>+" avg += w * ScaleH(pos);\n"
>+" W += w;\n"
>+" }\n"
>+" avg /= W;\n"
>+" vec4 L = clamp(POSTKERNEL_texOff(0), 0.0, 1.0);\n"
>+" return vec4(GammaInv(avg[1] + avg[2] * Gamma(L.rgb) - avg[0]),
>L.w);\n"
>+"}\n"
>+"";
>+
>+const size_t ssim_downscaler_len = sizeof(ssim_downscaler) - 1;
>diff --git a/modules/video_output/vulkan/shaders/ssim_super_res.c
>b/modules/video_output/vulkan/shaders/ssim_super_res.c
>new file mode 100644
>index 0000000000..b9b3ac3098
>--- /dev/null
>+++ b/modules/video_output/vulkan/shaders/ssim_super_res.c
>@@ -0,0 +1,276 @@
>+/*****************************************************************************
>+ * SSimSuperRes by Shiandow, adapted for mpv by igv
>+
>*****************************************************************************
>+ * Copyright (C) 2016 Shiandow
>+ * Copyright (C) 2020 igv
>+ *
>+ * This library is free software; you can redistribute it and/or
>modify it
>+ * under the terms of the GNU Lesser General Public License as
>published by the
>+ * Free Software Foundation; either version 3.0 of the License, or (at
>your
>+ * option) any later version.
>+ *
>+ * This library is distributed in the hope that it will be useful, but
>WITHOUT
>+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
>or
>+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General
>Public License
>+ * for more details.
>+ *
>+ * You should have received a copy of the GNU Lesser General Public
>License
>+ * along with this library.
>+
>*****************************************************************************/
>+
>+#include <stddef.h>
>+#include "shaders.h"
>+
>+const char ssim_super_res[] =
>+"// SSimSuperRes by Shiandow\n"
>+"//\n"
>+"// This library is free software; you can redistribute it and/or\n"
>+"// modify it under the terms of the GNU Lesser General Public\n"
>+"// License as published by the Free Software Foundation; either\n"
>+"// version 3.0 of the License, or (at your option) any later
>version.\n"
>+"// \n"
>+"// This library is distributed in the hope that it will be useful,\n"
>+"// but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
>+"// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
>GNU\n"
>+"// Lesser General Public License for more details.\n"
>+"// \n"
>+"// You should have received a copy of the GNU Lesser General
>Public\n"
>+"// License along with this library.\n"
>+"\n"
>+"//!HOOK POSTKERNEL\n"
>+"//!BIND HOOKED\n"
>+"//!SAVE LOWRES\n"
>+"//!WIDTH NATIVE_CROPPED.w\n"
>+"//!WHEN NATIVE_CROPPED.w OUTPUT.w <\n"
>+"//!COMPONENTS 4\n"
>+"//!DESC SSSR Downscaling I\n"
>+"\n"
>+"#define axis 0\n"
>+"\n"
>+"#define offset vec2(0,0)\n"
>+"\n"
>+"#define MN(B,C,x) (x < 1.0 ? ((2.-1.5*B-(C))*x + (-3.+2.*B+C))*x*x
>+ (1.-(B)/3.) : (((-(B)/6.-(C))*x + (B+5.*C))*x +
>(-2.*B-8.*C))*x+((4./3.)*B+4.*C))\n"
>+"#define Kernel(x) MN(0.334, 0.333, abs(x))\n"
>+"#define taps 2.0\n"
>+"\n"
>+"#define Kb 0.0722\n"
>+"#define Kr 0.2126\n"
>+"#define Luma(rgb) ( dot(vec3(Kr, 1.0 - Kr - Kb, Kb), pow(abs(rgb),
>vec3(2.0))) )\n"
>+"\n"
>+"vec4 hook() {\n"
>+" // Calculate bounds\n"
>+" float low = ceil((HOOKED_pos - taps/input_size) * HOOKED_size -
>offset - 0.5)[axis];\n"
>+" float high = floor((HOOKED_pos + taps/input_size) * HOOKED_size -
>offset - 0.5)[axis];\n"
>+"\n"
>+" float W = 0.0;\n"
>+" vec4 avg = vec4(0);\n"
>+" vec2 pos = HOOKED_pos;\n"
>+" vec4 tex;\n"
>+"\n"
>+" for (float k = low; k <= high; k++) {\n"
>+" pos[axis] = HOOKED_pt[axis] * (k - offset[axis] + 0.5);\n"
>+" float rel = (pos[axis] -
>HOOKED_pos[axis])*input_size[axis];\n"
>+" float w = Kernel(rel);\n"
>+"\n"
>+" tex.rgb = textureLod(HOOKED_raw, pos, 0.0).rgb *
>HOOKED_mul;\n"
>+" tex.a = Luma(tex.rgb);\n"
>+" avg += w * tex;\n"
>+" W += w;\n"
>+" }\n"
>+" avg /= W;\n"
>+"\n"
>+" return vec4(avg.rgb, abs(avg.a - Luma(avg.rgb)));\n"
>+"}\n"
>+"\n"
>+"//!HOOK POSTKERNEL\n"
>+"//!BIND LOWRES\n"
>+"//!SAVE LOWRES\n"
>+"//!WIDTH NATIVE_CROPPED.w\n"
>+"//!HEIGHT NATIVE_CROPPED.h\n"
>+"//!WHEN NATIVE_CROPPED.h OUTPUT.h <\n"
>+"//!COMPONENTS 4\n"
>+"//!DESC SSSR Downscaling II\n"
>+"\n"
>+"#define axis 1\n"
>+"\n"
>+"#define offset vec2(0,0)\n"
>+"\n"
>+"#define MN(B,C,x) (x < 1.0 ? ((2.-1.5*B-(C))*x + (-3.+2.*B+C))*x*x
>+ (1.-(B)/3.) : (((-(B)/6.-(C))*x + (B+5.*C))*x +
>(-2.*B-8.*C))*x+((4./3.)*B+4.*C))\n"
>+"#define Kernel(x) MN(0.334, 0.333, abs(x))\n"
>+"#define taps 2.0\n"
>+"\n"
>+"#define Kb 0.0722\n"
>+"#define Kr 0.2126\n"
>+"#define Luma(rgb) ( dot(vec3(Kr, 1.0 - Kr - Kb, Kb), pow(abs(rgb),
>vec3(2.0))) )\n"
>+"\n"
>+"vec4 hook() {\n"
>+" // Calculate bounds\n"
>+" float low = ceil((LOWRES_pos - taps/input_size) * LOWRES_size -
>offset - 0.5)[axis];\n"
>+" float high = floor((LOWRES_pos + taps/input_size) * LOWRES_size -
>offset - 0.5)[axis];\n"
>+"\n"
>+" float W = 0.0;\n"
>+" vec4 avg = vec4(0);\n"
>+" vec2 pos = LOWRES_pos;\n"
>+" vec4 tex;\n"
>+"\n"
>+" for (float k = low; k <= high; k++) {\n"
>+" pos[axis] = LOWRES_pt[axis] * (k - offset[axis] + 0.5);\n"
>+" float rel = (pos[axis] -
>LOWRES_pos[axis])*input_size[axis];\n"
>+" float w = Kernel(rel);\n"
>+"\n"
>+" tex.rgb = textureLod(LOWRES_raw, pos, 0.0).rgb *
>LOWRES_mul;\n"
>+" tex.a = Luma(tex.rgb);\n"
>+" avg += w * tex;\n"
>+" W += w;\n"
>+" }\n"
>+" avg /= W;\n"
>+"\n"
>+" return vec4(avg.rgb, abs(avg.a - Luma(avg.rgb)) +
>LOWRES_texOff(0).a);\n"
>+"}\n"
>+"\n"
>+"//!HOOK POSTKERNEL\n"
>+"//!BIND PREKERNEL\n"
>+"//!SAVE varL\n"
>+"//!WIDTH NATIVE_CROPPED.w\n"
>+"//!HEIGHT NATIVE_CROPPED.h\n"
>+"//!WHEN NATIVE_CROPPED.w OUTPUT.w <\n"
>+"//!COMPONENTS 4\n"
>+"//!DESC SSSR varL\n"
>+"\n"
>+"#define spread 1.0 / 1000.0\n"
>+"\n"
>+"#define sqr(x) pow(x, 2.0)\n"
>+"#define GetL(x,y) PREKERNEL_tex(PREKERNEL_pt*(PREKERNEL_pos *
>input_size + tex_offset + vec2(x,y))).rgb\n"
>+"\n"
>+"#define Gamma(x) ( pow(clamp(x, 0.0, 1.0), vec3(1.0/2.0)) )\n"
>+"#define Kb 0.0722\n"
>+"#define Kr 0.2126\n"
>+"#define Luma(rgb) ( dot(vec3(Kr, 1.0 - Kr - Kb, Kb), pow(abs(rgb),
>vec3(2.0))) )\n"
>+"\n"
>+"vec4 hook() {\n"
>+" vec3 meanL = vec3(0);\n"
>+" for (int X=-1; X<=1; X++)\n"
>+" for (int Y=-1; Y<=1; Y++) {\n"
>+" meanL += GetL(X,Y) * pow(spread, sqr(float(X)) +
>sqr(float(Y)));\n"
>+" }\n"
>+" meanL /= (1.0 + 4.0*spread + 4.0*spread*spread);\n"
>+"\n"
>+" float varL = 0.0;\n"
>+" for (int X=-1; X<=1; X++)\n"
>+" for (int Y=-1; Y<=1; Y++) {\n"
>+" varL += Luma(GetL(X,Y) - meanL) * pow(spread, sqr(float(X)) +
>sqr(float(Y)));\n"
>+" }\n"
>+" varL /= (spread + 4.0*spread + 4.0*spread*spread);\n"
>+"\n"
>+" return vec4(GetL(0,0), varL);\n"
>+"}\n"
>+"\n"
>+"//!HOOK POSTKERNEL\n"
>+"//!BIND LOWRES\n"
>+"//!SAVE varH\n"
>+"//!WIDTH NATIVE_CROPPED.w\n"
>+"//!HEIGHT NATIVE_CROPPED.h\n"
>+"//!WHEN NATIVE_CROPPED.w OUTPUT.w <\n"
>+"//!COMPONENTS 1\n"
>+"//!DESC SSSR varH\n"
>+"\n"
>+"#define spread 1.0 / 1000.0\n"
>+"\n"
>+"#define sqr(x) pow(x, 2.0)\n"
>+"#define GetH(x,y) LOWRES_texOff(vec2(x,y)).rgb\n"
>+"\n"
>+"#define Gamma(x) ( pow(clamp(x, 0.0, 1.0), vec3(1.0/2.0)) )\n"
>+"#define Kb 0.0722\n"
>+"#define Kr 0.2126\n"
>+"#define Luma(rgb) ( dot(vec3(Kr, 1.0 - Kr - Kb, Kb), pow(abs(rgb),
>vec3(2.0))) )\n"
>+"\n"
>+"vec4 hook() {\n"
>+" vec3 meanH = vec3(0);\n"
>+" for (int X=-1; X<=1; X++)\n"
>+" for (int Y=-1; Y<=1; Y++) {\n"
>+" meanH += GetH(X,Y) * pow(spread, sqr(float(X)) +
>sqr(float(Y)));\n"
>+" }\n"
>+" meanH /= (1.0 + 4.0*spread + 4.0*spread*spread);\n"
>+"\n"
>+" float varH = 0.0;\n"
>+" for (int X=-1; X<=1; X++)\n"
>+" for (int Y=-1; Y<=1; Y++) {\n"
>+" varH += Luma(GetH(X,Y) - meanH) * pow(spread, sqr(float(X)) +
>sqr(float(Y)));\n"
>+" }\n"
>+" varH /= (spread + 4.0*spread + 4.0*spread*spread);\n"
>+"\n"
>+" return vec4(varH, 0, 0, 0);\n"
>+"}\n"
>+"\n"
>+"//!HOOK POSTKERNEL\n"
>+"//!BIND HOOKED\n"
>+"//!BIND LOWRES\n"
>+"//!BIND varL\n"
>+"//!BIND varH\n"
>+"//!WHEN NATIVE_CROPPED.w OUTPUT.w <\n"
>+"//!DESC SSSR final pass\n"
>+"\n"
>+"// -- Window Size --\n"
>+"#define taps 3.0\n"
>+"#define even (taps - 2.0 * floor(taps / 2.0) == 0.0)\n"
>+"#define minX int(1.0-ceil(taps/2.0))\n"
>+"#define maxX int(floor(taps/2.0))\n"
>+"\n"
>+"#define factor (LOWRES_pt*HOOKED_size)\n"
>+"#define Kernel(x) (cos(acos(-1.0)*(x)/taps)) // Hann kernel\n"
>+"\n"
>+"#define sqr(x) dot(x,x)\n"
>+"\n"
>+"// -- Input processing --\n"
>+"#define L(x,y) ( varL_tex(varL_pt*(pos+vec2(x,y)+0.5)) )\n"
>+"#define H(x,y) ( varH_tex(varH_pt*(pos+vec2(x,y)+0.5)) )\n"
>+"#define Lowres(x,y) ( LOWRES_tex(LOWRES_pt*(pos+vec2(x,y)+0.5)) )\n"
>+"\n"
>+"#define Gamma(x) ( pow(clamp(x, 0.0, 1.0), vec3(1.0/2.0)) )\n"
>+"#define GammaInv(x) ( pow(clamp(x, 0.0, 1.0), vec3(2.0)) )\n"
>+"#define Kb 0.0722\n"
>+"#define Kr 0.2126\n"
>+"#define Luma(rgb) ( dot(vec3(Kr, 1.0 - Kr - Kb, Kb), pow(abs(rgb),
>vec3(2.0))) )\n"
>+"\n"
>+"vec4 hook() {\n"
>+" vec4 c0 = HOOKED_tex(HOOKED_pos);\n"
>+"\n"
>+" // Calculate position\n"
>+" vec2 pos = HOOKED_pos * LOWRES_size - vec2(0.5);\n"
>+" vec2 offset = pos - (even ? floor(pos) : round(pos));\n"
>+" pos -= offset;\n"
>+"\n"
>+" vec2 mVar = vec2(0.0);\n"
>+" for (int X=-1; X<=1; X++)\n"
>+" for (int Y=-1; Y<=1; Y++) {\n"
>+" vec2 w = clamp(1.5 - abs(vec2(X,Y) - offset), 0.0, 1.0);\n"
>+" mVar += w.r * w.g * vec2(Lowres(X,Y).a, 1.0);\n"
>+" }\n"
>+" mVar.r /= mVar.g;\n"
>+"\n"
>+" // Calculate faithfulness force\n"
>+" float weightSum = 0.0;\n"
>+" vec3 diff = vec3(0);\n"
>+"\n"
>+" for (int X = minX; X <= maxX; X++)\n"
>+" for (int Y = minX; Y <= maxX; Y++)\n"
>+" {\n"
>+" float varL = L(X,Y).a;\n"
>+" float varH = H(X,Y).r;\n"
>+" float R = -sqrt((varL + sqr(0.5/255.0)) / (varH + mVar.r +
>sqr(0.5/255.0)));\n"
>+"\n"
>+" vec2 krnl = Kernel(vec2(X,Y) - offset);\n"
>+" float weight = krnl.r * krnl.g / (Luma(c0.rgb -
>Lowres(X,Y).rgb) + Lowres(X,Y).a + sqr(0.5/255.0));\n"
>+"\n"
>+" diff += weight * (L(X,Y).rgb + Lowres(X,Y).rgb * R + (-1.0 -
>R) * (c0.rgb));\n"
>+" weightSum += weight;\n"
>+" }\n"
>+" diff /= weightSum;\n"
>+"\n"
>+" c0.rgb = ((c0.rgb) + diff);\n"
>+"\n"
>+" return c0;\n"
>+"}\n"
>+"";
>+
>+const size_t ssim_super_res_len = sizeof(ssim_super_res) - 1;
>--
>2.27.0
>
>_______________________________________________
>vlc-devel mailing list
>To unsubscribe or modify your subscription options:
>https://mailman.videolan.org/listinfo/vlc-devel
--
Envoyé de mon appareil Android avec Courriel K-9 Mail. Veuillez excuser ma brièveté.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mailman.videolan.org/pipermail/vlc-devel/attachments/20200620/55568e2d/attachment-0001.html>
More information about the vlc-devel
mailing list