diff --git a/README.md b/README.md index ed8c65b..5fd0db2 100644 --- a/README.md +++ b/README.md @@ -1,31 +1,6 @@ # Cartograph -A browser-based world map creation tool inspired by Wonderdraft and Inkarnate. Uses line-strip vector shapes with procedural geometry. - -## Features - -- **Shapes** — parametric circles, stars, rectangles; freeform pen tool with Catmull-Rom splines -- **Instanced rendering** — shapes with identical local-space geometry share vertex buffers; per-instance transforms (position, scale, rotation) uploaded via SSBO -- **Bezier editing** — double-click any shape to edit its Bezier control points and handles in local space -- **Shape editing** — select, move, rotate, scale individual shapes; rect-select multiple shapes -- **Groups** — group/ungroup shapes with nested hierarchy support, group-level selection and focus mode -- **Clipboard** — copy/paste shapes with deep-copy of geometry, group remapping for pasted items -- **Undo/redo** — property-level history stack (position, scale, rotation, vertex edits, create/delete, group) with batch operations -- **Pen tool** — click to place control points; Enter, double-click, or close-to-start to commit; Escape to cancel -- **Spatial index** — open-addressing hash grid for fast hit testing, rect-selection, and viewport culling on large shape counts -- **Viewport** — zoom (scroll) and pan (right-click drag) with screen↔world coordinate transforms -- **Debug panel** — toggleable log overlay (backtick), FPS meter with 60-frame rolling average, log filtering - -## Tech stack - -| Layer | Library | -|---|---| -| Language | C (C99) | -| Compiler | [Emscripten](https://emscripten.org/) (emcc) → WebAssembly | -| Graphics | [Sokol](https://github.com/floooh/sokol) with WebGPU backend | -| UI | [Dear ImGui](https://github.com/ocornut/imgui) via [cimgui](https://github.com/cimgui/cimgui) | -| Math | [cglm](https://github.com/recp/cglm) | -| Shaders | WGSL (compiled to C headers via `xxd -i`) | +A browser-based world map creation tool inspired by Wonderdraft and Inkarnate. Uses a hierarchical tile-based SDF rendering. ## Build @@ -42,66 +17,6 @@ make debug Output is `app.html`, served by Emscripten's built-in web server or any static server. -## Project structure - -``` -src/ - main.c Entry point, sokol init, render loop, input dispatch, UI panels, debug stats - api.h Central include hub — backend defines, all library headers, ALLOC/FREE macros - types.h Shared type definitions, constants, userdata_t - camera.h Viewport state, zoom/pan, MVP matrix (via glm_ortho), screen↔world transforms - render.h Shape & overlay pipeline init/shutdown, shader definitions - shape.h Shape geometry types, procedural generation, Bezier editing, vertex hash grouping, instanced buffer pool - spatial.h Spatial hash grid with linear probing, AABB queries, viewport culling - history.h Undo/redo stack — property-level tracking, vertex snapshots, batch operations - interact.h Selection AABB, group recursive helpers, resize handle hit-test, group rebuild - overlay.h Selection overlay geometry, rotate/corner handles, edit-mode anchor & handle visualization - draw.h Draw dispatch — frustum culling, instance map sorting, instanced draw calls - input.h Mouse/keyboard event handlers — select, move, rotate, resize, pen, edit mode, clipboard - ui_panels.h ImGui panels — toolbar, shape list tree, properties, debug log - util.h Stripe-based vector_t (dynamic array) - rand.h Xorshift32 PRNG - shaders/ WGSL shader sources (sprite, shape, overlay) - generated/ xxd-generated C headers from shaders -lib/ - sokol/ Sokol single-file headers (gfx, app, glue, log, memtrack) - imgui/ Dear ImGui + cimgui - cglm/ C linear math library - util/ Sokol utility headers -``` - -## Architecture notes - -### Instanced rendering with vertex hash grouping - -Shapes share vertex buffers when their local-space geometry is identical. Each shape stores a 64-bit FNV-1a hash of its vertex data. The geometry pool groups shapes by `(num_elements, vertex_hash)` — not just vertex count. This means: - -- **Parametric shapes** (circles, stars, rectangles from fixed formulas): all instances of the same type naturally produce the same hash, so they share one vertex buffer regardless of count. -- **Freeform paths** (pen tool): each path gets a unique hash, guaranteeing its own vertex buffer and preventing geometry corruption. -- **Bezier edits**: `shape_regenerate_from_ctrl` updates the hash and modifies the group buffer in-place via `sg_update_buffer` rather than destroying/recreating it. - -The previous implementation grouped only by vertex count, which caused pen-drawn paths with matching counts to silently share the wrong geometry. - -### Lazy group index rebuild - -The `g_group_by_id` lookup array is rebuilt lazily. Operations that modify groups set a `g_group_index_dirty` flag; the actual rebuild happens on the first `find_group()` call afterward. This avoids redundant rebuilds when multiple group operations occur within the same frame (e.g., undo then redo, or group then ungroup). - -### Hover state optimization - -`handle_hover` (called every frame) tracks the previous set of highlighted shapes (up to 64) and only toggles state on shapes entering or leaving the highlight set. The O(n) full-array sweep is only used as a fallback when the highlight set exceeds 64 shapes. - -### Pool rebuild granularity - -When the geometry pool rebuilds, existing group vertex buffers whose `(num_elements, vertex_hash)` key still exists are preserved rather than destroyed and recreated. Only new keys trigger buffer creation, and only orphaned keys trigger destruction. The shape data SSBO is also preserved when its size hasn't changed. - -### Spatial grid memory reuse - -The spatial hash grid retains per-slot entry arrays across rebuilds. Only slots whose shape count has grown beyond their current capacity trigger a reallocation. - -### Log deduplication - -The debug log ring buffer uses a 64-bit message hash for fast deduplication of warnings and errors (levels 0-2). Debug-level messages (level 3) skip dedup entirely to avoid the linear scan cost when verbose logging is active. - ## License MIT diff --git a/makefile b/makefile index 4af9328..1b78d01 100644 --- a/makefile +++ b/makefile @@ -67,7 +67,7 @@ debug: $(FETCH) $(SHADER_HEADERS) $(C_SOURCES) $(IMGUI_SOURCES) $(CGLM_SOURCES) $(CC) $(C_SOURCES) $(IMGUI_SOURCES) $(CGLM_SOURCES) \ -o $(TARGET) \ $(EMCC_FLAGS) \ - -g --profiling-funcs -gsource-map=inline \ + -g --profiling-funcs -gsource-map \ -sASSERTIONS \ -I$(LIB_DIR)/sokol \ -I$(LIB_DIR)/imgui \ diff --git a/src/api.h b/src/api.h index 0b52854..beadf85 100644 --- a/src/api.h +++ b/src/api.h @@ -1,10 +1,24 @@ #ifndef API_DEFINITION #define API_DEFINITION +#include +#include +#include +#include +#include + #include #define CIMGUI_DEFINE_ENUMS_AND_STRUCTS +static void log_fn(const char* tag, uint32_t log_level, uint32_t log_item_id, const char* message_or_null, uint32_t line_nr, const char* filename_or_null, void* user_data) +{ + if(log_level < 3) return; + fprintf(stderr, "[%s - %s]: (%d) %s \tat %s:%d\r\n", tag, log_level == 0 ? "FATAL" : log_level == 1 ? "ERROR" : log_level == 2 ? "WARNING" : "INFO", log_item_id, message_or_null, filename_or_null, line_nr); +} + +#define SOKOL_ASSERT(x) ((void)((x) || (log_fn("ASSERT", 1, 1, "Assertion failed", __LINE__, __FILE__, NULL),0))) + #define SOKOL_IMPL #define SOKOL_WGPU #define SOKOL_IMGUI_IMPL @@ -15,6 +29,22 @@ #define STBDS_REALLOC(context,ptr,size) emmalloc_realloc(ptr, size) #define STBDS_FREE(context,ptr) emmalloc_free(ptr) +#define COMPUTE_VIEWIDX_segments 0 +#define COMPUTE_VIEWIDX_shapes 1 +#define COMPUTE_VIEWIDX_circles 2 +#define COMPUTE_VIEWIDX_tiles 3 +#define COMPUTE_VIEWIDX_indices 4 +#define COMPUTE_VIEWIDX_SDF 5 + +#define DISPLAY_VIEWIDX_tiles 0 +#define DISPLAY_VIEWIDX_SDF 1 +#define DISPLAY_VIEWIDX_Sampler 2 + +static float clampf(float x, float a, float b) +{ + return x < a ? a : (x > b ? b : x); +} + #include "sokol_gfx.h" #include "sokol_app.h" #include "sokol_glue.h" @@ -22,14 +52,9 @@ #include "sokol_imgui.h" #include "stb_ds.h" -#include -#include -#include -#include -#include - #include "shape.h" -#include "cache.h" +//#include "cache.h" +#include "pool.h" #include "generated/compute.h" #include "generated/display.h" diff --git a/src/cache.h b/src/cache.h index 557b7b0..42b1152 100644 --- a/src/cache.h +++ b/src/cache.h @@ -37,10 +37,9 @@ uint32_t cache_allocate(scene_t* s) return layer; } -tile_slot_t* cache_search(scene_t* s, int lod, int tx, int ty, uint64_t frame_count) +tile_slot_t* cache_search(scene_t* s, tile_key_t* key, uint64_t frame_count) { - tile_key_t key = { lod, tx, ty }; - uint32_t index = stbds_hmgeti(s->cache.map, key); + uint32_t index = stbds_hmgeti(s->cache.map, *key); if(index >= 0) { @@ -59,11 +58,50 @@ tile_slot_t* cache_search(scene_t* s, int lod, int tx, int ty, uint64_t frame_co // Allocate a free layer uint32_t layer = cache_allocate(s); tile_slot_t* slot = &s->cache.slots[layer]; - slot->key.lod = lod; slot->key.tx = tx; slot->key.ty = ty; + slot->key.lod = key->lod; slot->key.tx = key->tx; slot->key.ty = key->ty; slot->layer = layer; - slot->ready = false; + slot->state = TILE_STATE_DIRTY; slot->last_used = frame_count; - stbds_hmput(s->cache.map, key, layer); + stbds_hmput(s->cache.map, *key, layer); return slot; +} +// Works in 3 steps, first we select every required tiles and store the mising one from the cache +// Then we evict the LRU cache until we have enough space for the missing tiles +// Finally we allocate the missing tiles +static int cache_query(scene_t* s, uint32_t lod, box_t* box, tile_key_t** buffer) +{ + uint64_t frame = sapp_frame_count(); + tile_key_t tile_key = { lod, 0, 0 }; + + for(uint32_t ty = box->min_y; ty < box->max_y; ty++) + { + tile_key.ty = ty; + for(uint32_t tx = box->min_x; tx < box->max_x; tx++) + { + tile_key.tx = tx; + stbds_hmget(s->cache.map, tile_key); + } + } +} +static int cache_cull(scene_t* s, uint32_t tile_count) +{ + uint32_t count = 0; + for(uint32_t i = 0; i < tile_count; i++) + { + tile_slot_t slot = s->cache.slots[i]; + tile_task_t* tile = &s->cache.tiles[i]; + tile->bounds.min_x = slot.key.tx * s->LODs[slot.key.lod].texel_size; + tile->bounds.min_y = slot.key.ty * s->LODs[slot.key.lod].texel_size; + tile->bounds.max_x = (slot.key.tx + 1) * s->LODs[slot.key.lod].texel_size; + tile->bounds.max_y = (slot.key.ty + 1) * s->LODs[slot.key.lod].texel_size; + tile->layer = slot.layer; + + uint32_t start = count; + for(uint32_t j = 0; j < s->num_shapes; j++) + { + if(BOX_INTERSECTS(tile->bounds, s->shapes[j].aabb)) s->cache.indices[count++] = j; + } + tile->offset = start; tile->count = count - start; + } } \ No newline at end of file diff --git a/src/generated/compute.h b/src/generated/compute.h index df740f5..c6f0722 100644 --- a/src/generated/compute.h +++ b/src/generated/compute.h @@ -7,622 +7,680 @@ unsigned char src_shaders_compute_wgsl[] = { 0x63, 0x32, 0x66, 0x2c, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x70, 0x33, 0x3a, 0x20, 0x76, 0x65, 0x63, 0x32, 0x66, 0x2c, 0x0d, 0x0a, 0x7d, 0x0d, 0x0a, 0x73, 0x74, 0x72, 0x75, 0x63, 0x74, 0x20, 0x53, 0x68, 0x61, 0x70, - 0x65, 0x4d, 0x65, 0x74, 0x61, 0x20, 0x7b, 0x0d, 0x0a, 0x20, 0x20, 0x20, - 0x20, 0x73, 0x74, 0x61, 0x72, 0x74, 0x5f, 0x73, 0x65, 0x67, 0x6d, 0x65, - 0x6e, 0x74, 0x3a, 0x20, 0x75, 0x33, 0x32, 0x2c, 0x0d, 0x0a, 0x20, 0x20, - 0x20, 0x20, 0x73, 0x65, 0x67, 0x6d, 0x65, 0x6e, 0x74, 0x5f, 0x63, 0x6f, - 0x75, 0x6e, 0x74, 0x3a, 0x20, 0x75, 0x33, 0x32, 0x2c, 0x0d, 0x0a, 0x20, - 0x20, 0x20, 0x20, 0x62, 0x62, 0x6f, 0x78, 0x5f, 0x6d, 0x69, 0x6e, 0x3a, - 0x20, 0x76, 0x65, 0x63, 0x32, 0x66, 0x2c, 0x0d, 0x0a, 0x20, 0x20, 0x20, - 0x20, 0x62, 0x62, 0x6f, 0x78, 0x5f, 0x6d, 0x61, 0x78, 0x3a, 0x20, 0x76, - 0x65, 0x63, 0x32, 0x66, 0x2c, 0x0d, 0x0a, 0x7d, 0x0d, 0x0a, 0x73, 0x74, - 0x72, 0x75, 0x63, 0x74, 0x20, 0x54, 0x69, 0x6c, 0x65, 0x20, 0x7b, 0x0d, - 0x0a, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x6f, 0x64, 0x3a, 0x20, 0x75, 0x33, - 0x32, 0x2c, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x74, 0x69, 0x6c, 0x65, - 0x5f, 0x73, 0x69, 0x7a, 0x65, 0x3a, 0x20, 0x66, 0x33, 0x32, 0x2c, 0x0d, - 0x0a, 0x20, 0x20, 0x20, 0x20, 0x77, 0x6f, 0x72, 0x6c, 0x64, 0x5f, 0x6d, - 0x69, 0x6e, 0x3a, 0x20, 0x76, 0x65, 0x63, 0x32, 0x66, 0x2c, 0x0d, 0x0a, - 0x20, 0x20, 0x20, 0x20, 0x77, 0x6f, 0x72, 0x6c, 0x64, 0x5f, 0x6d, 0x61, - 0x78, 0x3a, 0x20, 0x76, 0x65, 0x63, 0x32, 0x66, 0x2c, 0x0d, 0x0a, 0x20, - 0x20, 0x20, 0x20, 0x62, 0x75, 0x66, 0x66, 0x65, 0x72, 0x5f, 0x69, 0x6e, - 0x64, 0x65, 0x78, 0x3a, 0x20, 0x75, 0x33, 0x32, 0x2c, 0x0d, 0x0a, 0x7d, - 0x3b, 0x0d, 0x0a, 0x0d, 0x0a, 0x40, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x28, - 0x31, 0x29, 0x20, 0x40, 0x62, 0x69, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x28, - 0x30, 0x29, 0x20, 0x76, 0x61, 0x72, 0x3c, 0x73, 0x74, 0x6f, 0x72, 0x61, - 0x67, 0x65, 0x3e, 0x20, 0x73, 0x65, 0x67, 0x6d, 0x65, 0x6e, 0x74, 0x73, - 0x3a, 0x20, 0x61, 0x72, 0x72, 0x61, 0x79, 0x3c, 0x53, 0x65, 0x67, 0x6d, - 0x65, 0x6e, 0x74, 0x3e, 0x3b, 0x0d, 0x0a, 0x40, 0x67, 0x72, 0x6f, 0x75, - 0x70, 0x28, 0x31, 0x29, 0x20, 0x40, 0x62, 0x69, 0x6e, 0x64, 0x69, 0x6e, - 0x67, 0x28, 0x31, 0x29, 0x20, 0x76, 0x61, 0x72, 0x3c, 0x73, 0x74, 0x6f, - 0x72, 0x61, 0x67, 0x65, 0x3e, 0x20, 0x73, 0x68, 0x61, 0x70, 0x65, 0x73, - 0x3a, 0x20, 0x61, 0x72, 0x72, 0x61, 0x79, 0x3c, 0x53, 0x68, 0x61, 0x70, - 0x65, 0x4d, 0x65, 0x74, 0x61, 0x3e, 0x3b, 0x0d, 0x0a, 0x40, 0x67, 0x72, - 0x6f, 0x75, 0x70, 0x28, 0x31, 0x29, 0x20, 0x40, 0x62, 0x69, 0x6e, 0x64, - 0x69, 0x6e, 0x67, 0x28, 0x32, 0x29, 0x20, 0x76, 0x61, 0x72, 0x3c, 0x73, - 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x3e, 0x20, 0x74, 0x69, 0x6c, 0x65, - 0x73, 0x3a, 0x20, 0x61, 0x72, 0x72, 0x61, 0x79, 0x3c, 0x54, 0x69, 0x6c, - 0x65, 0x3e, 0x3b, 0x0d, 0x0a, 0x40, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x28, - 0x31, 0x29, 0x20, 0x40, 0x62, 0x69, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x28, - 0x33, 0x29, 0x20, 0x76, 0x61, 0x72, 0x3c, 0x73, 0x74, 0x6f, 0x72, 0x61, - 0x67, 0x65, 0x2c, 0x20, 0x72, 0x65, 0x61, 0x64, 0x5f, 0x77, 0x72, 0x69, - 0x74, 0x65, 0x3e, 0x20, 0x73, 0x64, 0x66, 0x5f, 0x62, 0x75, 0x66, 0x66, - 0x65, 0x72, 0x3a, 0x20, 0x74, 0x65, 0x78, 0x74, 0x75, 0x72, 0x65, 0x5f, - 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x5f, 0x32, 0x64, 0x5f, 0x61, - 0x72, 0x72, 0x61, 0x79, 0x3c, 0x72, 0x33, 0x32, 0x66, 0x6c, 0x6f, 0x61, - 0x74, 0x2c, 0x20, 0x72, 0x65, 0x61, 0x64, 0x5f, 0x77, 0x72, 0x69, 0x74, - 0x65, 0x3e, 0x3b, 0x0d, 0x0a, 0x0d, 0x0a, 0x73, 0x74, 0x72, 0x75, 0x63, - 0x74, 0x20, 0x55, 0x6e, 0x69, 0x66, 0x6f, 0x72, 0x6d, 0x73, 0x20, 0x7b, - 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x70, 0x61, 0x6e, 0x3a, 0x20, 0x76, - 0x65, 0x63, 0x32, 0x66, 0x2c, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x7a, - 0x6f, 0x6f, 0x6d, 0x3a, 0x20, 0x66, 0x33, 0x32, 0x2c, 0x0d, 0x0a, 0x7d, - 0x3b, 0x0d, 0x0a, 0x0d, 0x0a, 0x40, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x28, - 0x30, 0x29, 0x20, 0x40, 0x62, 0x69, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x28, - 0x30, 0x29, 0x20, 0x76, 0x61, 0x72, 0x3c, 0x75, 0x6e, 0x69, 0x66, 0x6f, - 0x72, 0x6d, 0x3e, 0x20, 0x75, 0x6e, 0x69, 0x66, 0x6f, 0x72, 0x6d, 0x73, - 0x3a, 0x20, 0x55, 0x6e, 0x69, 0x66, 0x6f, 0x72, 0x6d, 0x73, 0x3b, 0x0d, - 0x0a, 0x0d, 0x0a, 0x0d, 0x0a, 0x2f, 0x2f, 0x20, 0x2d, 0x2d, 0x2d, 0x2d, - 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x20, 0x43, 0x75, 0x62, 0x69, 0x63, - 0x20, 0x42, 0xc3, 0xa9, 0x7a, 0x69, 0x65, 0x72, 0x20, 0x68, 0x65, 0x6c, - 0x70, 0x65, 0x72, 0x73, 0x20, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, - 0x2d, 0x2d, 0x2d, 0x0d, 0x0a, 0x66, 0x6e, 0x20, 0x65, 0x76, 0x61, 0x6c, - 0x5f, 0x63, 0x75, 0x62, 0x69, 0x63, 0x28, 0x74, 0x3a, 0x20, 0x66, 0x33, - 0x32, 0x2c, 0x20, 0x70, 0x30, 0x3a, 0x20, 0x76, 0x65, 0x63, 0x32, 0x66, - 0x2c, 0x20, 0x70, 0x31, 0x3a, 0x20, 0x76, 0x65, 0x63, 0x32, 0x66, 0x2c, - 0x20, 0x70, 0x32, 0x3a, 0x20, 0x76, 0x65, 0x63, 0x32, 0x66, 0x2c, 0x20, - 0x70, 0x33, 0x3a, 0x20, 0x76, 0x65, 0x63, 0x32, 0x66, 0x29, 0x20, 0x2d, - 0x3e, 0x20, 0x76, 0x65, 0x63, 0x32, 0x66, 0x20, 0x7b, 0x0d, 0x0a, 0x20, - 0x20, 0x20, 0x20, 0x6c, 0x65, 0x74, 0x20, 0x6d, 0x74, 0x20, 0x3d, 0x20, - 0x31, 0x2e, 0x30, 0x20, 0x2d, 0x20, 0x74, 0x3b, 0x0d, 0x0a, 0x20, 0x20, - 0x20, 0x20, 0x6c, 0x65, 0x74, 0x20, 0x6d, 0x74, 0x32, 0x20, 0x3d, 0x20, - 0x6d, 0x74, 0x20, 0x2a, 0x20, 0x6d, 0x74, 0x3b, 0x0d, 0x0a, 0x20, 0x20, - 0x20, 0x20, 0x6c, 0x65, 0x74, 0x20, 0x74, 0x32, 0x20, 0x3d, 0x20, 0x74, - 0x20, 0x2a, 0x20, 0x74, 0x3b, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x72, - 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x6d, 0x74, 0x32, 0x20, 0x2a, 0x20, - 0x6d, 0x74, 0x20, 0x2a, 0x20, 0x70, 0x30, 0x20, 0x2b, 0x20, 0x33, 0x2e, - 0x30, 0x20, 0x2a, 0x20, 0x6d, 0x74, 0x32, 0x20, 0x2a, 0x20, 0x74, 0x20, - 0x2a, 0x20, 0x70, 0x31, 0x20, 0x2b, 0x20, 0x33, 0x2e, 0x30, 0x20, 0x2a, - 0x20, 0x6d, 0x74, 0x20, 0x2a, 0x20, 0x74, 0x32, 0x20, 0x2a, 0x20, 0x70, - 0x32, 0x20, 0x2b, 0x20, 0x74, 0x32, 0x20, 0x2a, 0x20, 0x74, 0x20, 0x2a, - 0x20, 0x70, 0x33, 0x3b, 0x0d, 0x0a, 0x7d, 0x0d, 0x0a, 0x0d, 0x0a, 0x66, - 0x6e, 0x20, 0x65, 0x76, 0x61, 0x6c, 0x5f, 0x63, 0x75, 0x62, 0x69, 0x63, - 0x5f, 0x64, 0x65, 0x72, 0x69, 0x76, 0x61, 0x74, 0x69, 0x76, 0x65, 0x28, - 0x74, 0x3a, 0x20, 0x66, 0x33, 0x32, 0x2c, 0x20, 0x70, 0x30, 0x3a, 0x20, - 0x76, 0x65, 0x63, 0x32, 0x66, 0x2c, 0x20, 0x70, 0x31, 0x3a, 0x20, 0x76, - 0x65, 0x63, 0x32, 0x66, 0x2c, 0x20, 0x70, 0x32, 0x3a, 0x20, 0x76, 0x65, - 0x63, 0x32, 0x66, 0x2c, 0x20, 0x70, 0x33, 0x3a, 0x20, 0x76, 0x65, 0x63, - 0x32, 0x66, 0x29, 0x20, 0x2d, 0x3e, 0x20, 0x76, 0x65, 0x63, 0x32, 0x66, - 0x20, 0x7b, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x65, 0x74, 0x20, - 0x6d, 0x74, 0x20, 0x3d, 0x20, 0x31, 0x2e, 0x30, 0x20, 0x2d, 0x20, 0x74, + 0x65, 0x4d, 0x65, 0x74, 0x61, 0x20, 0x7b, 0x20, 0x0d, 0x0a, 0x20, 0x20, + 0x20, 0x20, 0x73, 0x74, 0x61, 0x72, 0x74, 0x5f, 0x73, 0x65, 0x67, 0x6d, + 0x65, 0x6e, 0x74, 0x3a, 0x20, 0x75, 0x33, 0x32, 0x2c, 0x20, 0x2f, 0x2f, + 0x4f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x20, 0x69, 0x6e, 0x20, 0x74, 0x68, + 0x65, 0x20, 0x73, 0x65, 0x67, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x20, 0x62, + 0x75, 0x66, 0x66, 0x65, 0x72, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x73, + 0x65, 0x67, 0x6d, 0x65, 0x6e, 0x74, 0x5f, 0x63, 0x6f, 0x75, 0x6e, 0x74, + 0x3a, 0x20, 0x75, 0x33, 0x32, 0x2c, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, + 0x62, 0x62, 0x6f, 0x78, 0x5f, 0x6d, 0x69, 0x6e, 0x3a, 0x20, 0x76, 0x65, + 0x63, 0x32, 0x66, 0x2c, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x62, 0x62, + 0x6f, 0x78, 0x5f, 0x6d, 0x61, 0x78, 0x3a, 0x20, 0x76, 0x65, 0x63, 0x32, + 0x66, 0x2c, 0x0d, 0x0a, 0x7d, 0x0d, 0x0a, 0x73, 0x74, 0x72, 0x75, 0x63, + 0x74, 0x20, 0x43, 0x69, 0x72, 0x63, 0x6c, 0x65, 0x20, 0x7b, 0x0d, 0x0a, + 0x20, 0x20, 0x20, 0x20, 0x63, 0x65, 0x6e, 0x74, 0x65, 0x72, 0x3a, 0x20, + 0x76, 0x65, 0x63, 0x32, 0x66, 0x2c, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, + 0x72, 0x61, 0x64, 0x69, 0x75, 0x73, 0x3a, 0x20, 0x66, 0x33, 0x32, 0x2c, + 0x0d, 0x0a, 0x7d, 0x0d, 0x0a, 0x73, 0x74, 0x72, 0x75, 0x63, 0x74, 0x20, + 0x54, 0x69, 0x6c, 0x65, 0x20, 0x7b, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, + 0x77, 0x6f, 0x72, 0x6c, 0x64, 0x5f, 0x6d, 0x69, 0x6e, 0x3a, 0x20, 0x76, + 0x65, 0x63, 0x32, 0x66, 0x2c, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x77, + 0x6f, 0x72, 0x6c, 0x64, 0x5f, 0x6d, 0x61, 0x78, 0x3a, 0x20, 0x76, 0x65, + 0x63, 0x32, 0x66, 0x2c, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x6f, 0x66, + 0x66, 0x73, 0x65, 0x74, 0x3a, 0x20, 0x75, 0x33, 0x32, 0x2c, 0x0d, 0x0a, + 0x20, 0x20, 0x20, 0x20, 0x63, 0x69, 0x72, 0x63, 0x6c, 0x65, 0x5f, 0x63, + 0x6f, 0x75, 0x6e, 0x74, 0x3a, 0x20, 0x75, 0x33, 0x32, 0x2c, 0x0d, 0x0a, + 0x20, 0x20, 0x20, 0x20, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x3a, 0x20, 0x75, + 0x33, 0x32, 0x2c, 0x0d, 0x0a, 0x7d, 0x3b, 0x0d, 0x0a, 0x0d, 0x0a, 0x40, + 0x67, 0x72, 0x6f, 0x75, 0x70, 0x28, 0x31, 0x29, 0x20, 0x40, 0x62, 0x69, + 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x28, 0x30, 0x29, 0x20, 0x76, 0x61, 0x72, + 0x3c, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x3e, 0x20, 0x73, 0x65, + 0x67, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x3a, 0x20, 0x61, 0x72, 0x72, 0x61, + 0x79, 0x3c, 0x53, 0x65, 0x67, 0x6d, 0x65, 0x6e, 0x74, 0x3e, 0x3b, 0x0d, + 0x0a, 0x40, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x28, 0x31, 0x29, 0x20, 0x40, + 0x62, 0x69, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x28, 0x31, 0x29, 0x20, 0x76, + 0x61, 0x72, 0x3c, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x3e, 0x20, + 0x73, 0x68, 0x61, 0x70, 0x65, 0x73, 0x3a, 0x20, 0x61, 0x72, 0x72, 0x61, + 0x79, 0x3c, 0x53, 0x68, 0x61, 0x70, 0x65, 0x4d, 0x65, 0x74, 0x61, 0x3e, + 0x3b, 0x0d, 0x0a, 0x40, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x28, 0x31, 0x29, + 0x20, 0x40, 0x62, 0x69, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x28, 0x32, 0x29, + 0x20, 0x76, 0x61, 0x72, 0x3c, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, + 0x3e, 0x20, 0x63, 0x69, 0x72, 0x63, 0x6c, 0x65, 0x73, 0x3a, 0x20, 0x61, + 0x72, 0x72, 0x61, 0x79, 0x3c, 0x43, 0x69, 0x72, 0x63, 0x6c, 0x65, 0x3e, + 0x3b, 0x0d, 0x0a, 0x40, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x28, 0x31, 0x29, + 0x20, 0x40, 0x62, 0x69, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x28, 0x33, 0x29, + 0x20, 0x76, 0x61, 0x72, 0x3c, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, + 0x3e, 0x20, 0x74, 0x69, 0x6c, 0x65, 0x73, 0x3a, 0x20, 0x61, 0x72, 0x72, + 0x61, 0x79, 0x3c, 0x54, 0x69, 0x6c, 0x65, 0x3e, 0x3b, 0x0d, 0x0a, 0x40, + 0x67, 0x72, 0x6f, 0x75, 0x70, 0x28, 0x31, 0x29, 0x20, 0x40, 0x62, 0x69, + 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x28, 0x34, 0x29, 0x20, 0x76, 0x61, 0x72, + 0x3c, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x3e, 0x20, 0x69, 0x6e, + 0x64, 0x69, 0x63, 0x65, 0x73, 0x3a, 0x20, 0x61, 0x72, 0x72, 0x61, 0x79, + 0x3c, 0x75, 0x33, 0x32, 0x3e, 0x3b, 0x0d, 0x0a, 0x40, 0x67, 0x72, 0x6f, + 0x75, 0x70, 0x28, 0x31, 0x29, 0x20, 0x40, 0x62, 0x69, 0x6e, 0x64, 0x69, + 0x6e, 0x67, 0x28, 0x35, 0x29, 0x20, 0x76, 0x61, 0x72, 0x20, 0x73, 0x64, + 0x66, 0x5f, 0x62, 0x75, 0x66, 0x66, 0x65, 0x72, 0x3a, 0x20, 0x74, 0x65, + 0x78, 0x74, 0x75, 0x72, 0x65, 0x5f, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, + 0x65, 0x5f, 0x32, 0x64, 0x3c, 0x72, 0x31, 0x36, 0x66, 0x6c, 0x6f, 0x61, + 0x74, 0x2c, 0x20, 0x77, 0x72, 0x69, 0x74, 0x65, 0x3e, 0x3b, 0x0d, 0x0a, + 0x0d, 0x0a, 0x6f, 0x76, 0x65, 0x72, 0x72, 0x69, 0x64, 0x65, 0x20, 0x54, + 0x49, 0x4c, 0x45, 0x5f, 0x53, 0x49, 0x5a, 0x45, 0x3a, 0x20, 0x75, 0x33, + 0x32, 0x20, 0x3d, 0x20, 0x32, 0x35, 0x36, 0x75, 0x3b, 0x0d, 0x0a, 0x0d, + 0x0a, 0x2f, 0x2f, 0x20, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, + 0x2d, 0x2d, 0x20, 0x43, 0x75, 0x62, 0x69, 0x63, 0x20, 0x42, 0xc3, 0xa9, + 0x7a, 0x69, 0x65, 0x72, 0x20, 0x68, 0x65, 0x6c, 0x70, 0x65, 0x72, 0x73, + 0x20, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0d, + 0x0a, 0x66, 0x6e, 0x20, 0x65, 0x76, 0x61, 0x6c, 0x5f, 0x63, 0x75, 0x62, + 0x69, 0x63, 0x28, 0x74, 0x3a, 0x20, 0x66, 0x33, 0x32, 0x2c, 0x20, 0x70, + 0x30, 0x3a, 0x20, 0x76, 0x65, 0x63, 0x32, 0x66, 0x2c, 0x20, 0x70, 0x31, + 0x3a, 0x20, 0x76, 0x65, 0x63, 0x32, 0x66, 0x2c, 0x20, 0x70, 0x32, 0x3a, + 0x20, 0x76, 0x65, 0x63, 0x32, 0x66, 0x2c, 0x20, 0x70, 0x33, 0x3a, 0x20, + 0x76, 0x65, 0x63, 0x32, 0x66, 0x29, 0x20, 0x2d, 0x3e, 0x20, 0x76, 0x65, + 0x63, 0x32, 0x66, 0x20, 0x7b, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x6c, + 0x65, 0x74, 0x20, 0x6d, 0x74, 0x20, 0x3d, 0x20, 0x31, 0x2e, 0x30, 0x20, + 0x2d, 0x20, 0x74, 0x3b, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x65, + 0x74, 0x20, 0x6d, 0x74, 0x32, 0x20, 0x3d, 0x20, 0x6d, 0x74, 0x20, 0x2a, + 0x20, 0x6d, 0x74, 0x3b, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x65, + 0x74, 0x20, 0x74, 0x32, 0x20, 0x3d, 0x20, 0x74, 0x20, 0x2a, 0x20, 0x74, 0x3b, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, - 0x6e, 0x20, 0x33, 0x2e, 0x30, 0x20, 0x2a, 0x20, 0x6d, 0x74, 0x20, 0x2a, - 0x20, 0x6d, 0x74, 0x20, 0x2a, 0x20, 0x28, 0x70, 0x31, 0x20, 0x2d, 0x20, - 0x70, 0x30, 0x29, 0x20, 0x2b, 0x20, 0x36, 0x2e, 0x30, 0x20, 0x2a, 0x20, - 0x6d, 0x74, 0x20, 0x2a, 0x20, 0x74, 0x20, 0x2a, 0x20, 0x28, 0x70, 0x32, - 0x20, 0x2d, 0x20, 0x70, 0x31, 0x29, 0x20, 0x2b, 0x20, 0x33, 0x2e, 0x30, - 0x20, 0x2a, 0x20, 0x74, 0x20, 0x2a, 0x20, 0x74, 0x20, 0x2a, 0x20, 0x28, - 0x70, 0x33, 0x20, 0x2d, 0x20, 0x70, 0x32, 0x29, 0x3b, 0x0d, 0x0a, 0x7d, - 0x0d, 0x0a, 0x0d, 0x0a, 0x2f, 0x2f, 0x20, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, - 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x20, 0x44, 0x69, 0x73, 0x74, 0x61, 0x6e, - 0x63, 0x65, 0x20, 0x74, 0x6f, 0x20, 0x61, 0x20, 0x63, 0x75, 0x62, 0x69, - 0x63, 0x20, 0x42, 0xc3, 0xa9, 0x7a, 0x69, 0x65, 0x72, 0x20, 0x28, 0x73, - 0x61, 0x6d, 0x70, 0x6c, 0x69, 0x6e, 0x67, 0x20, 0x2b, 0x20, 0x4e, 0x65, - 0x77, 0x74, 0x6f, 0x6e, 0x20, 0x72, 0x65, 0x66, 0x69, 0x6e, 0x65, 0x6d, - 0x65, 0x6e, 0x74, 0x29, 0x20, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, - 0x2d, 0x2d, 0x2d, 0x0d, 0x0a, 0x66, 0x6e, 0x20, 0x64, 0x69, 0x73, 0x74, - 0x61, 0x6e, 0x63, 0x65, 0x5f, 0x74, 0x6f, 0x5f, 0x63, 0x75, 0x62, 0x69, - 0x63, 0x28, 0x70, 0x3a, 0x20, 0x76, 0x65, 0x63, 0x32, 0x66, 0x2c, 0x20, - 0x73, 0x65, 0x67, 0x3a, 0x20, 0x53, 0x65, 0x67, 0x6d, 0x65, 0x6e, 0x74, - 0x29, 0x20, 0x2d, 0x3e, 0x20, 0x66, 0x33, 0x32, 0x20, 0x7b, 0x0d, 0x0a, - 0x20, 0x20, 0x20, 0x20, 0x6c, 0x65, 0x74, 0x20, 0x70, 0x30, 0x20, 0x3d, - 0x20, 0x73, 0x65, 0x67, 0x2e, 0x70, 0x30, 0x3b, 0x20, 0x6c, 0x65, 0x74, - 0x20, 0x70, 0x31, 0x20, 0x3d, 0x20, 0x73, 0x65, 0x67, 0x2e, 0x70, 0x31, - 0x3b, 0x20, 0x6c, 0x65, 0x74, 0x20, 0x70, 0x32, 0x20, 0x3d, 0x20, 0x73, - 0x65, 0x67, 0x2e, 0x70, 0x32, 0x3b, 0x20, 0x6c, 0x65, 0x74, 0x20, 0x70, - 0x33, 0x20, 0x3d, 0x20, 0x73, 0x65, 0x67, 0x2e, 0x70, 0x33, 0x3b, 0x0d, - 0x0a, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x2f, 0x2f, 0x20, 0x55, 0x6e, - 0x69, 0x66, 0x6f, 0x72, 0x6d, 0x20, 0x73, 0x61, 0x6d, 0x70, 0x6c, 0x69, - 0x6e, 0x67, 0x20, 0x74, 0x6f, 0x20, 0x66, 0x69, 0x6e, 0x64, 0x20, 0x61, - 0x20, 0x67, 0x6f, 0x6f, 0x64, 0x20, 0x73, 0x74, 0x61, 0x72, 0x74, 0x69, - 0x6e, 0x67, 0x20, 0x74, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x65, - 0x74, 0x20, 0x73, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x73, 0x20, 0x3d, 0x20, - 0x31, 0x36, 0x75, 0x3b, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x76, 0x61, - 0x72, 0x20, 0x62, 0x65, 0x73, 0x74, 0x5f, 0x74, 0x20, 0x3d, 0x20, 0x30, - 0x2e, 0x30, 0x3b, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x76, 0x61, 0x72, - 0x20, 0x62, 0x65, 0x73, 0x74, 0x5f, 0x64, 0x69, 0x73, 0x74, 0x20, 0x3d, - 0x20, 0x31, 0x65, 0x32, 0x30, 0x3b, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, - 0x66, 0x6f, 0x72, 0x20, 0x28, 0x76, 0x61, 0x72, 0x20, 0x69, 0x20, 0x3d, - 0x20, 0x30, 0x75, 0x3b, 0x20, 0x69, 0x20, 0x3c, 0x20, 0x73, 0x61, 0x6d, - 0x70, 0x6c, 0x65, 0x73, 0x3b, 0x20, 0x69, 0x2b, 0x2b, 0x29, 0x20, 0x7b, - 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x65, - 0x74, 0x20, 0x74, 0x20, 0x3d, 0x20, 0x66, 0x33, 0x32, 0x28, 0x69, 0x29, - 0x20, 0x2f, 0x20, 0x66, 0x33, 0x32, 0x28, 0x73, 0x61, 0x6d, 0x70, 0x6c, - 0x65, 0x73, 0x20, 0x2d, 0x20, 0x31, 0x75, 0x29, 0x3b, 0x0d, 0x0a, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x65, 0x74, 0x20, 0x71, + 0x6e, 0x20, 0x6d, 0x74, 0x32, 0x20, 0x2a, 0x20, 0x6d, 0x74, 0x20, 0x2a, + 0x20, 0x70, 0x30, 0x20, 0x2b, 0x20, 0x33, 0x2e, 0x30, 0x20, 0x2a, 0x20, + 0x6d, 0x74, 0x32, 0x20, 0x2a, 0x20, 0x74, 0x20, 0x2a, 0x20, 0x70, 0x31, + 0x20, 0x2b, 0x20, 0x33, 0x2e, 0x30, 0x20, 0x2a, 0x20, 0x6d, 0x74, 0x20, + 0x2a, 0x20, 0x74, 0x32, 0x20, 0x2a, 0x20, 0x70, 0x32, 0x20, 0x2b, 0x20, + 0x74, 0x32, 0x20, 0x2a, 0x20, 0x74, 0x20, 0x2a, 0x20, 0x70, 0x33, 0x3b, + 0x0d, 0x0a, 0x7d, 0x0d, 0x0a, 0x0d, 0x0a, 0x66, 0x6e, 0x20, 0x65, 0x76, + 0x61, 0x6c, 0x5f, 0x63, 0x75, 0x62, 0x69, 0x63, 0x5f, 0x64, 0x65, 0x72, + 0x69, 0x76, 0x61, 0x74, 0x69, 0x76, 0x65, 0x28, 0x74, 0x3a, 0x20, 0x66, + 0x33, 0x32, 0x2c, 0x20, 0x70, 0x30, 0x3a, 0x20, 0x76, 0x65, 0x63, 0x32, + 0x66, 0x2c, 0x20, 0x70, 0x31, 0x3a, 0x20, 0x76, 0x65, 0x63, 0x32, 0x66, + 0x2c, 0x20, 0x70, 0x32, 0x3a, 0x20, 0x76, 0x65, 0x63, 0x32, 0x66, 0x2c, + 0x20, 0x70, 0x33, 0x3a, 0x20, 0x76, 0x65, 0x63, 0x32, 0x66, 0x29, 0x20, + 0x2d, 0x3e, 0x20, 0x76, 0x65, 0x63, 0x32, 0x66, 0x20, 0x7b, 0x0d, 0x0a, + 0x20, 0x20, 0x20, 0x20, 0x6c, 0x65, 0x74, 0x20, 0x6d, 0x74, 0x20, 0x3d, + 0x20, 0x31, 0x2e, 0x30, 0x20, 0x2d, 0x20, 0x74, 0x3b, 0x0d, 0x0a, 0x20, + 0x20, 0x20, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x33, 0x2e, + 0x30, 0x20, 0x2a, 0x20, 0x6d, 0x74, 0x20, 0x2a, 0x20, 0x6d, 0x74, 0x20, + 0x2a, 0x20, 0x28, 0x70, 0x31, 0x20, 0x2d, 0x20, 0x70, 0x30, 0x29, 0x20, + 0x2b, 0x20, 0x36, 0x2e, 0x30, 0x20, 0x2a, 0x20, 0x6d, 0x74, 0x20, 0x2a, + 0x20, 0x74, 0x20, 0x2a, 0x20, 0x28, 0x70, 0x32, 0x20, 0x2d, 0x20, 0x70, + 0x31, 0x29, 0x20, 0x2b, 0x20, 0x33, 0x2e, 0x30, 0x20, 0x2a, 0x20, 0x74, + 0x20, 0x2a, 0x20, 0x74, 0x20, 0x2a, 0x20, 0x28, 0x70, 0x33, 0x20, 0x2d, + 0x20, 0x70, 0x32, 0x29, 0x3b, 0x0d, 0x0a, 0x7d, 0x0d, 0x0a, 0x0d, 0x0a, + 0x2f, 0x2f, 0x20, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, + 0x2d, 0x20, 0x44, 0x69, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x20, 0x74, + 0x6f, 0x20, 0x61, 0x20, 0x63, 0x75, 0x62, 0x69, 0x63, 0x20, 0x42, 0xc3, + 0xa9, 0x7a, 0x69, 0x65, 0x72, 0x20, 0x28, 0x73, 0x61, 0x6d, 0x70, 0x6c, + 0x69, 0x6e, 0x67, 0x20, 0x2b, 0x20, 0x4e, 0x65, 0x77, 0x74, 0x6f, 0x6e, + 0x20, 0x72, 0x65, 0x66, 0x69, 0x6e, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x29, + 0x20, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0d, + 0x0a, 0x66, 0x6e, 0x20, 0x64, 0x69, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, + 0x5f, 0x74, 0x6f, 0x5f, 0x63, 0x75, 0x62, 0x69, 0x63, 0x28, 0x70, 0x3a, + 0x20, 0x76, 0x65, 0x63, 0x32, 0x66, 0x2c, 0x20, 0x73, 0x65, 0x67, 0x3a, + 0x20, 0x53, 0x65, 0x67, 0x6d, 0x65, 0x6e, 0x74, 0x29, 0x20, 0x2d, 0x3e, + 0x20, 0x66, 0x33, 0x32, 0x20, 0x7b, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, + 0x6c, 0x65, 0x74, 0x20, 0x70, 0x30, 0x20, 0x3d, 0x20, 0x73, 0x65, 0x67, + 0x2e, 0x70, 0x30, 0x3b, 0x20, 0x6c, 0x65, 0x74, 0x20, 0x70, 0x31, 0x20, + 0x3d, 0x20, 0x73, 0x65, 0x67, 0x2e, 0x70, 0x31, 0x3b, 0x20, 0x6c, 0x65, + 0x74, 0x20, 0x70, 0x32, 0x20, 0x3d, 0x20, 0x73, 0x65, 0x67, 0x2e, 0x70, + 0x32, 0x3b, 0x20, 0x6c, 0x65, 0x74, 0x20, 0x70, 0x33, 0x20, 0x3d, 0x20, + 0x73, 0x65, 0x67, 0x2e, 0x70, 0x33, 0x3b, 0x0d, 0x0a, 0x0d, 0x0a, 0x20, + 0x20, 0x20, 0x20, 0x2f, 0x2f, 0x20, 0x55, 0x6e, 0x69, 0x66, 0x6f, 0x72, + 0x6d, 0x20, 0x73, 0x61, 0x6d, 0x70, 0x6c, 0x69, 0x6e, 0x67, 0x20, 0x74, + 0x6f, 0x20, 0x66, 0x69, 0x6e, 0x64, 0x20, 0x61, 0x20, 0x67, 0x6f, 0x6f, + 0x64, 0x20, 0x73, 0x74, 0x61, 0x72, 0x74, 0x69, 0x6e, 0x67, 0x20, 0x74, + 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x65, 0x74, 0x20, 0x73, 0x61, + 0x6d, 0x70, 0x6c, 0x65, 0x73, 0x20, 0x3d, 0x20, 0x31, 0x36, 0x75, 0x3b, + 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x76, 0x61, 0x72, 0x20, 0x62, 0x65, + 0x73, 0x74, 0x5f, 0x74, 0x20, 0x3d, 0x20, 0x30, 0x2e, 0x30, 0x3b, 0x0d, + 0x0a, 0x20, 0x20, 0x20, 0x20, 0x76, 0x61, 0x72, 0x20, 0x62, 0x65, 0x73, + 0x74, 0x5f, 0x64, 0x69, 0x73, 0x74, 0x20, 0x3d, 0x20, 0x31, 0x65, 0x32, + 0x30, 0x3b, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x66, 0x6f, 0x72, 0x20, + 0x28, 0x76, 0x61, 0x72, 0x20, 0x69, 0x20, 0x3d, 0x20, 0x30, 0x75, 0x3b, + 0x20, 0x69, 0x20, 0x3c, 0x20, 0x73, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x73, + 0x3b, 0x20, 0x69, 0x2b, 0x2b, 0x29, 0x20, 0x7b, 0x0d, 0x0a, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x65, 0x74, 0x20, 0x74, 0x20, + 0x3d, 0x20, 0x66, 0x33, 0x32, 0x28, 0x69, 0x29, 0x20, 0x2f, 0x20, 0x66, + 0x33, 0x32, 0x28, 0x73, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x73, 0x20, 0x2d, + 0x20, 0x31, 0x75, 0x29, 0x3b, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x6c, 0x65, 0x74, 0x20, 0x71, 0x20, 0x3d, 0x20, 0x65, + 0x76, 0x61, 0x6c, 0x5f, 0x63, 0x75, 0x62, 0x69, 0x63, 0x28, 0x74, 0x2c, + 0x20, 0x70, 0x30, 0x2c, 0x20, 0x70, 0x31, 0x2c, 0x20, 0x70, 0x32, 0x2c, + 0x20, 0x70, 0x33, 0x29, 0x3b, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x6c, 0x65, 0x74, 0x20, 0x64, 0x20, 0x3d, 0x20, 0x64, + 0x69, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x28, 0x70, 0x2c, 0x20, 0x71, + 0x29, 0x3b, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x69, 0x66, 0x20, 0x64, 0x20, 0x3c, 0x20, 0x62, 0x65, 0x73, 0x74, 0x5f, + 0x64, 0x69, 0x73, 0x74, 0x20, 0x7b, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x62, 0x65, 0x73, 0x74, + 0x5f, 0x64, 0x69, 0x73, 0x74, 0x20, 0x3d, 0x20, 0x64, 0x3b, 0x0d, 0x0a, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x62, 0x65, 0x73, 0x74, 0x5f, 0x74, 0x20, 0x3d, 0x20, 0x74, 0x3b, 0x0d, + 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7d, 0x0d, 0x0a, + 0x20, 0x20, 0x20, 0x20, 0x7d, 0x0d, 0x0a, 0x0d, 0x0a, 0x20, 0x20, 0x20, + 0x20, 0x2f, 0x2f, 0x20, 0x4e, 0x65, 0x77, 0x74, 0x6f, 0x6e, 0x20, 0x72, + 0x65, 0x66, 0x69, 0x6e, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x20, 0x6f, 0x6e, + 0x20, 0x74, 0x68, 0x65, 0x20, 0x73, 0x71, 0x75, 0x61, 0x72, 0x65, 0x64, + 0x20, 0x64, 0x69, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x20, 0x28, 0x6d, + 0x61, 0x78, 0x20, 0x34, 0x20, 0x69, 0x74, 0x65, 0x72, 0x61, 0x74, 0x69, + 0x6f, 0x6e, 0x73, 0x29, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x76, 0x61, + 0x72, 0x20, 0x74, 0x20, 0x3d, 0x20, 0x63, 0x6c, 0x61, 0x6d, 0x70, 0x28, + 0x62, 0x65, 0x73, 0x74, 0x5f, 0x74, 0x2c, 0x20, 0x30, 0x2e, 0x30, 0x2c, + 0x20, 0x31, 0x2e, 0x30, 0x29, 0x3b, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, + 0x66, 0x6f, 0x72, 0x20, 0x28, 0x76, 0x61, 0x72, 0x20, 0x69, 0x74, 0x65, + 0x72, 0x20, 0x3d, 0x20, 0x30, 0x75, 0x3b, 0x20, 0x69, 0x74, 0x65, 0x72, + 0x20, 0x3c, 0x20, 0x34, 0x75, 0x3b, 0x20, 0x69, 0x74, 0x65, 0x72, 0x2b, + 0x2b, 0x29, 0x20, 0x7b, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x6c, 0x65, 0x74, 0x20, 0x42, 0x20, 0x3d, 0x20, 0x65, 0x76, + 0x61, 0x6c, 0x5f, 0x63, 0x75, 0x62, 0x69, 0x63, 0x28, 0x74, 0x2c, 0x20, + 0x70, 0x30, 0x2c, 0x20, 0x70, 0x31, 0x2c, 0x20, 0x70, 0x32, 0x2c, 0x20, + 0x70, 0x33, 0x29, 0x20, 0x2d, 0x20, 0x70, 0x3b, 0x0d, 0x0a, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x65, 0x74, 0x20, 0x42, 0x70, 0x20, 0x3d, 0x20, 0x65, 0x76, 0x61, 0x6c, 0x5f, 0x63, 0x75, 0x62, 0x69, - 0x63, 0x28, 0x74, 0x2c, 0x20, 0x70, 0x30, 0x2c, 0x20, 0x70, 0x31, 0x2c, - 0x20, 0x70, 0x32, 0x2c, 0x20, 0x70, 0x33, 0x29, 0x3b, 0x0d, 0x0a, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x65, 0x74, 0x20, 0x64, - 0x20, 0x3d, 0x20, 0x64, 0x69, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x28, - 0x70, 0x2c, 0x20, 0x71, 0x29, 0x3b, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, 0x64, 0x20, 0x3c, 0x20, 0x62, - 0x65, 0x73, 0x74, 0x5f, 0x64, 0x69, 0x73, 0x74, 0x20, 0x7b, 0x0d, 0x0a, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x62, 0x65, 0x73, 0x74, 0x5f, 0x64, 0x69, 0x73, 0x74, 0x20, 0x3d, 0x20, - 0x64, 0x3b, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x62, 0x65, 0x73, 0x74, 0x5f, 0x74, 0x20, 0x3d, - 0x20, 0x74, 0x3b, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x7d, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x7d, 0x0d, 0x0a, 0x0d, - 0x0a, 0x20, 0x20, 0x20, 0x20, 0x2f, 0x2f, 0x20, 0x4e, 0x65, 0x77, 0x74, - 0x6f, 0x6e, 0x20, 0x72, 0x65, 0x66, 0x69, 0x6e, 0x65, 0x6d, 0x65, 0x6e, - 0x74, 0x20, 0x6f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x73, 0x71, 0x75, - 0x61, 0x72, 0x65, 0x64, 0x20, 0x64, 0x69, 0x73, 0x74, 0x61, 0x6e, 0x63, - 0x65, 0x20, 0x28, 0x6d, 0x61, 0x78, 0x20, 0x34, 0x20, 0x69, 0x74, 0x65, - 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x29, 0x0d, 0x0a, 0x20, 0x20, - 0x20, 0x20, 0x76, 0x61, 0x72, 0x20, 0x74, 0x20, 0x3d, 0x20, 0x63, 0x6c, - 0x61, 0x6d, 0x70, 0x28, 0x62, 0x65, 0x73, 0x74, 0x5f, 0x74, 0x2c, 0x20, - 0x30, 0x2e, 0x30, 0x2c, 0x20, 0x31, 0x2e, 0x30, 0x29, 0x3b, 0x0d, 0x0a, - 0x20, 0x20, 0x20, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x28, 0x76, 0x61, 0x72, - 0x20, 0x69, 0x74, 0x65, 0x72, 0x20, 0x3d, 0x20, 0x30, 0x75, 0x3b, 0x20, - 0x69, 0x74, 0x65, 0x72, 0x20, 0x3c, 0x20, 0x34, 0x75, 0x3b, 0x20, 0x69, - 0x74, 0x65, 0x72, 0x2b, 0x2b, 0x29, 0x20, 0x7b, 0x0d, 0x0a, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x65, 0x74, 0x20, 0x42, 0x20, - 0x3d, 0x20, 0x65, 0x76, 0x61, 0x6c, 0x5f, 0x63, 0x75, 0x62, 0x69, 0x63, + 0x63, 0x5f, 0x64, 0x65, 0x72, 0x69, 0x76, 0x61, 0x74, 0x69, 0x76, 0x65, 0x28, 0x74, 0x2c, 0x20, 0x70, 0x30, 0x2c, 0x20, 0x70, 0x31, 0x2c, 0x20, - 0x70, 0x32, 0x2c, 0x20, 0x70, 0x33, 0x29, 0x20, 0x2d, 0x20, 0x70, 0x3b, - 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x65, - 0x74, 0x20, 0x42, 0x70, 0x20, 0x3d, 0x20, 0x65, 0x76, 0x61, 0x6c, 0x5f, - 0x63, 0x75, 0x62, 0x69, 0x63, 0x5f, 0x64, 0x65, 0x72, 0x69, 0x76, 0x61, - 0x74, 0x69, 0x76, 0x65, 0x28, 0x74, 0x2c, 0x20, 0x70, 0x30, 0x2c, 0x20, - 0x70, 0x31, 0x2c, 0x20, 0x70, 0x32, 0x2c, 0x20, 0x70, 0x33, 0x29, 0x3b, - 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x65, - 0x74, 0x20, 0x66, 0x20, 0x3d, 0x20, 0x64, 0x6f, 0x74, 0x28, 0x42, 0x2c, - 0x20, 0x42, 0x70, 0x29, 0x3b, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x2f, 0x2f, 0x20, 0xc2, - 0xbd, 0x20, 0x64, 0x65, 0x72, 0x69, 0x76, 0x61, 0x74, 0x69, 0x76, 0x65, - 0x20, 0x6f, 0x66, 0x20, 0x7c, 0x42, 0x7c, 0xc2, 0xb2, 0x0d, 0x0a, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x65, 0x74, 0x20, 0x64, - 0x66, 0x20, 0x3d, 0x20, 0x64, 0x6f, 0x74, 0x28, 0x42, 0x70, 0x2c, 0x20, - 0x42, 0x70, 0x29, 0x20, 0x2b, 0x20, 0x64, 0x6f, 0x74, 0x28, 0x42, 0x2c, - 0x20, 0x33, 0x2e, 0x30, 0x20, 0x2a, 0x20, 0x28, 0x70, 0x32, 0x20, 0x2d, - 0x20, 0x70, 0x31, 0x20, 0x2b, 0x20, 0x28, 0x70, 0x33, 0x20, 0x2d, 0x20, - 0x70, 0x32, 0x20, 0x2d, 0x20, 0x70, 0x32, 0x20, 0x2b, 0x20, 0x70, 0x31, - 0x29, 0x20, 0x2a, 0x20, 0x32, 0x2e, 0x30, 0x20, 0x2a, 0x20, 0x74, 0x29, - 0x29, 0x3b, 0x20, 0x2f, 0x2f, 0x20, 0x73, 0x69, 0x6d, 0x70, 0x6c, 0x69, - 0x66, 0x69, 0x65, 0x64, 0x20, 0x32, 0x6e, 0x64, 0x20, 0x64, 0x65, 0x72, - 0x69, 0x76, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x69, 0x66, 0x20, 0x61, 0x62, 0x73, 0x28, 0x64, 0x66, 0x29, 0x20, 0x3c, - 0x20, 0x31, 0x65, 0x2d, 0x31, 0x32, 0x20, 0x7b, 0x20, 0x62, 0x72, 0x65, - 0x61, 0x6b, 0x3b, 0x20, 0x7d, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x6c, 0x65, 0x74, 0x20, 0x73, 0x74, 0x65, 0x70, 0x20, - 0x3d, 0x20, 0x66, 0x20, 0x2f, 0x20, 0x64, 0x66, 0x3b, 0x0d, 0x0a, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x74, 0x20, 0x3d, 0x20, 0x63, - 0x6c, 0x61, 0x6d, 0x70, 0x28, 0x74, 0x20, 0x2d, 0x20, 0x73, 0x74, 0x65, - 0x70, 0x2c, 0x20, 0x30, 0x2e, 0x30, 0x2c, 0x20, 0x31, 0x2e, 0x30, 0x29, - 0x3b, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x69, - 0x66, 0x20, 0x61, 0x62, 0x73, 0x28, 0x73, 0x74, 0x65, 0x70, 0x29, 0x20, - 0x3c, 0x20, 0x31, 0x65, 0x2d, 0x36, 0x20, 0x7b, 0x20, 0x62, 0x72, 0x65, - 0x61, 0x6b, 0x3b, 0x20, 0x7d, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x7d, - 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x65, 0x74, 0x20, 0x71, 0x5f, - 0x66, 0x69, 0x6e, 0x61, 0x6c, 0x20, 0x3d, 0x20, 0x65, 0x76, 0x61, 0x6c, - 0x5f, 0x63, 0x75, 0x62, 0x69, 0x63, 0x28, 0x74, 0x2c, 0x20, 0x70, 0x30, - 0x2c, 0x20, 0x70, 0x31, 0x2c, 0x20, 0x70, 0x32, 0x2c, 0x20, 0x70, 0x33, - 0x29, 0x3b, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x74, 0x75, - 0x72, 0x6e, 0x20, 0x64, 0x69, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x28, - 0x70, 0x2c, 0x20, 0x71, 0x5f, 0x66, 0x69, 0x6e, 0x61, 0x6c, 0x29, 0x3b, - 0x0d, 0x0a, 0x7d, 0x0d, 0x0a, 0x0d, 0x0a, 0x2f, 0x2f, 0x20, 0x2d, 0x2d, - 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x20, 0x41, 0x6e, 0x61, - 0x6c, 0x79, 0x74, 0x69, 0x63, 0x61, 0x6c, 0x20, 0x63, 0x75, 0x62, 0x69, - 0x63, 0x20, 0x72, 0x6f, 0x6f, 0x74, 0x20, 0x73, 0x6f, 0x6c, 0x76, 0x65, - 0x72, 0x20, 0x28, 0x66, 0x6f, 0x72, 0x20, 0x79, 0x2d, 0x63, 0x72, 0x6f, - 0x73, 0x73, 0x69, 0x6e, 0x67, 0x29, 0x20, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, - 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0d, 0x0a, 0x2f, 0x2f, 0x20, 0x52, 0x65, - 0x74, 0x75, 0x72, 0x6e, 0x73, 0x20, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, - 0x20, 0x6f, 0x66, 0x20, 0x72, 0x65, 0x61, 0x6c, 0x20, 0x72, 0x6f, 0x6f, - 0x74, 0x73, 0x20, 0x69, 0x6e, 0x20, 0x5b, 0x30, 0x2c, 0x31, 0x5d, 0x2c, - 0x20, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x64, 0x20, 0x69, 0x6e, 0x20, 0x72, - 0x6f, 0x6f, 0x74, 0x73, 0x20, 0x61, 0x72, 0x72, 0x61, 0x79, 0x20, 0x28, - 0x75, 0x70, 0x20, 0x74, 0x6f, 0x20, 0x33, 0x29, 0x2e, 0x0d, 0x0a, 0x66, - 0x6e, 0x20, 0x73, 0x6f, 0x6c, 0x76, 0x65, 0x5f, 0x63, 0x75, 0x62, 0x69, - 0x63, 0x5f, 0x69, 0x6e, 0x5f, 0x30, 0x31, 0x28, 0x63, 0x33, 0x3a, 0x20, - 0x66, 0x33, 0x32, 0x2c, 0x20, 0x63, 0x32, 0x3a, 0x20, 0x66, 0x33, 0x32, - 0x2c, 0x20, 0x63, 0x31, 0x3a, 0x20, 0x66, 0x33, 0x32, 0x2c, 0x20, 0x63, - 0x30, 0x3a, 0x20, 0x66, 0x33, 0x32, 0x2c, 0x20, 0x72, 0x6f, 0x6f, 0x74, - 0x73, 0x3a, 0x20, 0x70, 0x74, 0x72, 0x3c, 0x66, 0x75, 0x6e, 0x63, 0x74, - 0x69, 0x6f, 0x6e, 0x2c, 0x20, 0x61, 0x72, 0x72, 0x61, 0x79, 0x3c, 0x66, - 0x33, 0x32, 0x2c, 0x20, 0x33, 0x3e, 0x3e, 0x29, 0x20, 0x2d, 0x3e, 0x20, - 0x75, 0x33, 0x32, 0x20, 0x7b, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x2f, - 0x2f, 0x20, 0x4e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x69, 0x73, 0x65, 0x3a, - 0x20, 0x63, 0x33, 0x20, 0x2a, 0x20, 0x74, 0x5e, 0x33, 0x20, 0x2b, 0x20, - 0x63, 0x32, 0x20, 0x2a, 0x20, 0x74, 0x5e, 0x32, 0x20, 0x2b, 0x20, 0x63, - 0x31, 0x20, 0x2a, 0x20, 0x74, 0x20, 0x2b, 0x20, 0x63, 0x30, 0x20, 0x3d, - 0x20, 0x30, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, 0x61, - 0x62, 0x73, 0x28, 0x63, 0x33, 0x29, 0x20, 0x3c, 0x20, 0x31, 0x65, 0x2d, - 0x39, 0x20, 0x7b, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x2f, 0x2f, 0x20, 0x51, 0x75, 0x61, 0x64, 0x72, 0x61, 0x74, 0x69, - 0x63, 0x20, 0x66, 0x61, 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x0d, 0x0a, + 0x70, 0x32, 0x2c, 0x20, 0x70, 0x33, 0x29, 0x3b, 0x0d, 0x0a, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x65, 0x74, 0x20, 0x66, 0x20, + 0x3d, 0x20, 0x64, 0x6f, 0x74, 0x28, 0x42, 0x2c, 0x20, 0x42, 0x70, 0x29, + 0x3b, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x2f, 0x2f, 0x20, 0xc2, 0xbd, 0x20, 0x64, 0x65, + 0x72, 0x69, 0x76, 0x61, 0x74, 0x69, 0x76, 0x65, 0x20, 0x6f, 0x66, 0x20, + 0x7c, 0x42, 0x7c, 0xc2, 0xb2, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x6c, 0x65, 0x74, 0x20, 0x64, 0x66, 0x20, 0x3d, 0x20, + 0x64, 0x6f, 0x74, 0x28, 0x42, 0x70, 0x2c, 0x20, 0x42, 0x70, 0x29, 0x20, + 0x2b, 0x20, 0x64, 0x6f, 0x74, 0x28, 0x42, 0x2c, 0x20, 0x33, 0x2e, 0x30, + 0x20, 0x2a, 0x20, 0x28, 0x70, 0x32, 0x20, 0x2d, 0x20, 0x70, 0x31, 0x20, + 0x2b, 0x20, 0x28, 0x70, 0x33, 0x20, 0x2d, 0x20, 0x70, 0x32, 0x20, 0x2d, + 0x20, 0x70, 0x32, 0x20, 0x2b, 0x20, 0x70, 0x31, 0x29, 0x20, 0x2a, 0x20, + 0x32, 0x2e, 0x30, 0x20, 0x2a, 0x20, 0x74, 0x29, 0x29, 0x3b, 0x20, 0x2f, + 0x2f, 0x20, 0x73, 0x69, 0x6d, 0x70, 0x6c, 0x69, 0x66, 0x69, 0x65, 0x64, + 0x20, 0x32, 0x6e, 0x64, 0x20, 0x64, 0x65, 0x72, 0x69, 0x76, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, 0x61, - 0x62, 0x73, 0x28, 0x63, 0x32, 0x29, 0x20, 0x3c, 0x20, 0x31, 0x65, 0x2d, - 0x39, 0x20, 0x7b, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, 0x61, 0x62, 0x73, 0x28, - 0x63, 0x31, 0x29, 0x20, 0x3c, 0x20, 0x31, 0x65, 0x2d, 0x39, 0x20, 0x7b, - 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x30, 0x75, 0x3b, 0x20, - 0x7d, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x6c, 0x65, 0x74, 0x20, 0x74, 0x20, 0x3d, 0x20, 0x2d, - 0x63, 0x30, 0x20, 0x2f, 0x20, 0x63, 0x31, 0x3b, 0x0d, 0x0a, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, - 0x20, 0x74, 0x20, 0x3e, 0x3d, 0x20, 0x30, 0x2e, 0x30, 0x20, 0x26, 0x26, - 0x20, 0x74, 0x20, 0x3c, 0x3d, 0x20, 0x31, 0x2e, 0x30, 0x20, 0x7b, 0x0d, + 0x62, 0x73, 0x28, 0x64, 0x66, 0x29, 0x20, 0x3c, 0x20, 0x31, 0x65, 0x2d, + 0x31, 0x32, 0x20, 0x7b, 0x20, 0x62, 0x72, 0x65, 0x61, 0x6b, 0x3b, 0x20, + 0x7d, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x6c, + 0x65, 0x74, 0x20, 0x73, 0x74, 0x65, 0x70, 0x20, 0x3d, 0x20, 0x66, 0x20, + 0x2f, 0x20, 0x64, 0x66, 0x3b, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x74, 0x20, 0x3d, 0x20, 0x63, 0x6c, 0x61, 0x6d, 0x70, + 0x28, 0x74, 0x20, 0x2d, 0x20, 0x73, 0x74, 0x65, 0x70, 0x2c, 0x20, 0x30, + 0x2e, 0x30, 0x2c, 0x20, 0x31, 0x2e, 0x30, 0x29, 0x3b, 0x0d, 0x0a, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, 0x61, 0x62, + 0x73, 0x28, 0x73, 0x74, 0x65, 0x70, 0x29, 0x20, 0x3c, 0x20, 0x31, 0x65, + 0x2d, 0x36, 0x20, 0x7b, 0x20, 0x62, 0x72, 0x65, 0x61, 0x6b, 0x3b, 0x20, + 0x7d, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x7d, 0x0d, 0x0a, 0x20, 0x20, + 0x20, 0x20, 0x6c, 0x65, 0x74, 0x20, 0x71, 0x5f, 0x66, 0x69, 0x6e, 0x61, + 0x6c, 0x20, 0x3d, 0x20, 0x65, 0x76, 0x61, 0x6c, 0x5f, 0x63, 0x75, 0x62, + 0x69, 0x63, 0x28, 0x74, 0x2c, 0x20, 0x70, 0x30, 0x2c, 0x20, 0x70, 0x31, + 0x2c, 0x20, 0x70, 0x32, 0x2c, 0x20, 0x70, 0x33, 0x29, 0x3b, 0x0d, 0x0a, + 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x64, + 0x69, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x28, 0x70, 0x2c, 0x20, 0x71, + 0x5f, 0x66, 0x69, 0x6e, 0x61, 0x6c, 0x29, 0x3b, 0x0d, 0x0a, 0x7d, 0x0d, + 0x0a, 0x0d, 0x0a, 0x2f, 0x2f, 0x20, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, + 0x2d, 0x2d, 0x2d, 0x2d, 0x20, 0x41, 0x6e, 0x61, 0x6c, 0x79, 0x74, 0x69, + 0x63, 0x61, 0x6c, 0x20, 0x63, 0x75, 0x62, 0x69, 0x63, 0x20, 0x72, 0x6f, + 0x6f, 0x74, 0x20, 0x73, 0x6f, 0x6c, 0x76, 0x65, 0x72, 0x20, 0x28, 0x66, + 0x6f, 0x72, 0x20, 0x79, 0x2d, 0x63, 0x72, 0x6f, 0x73, 0x73, 0x69, 0x6e, + 0x67, 0x29, 0x20, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, + 0x2d, 0x0d, 0x0a, 0x2f, 0x2f, 0x20, 0x52, 0x65, 0x74, 0x75, 0x72, 0x6e, + 0x73, 0x20, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x20, 0x6f, 0x66, 0x20, + 0x72, 0x65, 0x61, 0x6c, 0x20, 0x72, 0x6f, 0x6f, 0x74, 0x73, 0x20, 0x69, + 0x6e, 0x20, 0x5b, 0x30, 0x2c, 0x31, 0x5d, 0x2c, 0x20, 0x73, 0x74, 0x6f, + 0x72, 0x65, 0x64, 0x20, 0x69, 0x6e, 0x20, 0x72, 0x6f, 0x6f, 0x74, 0x73, + 0x20, 0x61, 0x72, 0x72, 0x61, 0x79, 0x20, 0x28, 0x75, 0x70, 0x20, 0x74, + 0x6f, 0x20, 0x33, 0x29, 0x2e, 0x0d, 0x0a, 0x66, 0x6e, 0x20, 0x73, 0x6f, + 0x6c, 0x76, 0x65, 0x5f, 0x63, 0x75, 0x62, 0x69, 0x63, 0x5f, 0x69, 0x6e, + 0x5f, 0x30, 0x31, 0x28, 0x63, 0x33, 0x3a, 0x20, 0x66, 0x33, 0x32, 0x2c, + 0x20, 0x63, 0x32, 0x3a, 0x20, 0x66, 0x33, 0x32, 0x2c, 0x20, 0x63, 0x31, + 0x3a, 0x20, 0x66, 0x33, 0x32, 0x2c, 0x20, 0x63, 0x30, 0x3a, 0x20, 0x66, + 0x33, 0x32, 0x2c, 0x20, 0x72, 0x6f, 0x6f, 0x74, 0x73, 0x3a, 0x20, 0x70, + 0x74, 0x72, 0x3c, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x2c, + 0x20, 0x61, 0x72, 0x72, 0x61, 0x79, 0x3c, 0x66, 0x33, 0x32, 0x2c, 0x20, + 0x33, 0x3e, 0x3e, 0x29, 0x20, 0x2d, 0x3e, 0x20, 0x75, 0x33, 0x32, 0x20, + 0x7b, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x2f, 0x2f, 0x20, 0x4e, 0x6f, + 0x72, 0x6d, 0x61, 0x6c, 0x69, 0x73, 0x65, 0x3a, 0x20, 0x63, 0x33, 0x20, + 0x2a, 0x20, 0x74, 0x5e, 0x33, 0x20, 0x2b, 0x20, 0x63, 0x32, 0x20, 0x2a, + 0x20, 0x74, 0x5e, 0x32, 0x20, 0x2b, 0x20, 0x63, 0x31, 0x20, 0x2a, 0x20, + 0x74, 0x20, 0x2b, 0x20, 0x63, 0x30, 0x20, 0x3d, 0x20, 0x30, 0x0d, 0x0a, + 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, 0x61, 0x62, 0x73, 0x28, 0x63, + 0x33, 0x29, 0x20, 0x3c, 0x20, 0x31, 0x65, 0x2d, 0x39, 0x20, 0x7b, 0x0d, + 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x2f, 0x2f, 0x20, + 0x51, 0x75, 0x61, 0x64, 0x72, 0x61, 0x74, 0x69, 0x63, 0x20, 0x66, 0x61, + 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, 0x61, 0x62, 0x73, 0x28, 0x63, + 0x32, 0x29, 0x20, 0x3c, 0x20, 0x31, 0x65, 0x2d, 0x39, 0x20, 0x7b, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x28, 0x2a, 0x72, 0x6f, 0x6f, 0x74, 0x73, - 0x29, 0x5b, 0x30, 0x5d, 0x20, 0x3d, 0x20, 0x74, 0x3b, 0x0d, 0x0a, 0x20, + 0x20, 0x69, 0x66, 0x20, 0x61, 0x62, 0x73, 0x28, 0x63, 0x31, 0x29, 0x20, + 0x3c, 0x20, 0x31, 0x65, 0x2d, 0x39, 0x20, 0x7b, 0x20, 0x72, 0x65, 0x74, + 0x75, 0x72, 0x6e, 0x20, 0x30, 0x75, 0x3b, 0x20, 0x7d, 0x0d, 0x0a, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x6c, + 0x65, 0x74, 0x20, 0x74, 0x20, 0x3d, 0x20, 0x2d, 0x63, 0x30, 0x20, 0x2f, + 0x20, 0x63, 0x31, 0x3b, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, 0x74, 0x20, 0x3e, + 0x3d, 0x20, 0x30, 0x2e, 0x30, 0x20, 0x26, 0x26, 0x20, 0x74, 0x20, 0x3c, + 0x3d, 0x20, 0x31, 0x2e, 0x30, 0x20, 0x7b, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x31, 0x75, - 0x3b, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x7d, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, - 0x20, 0x30, 0x75, 0x3b, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x7d, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x6c, 0x65, 0x74, 0x20, 0x64, 0x69, 0x73, 0x63, 0x20, 0x3d, 0x20, - 0x63, 0x31, 0x20, 0x2a, 0x20, 0x63, 0x31, 0x20, 0x2d, 0x20, 0x34, 0x2e, - 0x30, 0x20, 0x2a, 0x20, 0x63, 0x32, 0x20, 0x2a, 0x20, 0x63, 0x30, 0x3b, - 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, - 0x20, 0x64, 0x69, 0x73, 0x63, 0x20, 0x3c, 0x20, 0x30, 0x2e, 0x30, 0x20, - 0x7b, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x30, 0x75, 0x3b, - 0x20, 0x7d, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x6c, 0x65, 0x74, 0x20, 0x73, 0x64, 0x20, 0x3d, 0x20, 0x73, 0x71, 0x72, - 0x74, 0x28, 0x64, 0x69, 0x73, 0x63, 0x29, 0x3b, 0x0d, 0x0a, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x65, 0x74, 0x20, 0x74, 0x30, - 0x20, 0x3d, 0x20, 0x28, 0x2d, 0x63, 0x31, 0x20, 0x2b, 0x20, 0x73, 0x64, - 0x29, 0x20, 0x2f, 0x20, 0x28, 0x32, 0x2e, 0x30, 0x20, 0x2a, 0x20, 0x63, - 0x32, 0x29, 0x3b, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x6c, 0x65, 0x74, 0x20, 0x74, 0x31, 0x20, 0x3d, 0x20, 0x28, 0x2d, - 0x63, 0x31, 0x20, 0x2d, 0x20, 0x73, 0x64, 0x29, 0x20, 0x2f, 0x20, 0x28, - 0x32, 0x2e, 0x30, 0x20, 0x2a, 0x20, 0x63, 0x32, 0x29, 0x3b, 0x0d, 0x0a, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x76, 0x61, 0x72, 0x20, - 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x20, 0x3d, 0x20, 0x30, 0x75, 0x3b, 0x0d, - 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, - 0x74, 0x30, 0x20, 0x3e, 0x3d, 0x20, 0x30, 0x2e, 0x30, 0x20, 0x26, 0x26, - 0x20, 0x74, 0x30, 0x20, 0x3c, 0x3d, 0x20, 0x31, 0x2e, 0x30, 0x20, 0x7b, - 0x20, 0x28, 0x2a, 0x72, 0x6f, 0x6f, 0x74, 0x73, 0x29, 0x5b, 0x63, 0x6f, - 0x75, 0x6e, 0x74, 0x5d, 0x20, 0x3d, 0x20, 0x74, 0x30, 0x3b, 0x20, 0x63, - 0x6f, 0x75, 0x6e, 0x74, 0x2b, 0x2b, 0x3b, 0x20, 0x7d, 0x0d, 0x0a, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, 0x74, 0x31, - 0x20, 0x3e, 0x3d, 0x20, 0x30, 0x2e, 0x30, 0x20, 0x26, 0x26, 0x20, 0x74, - 0x31, 0x20, 0x3c, 0x3d, 0x20, 0x31, 0x2e, 0x30, 0x20, 0x7b, 0x20, 0x28, - 0x2a, 0x72, 0x6f, 0x6f, 0x74, 0x73, 0x29, 0x5b, 0x63, 0x6f, 0x75, 0x6e, - 0x74, 0x5d, 0x20, 0x3d, 0x20, 0x74, 0x31, 0x3b, 0x20, 0x63, 0x6f, 0x75, - 0x6e, 0x74, 0x2b, 0x2b, 0x3b, 0x20, 0x7d, 0x0d, 0x0a, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, - 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x3b, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, - 0x7d, 0x0d, 0x0a, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x2f, 0x2f, 0x20, - 0x44, 0x65, 0x70, 0x72, 0x65, 0x73, 0x73, 0x65, 0x64, 0x20, 0x63, 0x75, - 0x62, 0x69, 0x63, 0x3a, 0x20, 0x6c, 0x65, 0x74, 0x20, 0x74, 0x20, 0x3d, - 0x20, 0x78, 0x20, 0x2d, 0x20, 0x63, 0x32, 0x2f, 0x28, 0x33, 0x2a, 0x63, - 0x33, 0x29, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x65, 0x74, 0x20, - 0x61, 0x20, 0x3d, 0x20, 0x63, 0x32, 0x20, 0x2f, 0x20, 0x63, 0x33, 0x3b, - 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x65, 0x74, 0x20, 0x62, 0x20, - 0x3d, 0x20, 0x63, 0x31, 0x20, 0x2f, 0x20, 0x63, 0x33, 0x3b, 0x0d, 0x0a, - 0x20, 0x20, 0x20, 0x20, 0x6c, 0x65, 0x74, 0x20, 0x63, 0x20, 0x3d, 0x20, - 0x63, 0x30, 0x20, 0x2f, 0x20, 0x63, 0x33, 0x3b, 0x0d, 0x0a, 0x20, 0x20, - 0x20, 0x20, 0x6c, 0x65, 0x74, 0x20, 0x70, 0x20, 0x3d, 0x20, 0x62, 0x20, - 0x2d, 0x20, 0x61, 0x20, 0x2a, 0x20, 0x61, 0x20, 0x2f, 0x20, 0x33, 0x2e, - 0x30, 0x3b, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x65, 0x74, 0x20, - 0x71, 0x20, 0x3d, 0x20, 0x32, 0x2e, 0x30, 0x20, 0x2a, 0x20, 0x61, 0x20, - 0x2a, 0x20, 0x61, 0x20, 0x2a, 0x20, 0x61, 0x20, 0x2f, 0x20, 0x32, 0x37, - 0x2e, 0x30, 0x20, 0x2d, 0x20, 0x61, 0x20, 0x2a, 0x20, 0x62, 0x20, 0x2f, - 0x20, 0x33, 0x2e, 0x30, 0x20, 0x2b, 0x20, 0x63, 0x3b, 0x0d, 0x0a, 0x20, - 0x20, 0x20, 0x20, 0x6c, 0x65, 0x74, 0x20, 0x64, 0x69, 0x73, 0x63, 0x20, - 0x3d, 0x20, 0x71, 0x20, 0x2a, 0x20, 0x71, 0x20, 0x2f, 0x20, 0x34, 0x2e, - 0x30, 0x20, 0x2b, 0x20, 0x70, 0x20, 0x2a, 0x20, 0x70, 0x20, 0x2a, 0x20, - 0x70, 0x20, 0x2f, 0x20, 0x32, 0x37, 0x2e, 0x30, 0x3b, 0x0d, 0x0a, 0x0d, - 0x0a, 0x20, 0x20, 0x20, 0x20, 0x76, 0x61, 0x72, 0x20, 0x63, 0x6f, 0x75, - 0x6e, 0x74, 0x20, 0x3d, 0x20, 0x30, 0x75, 0x3b, 0x0d, 0x0a, 0x20, 0x20, - 0x20, 0x20, 0x6c, 0x65, 0x74, 0x20, 0x73, 0x68, 0x69, 0x66, 0x74, 0x20, - 0x3d, 0x20, 0x61, 0x20, 0x2f, 0x20, 0x33, 0x2e, 0x30, 0x3b, 0x0d, 0x0a, - 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, 0x64, 0x69, 0x73, - 0x63, 0x20, 0x3e, 0x20, 0x30, 0x2e, 0x30, 0x20, 0x7b, 0x0d, 0x0a, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x65, 0x74, 0x20, 0x73, - 0x64, 0x20, 0x3d, 0x20, 0x73, 0x71, 0x72, 0x74, 0x28, 0x64, 0x69, 0x73, - 0x63, 0x29, 0x3b, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x6c, 0x65, 0x74, 0x20, 0x75, 0x20, 0x3d, 0x20, 0x73, 0x69, 0x67, - 0x6e, 0x28, 0x2d, 0x71, 0x2f, 0x32, 0x2e, 0x30, 0x20, 0x2b, 0x20, 0x73, - 0x64, 0x29, 0x20, 0x2a, 0x20, 0x70, 0x6f, 0x77, 0x28, 0x61, 0x62, 0x73, - 0x28, 0x2d, 0x71, 0x2f, 0x32, 0x2e, 0x30, 0x20, 0x2b, 0x20, 0x73, 0x64, - 0x29, 0x2c, 0x20, 0x31, 0x2e, 0x30, 0x2f, 0x33, 0x2e, 0x30, 0x29, 0x3b, - 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x65, - 0x74, 0x20, 0x76, 0x20, 0x3d, 0x20, 0x73, 0x69, 0x67, 0x6e, 0x28, 0x2d, - 0x71, 0x2f, 0x32, 0x2e, 0x30, 0x20, 0x2d, 0x20, 0x73, 0x64, 0x29, 0x20, - 0x2a, 0x20, 0x70, 0x6f, 0x77, 0x28, 0x61, 0x62, 0x73, 0x28, 0x2d, 0x71, - 0x2f, 0x32, 0x2e, 0x30, 0x20, 0x2d, 0x20, 0x73, 0x64, 0x29, 0x2c, 0x20, - 0x31, 0x2e, 0x30, 0x2f, 0x33, 0x2e, 0x30, 0x29, 0x3b, 0x0d, 0x0a, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x65, 0x74, 0x20, 0x78, - 0x31, 0x20, 0x3d, 0x20, 0x75, 0x20, 0x2b, 0x20, 0x76, 0x3b, 0x0d, 0x0a, + 0x20, 0x28, 0x2a, 0x72, 0x6f, 0x6f, 0x74, 0x73, 0x29, 0x5b, 0x30, 0x5d, + 0x20, 0x3d, 0x20, 0x74, 0x3b, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x72, + 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x31, 0x75, 0x3b, 0x0d, 0x0a, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7d, + 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x30, 0x75, 0x3b, + 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7d, 0x0d, + 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x65, 0x74, + 0x20, 0x64, 0x69, 0x73, 0x63, 0x20, 0x3d, 0x20, 0x63, 0x31, 0x20, 0x2a, + 0x20, 0x63, 0x31, 0x20, 0x2d, 0x20, 0x34, 0x2e, 0x30, 0x20, 0x2a, 0x20, + 0x63, 0x32, 0x20, 0x2a, 0x20, 0x63, 0x30, 0x3b, 0x0d, 0x0a, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, 0x64, 0x69, 0x73, + 0x63, 0x20, 0x3c, 0x20, 0x30, 0x2e, 0x30, 0x20, 0x7b, 0x20, 0x72, 0x65, + 0x74, 0x75, 0x72, 0x6e, 0x20, 0x30, 0x75, 0x3b, 0x20, 0x7d, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x65, 0x74, 0x20, - 0x74, 0x20, 0x3d, 0x20, 0x78, 0x31, 0x20, 0x2d, 0x20, 0x73, 0x68, 0x69, - 0x66, 0x74, 0x3b, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x73, 0x64, 0x20, 0x3d, 0x20, 0x73, 0x71, 0x72, 0x74, 0x28, 0x64, 0x69, + 0x73, 0x63, 0x29, 0x3b, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x6c, 0x65, 0x74, 0x20, 0x74, 0x30, 0x20, 0x3d, 0x20, 0x28, + 0x2d, 0x63, 0x31, 0x20, 0x2b, 0x20, 0x73, 0x64, 0x29, 0x20, 0x2f, 0x20, + 0x28, 0x32, 0x2e, 0x30, 0x20, 0x2a, 0x20, 0x63, 0x32, 0x29, 0x3b, 0x0d, + 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x65, 0x74, + 0x20, 0x74, 0x31, 0x20, 0x3d, 0x20, 0x28, 0x2d, 0x63, 0x31, 0x20, 0x2d, + 0x20, 0x73, 0x64, 0x29, 0x20, 0x2f, 0x20, 0x28, 0x32, 0x2e, 0x30, 0x20, + 0x2a, 0x20, 0x63, 0x32, 0x29, 0x3b, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x76, 0x61, 0x72, 0x20, 0x63, 0x6f, 0x75, 0x6e, + 0x74, 0x20, 0x3d, 0x20, 0x30, 0x75, 0x3b, 0x0d, 0x0a, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, 0x74, 0x30, 0x20, 0x3e, + 0x3d, 0x20, 0x30, 0x2e, 0x30, 0x20, 0x26, 0x26, 0x20, 0x74, 0x30, 0x20, + 0x3c, 0x3d, 0x20, 0x31, 0x2e, 0x30, 0x20, 0x7b, 0x20, 0x28, 0x2a, 0x72, + 0x6f, 0x6f, 0x74, 0x73, 0x29, 0x5b, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x5d, + 0x20, 0x3d, 0x20, 0x74, 0x30, 0x3b, 0x20, 0x63, 0x6f, 0x75, 0x6e, 0x74, + 0x2b, 0x2b, 0x3b, 0x20, 0x7d, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, 0x74, 0x31, 0x20, 0x3e, 0x3d, 0x20, + 0x30, 0x2e, 0x30, 0x20, 0x26, 0x26, 0x20, 0x74, 0x31, 0x20, 0x3c, 0x3d, + 0x20, 0x31, 0x2e, 0x30, 0x20, 0x7b, 0x20, 0x28, 0x2a, 0x72, 0x6f, 0x6f, + 0x74, 0x73, 0x29, 0x5b, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x5d, 0x20, 0x3d, + 0x20, 0x74, 0x31, 0x3b, 0x20, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x2b, 0x2b, + 0x3b, 0x20, 0x7d, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x63, 0x6f, 0x75, 0x6e, + 0x74, 0x3b, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x7d, 0x0d, 0x0a, 0x0d, + 0x0a, 0x20, 0x20, 0x20, 0x20, 0x2f, 0x2f, 0x20, 0x44, 0x65, 0x70, 0x72, + 0x65, 0x73, 0x73, 0x65, 0x64, 0x20, 0x63, 0x75, 0x62, 0x69, 0x63, 0x3a, + 0x20, 0x6c, 0x65, 0x74, 0x20, 0x74, 0x20, 0x3d, 0x20, 0x78, 0x20, 0x2d, + 0x20, 0x63, 0x32, 0x2f, 0x28, 0x33, 0x2a, 0x63, 0x33, 0x29, 0x0d, 0x0a, + 0x20, 0x20, 0x20, 0x20, 0x6c, 0x65, 0x74, 0x20, 0x61, 0x20, 0x3d, 0x20, + 0x63, 0x32, 0x20, 0x2f, 0x20, 0x63, 0x33, 0x3b, 0x0d, 0x0a, 0x20, 0x20, + 0x20, 0x20, 0x6c, 0x65, 0x74, 0x20, 0x62, 0x20, 0x3d, 0x20, 0x63, 0x31, + 0x20, 0x2f, 0x20, 0x63, 0x33, 0x3b, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, + 0x6c, 0x65, 0x74, 0x20, 0x63, 0x20, 0x3d, 0x20, 0x63, 0x30, 0x20, 0x2f, + 0x20, 0x63, 0x33, 0x3b, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x65, + 0x74, 0x20, 0x70, 0x20, 0x3d, 0x20, 0x62, 0x20, 0x2d, 0x20, 0x61, 0x20, + 0x2a, 0x20, 0x61, 0x20, 0x2f, 0x20, 0x33, 0x2e, 0x30, 0x3b, 0x0d, 0x0a, + 0x20, 0x20, 0x20, 0x20, 0x6c, 0x65, 0x74, 0x20, 0x71, 0x20, 0x3d, 0x20, + 0x32, 0x2e, 0x30, 0x20, 0x2a, 0x20, 0x61, 0x20, 0x2a, 0x20, 0x61, 0x20, + 0x2a, 0x20, 0x61, 0x20, 0x2f, 0x20, 0x32, 0x37, 0x2e, 0x30, 0x20, 0x2d, + 0x20, 0x61, 0x20, 0x2a, 0x20, 0x62, 0x20, 0x2f, 0x20, 0x33, 0x2e, 0x30, + 0x20, 0x2b, 0x20, 0x63, 0x3b, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x6c, + 0x65, 0x74, 0x20, 0x64, 0x69, 0x73, 0x63, 0x20, 0x3d, 0x20, 0x71, 0x20, + 0x2a, 0x20, 0x71, 0x20, 0x2f, 0x20, 0x34, 0x2e, 0x30, 0x20, 0x2b, 0x20, + 0x70, 0x20, 0x2a, 0x20, 0x70, 0x20, 0x2a, 0x20, 0x70, 0x20, 0x2f, 0x20, + 0x32, 0x37, 0x2e, 0x30, 0x3b, 0x0d, 0x0a, 0x0d, 0x0a, 0x20, 0x20, 0x20, + 0x20, 0x76, 0x61, 0x72, 0x20, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x20, 0x3d, + 0x20, 0x30, 0x75, 0x3b, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x65, + 0x74, 0x20, 0x73, 0x68, 0x69, 0x66, 0x74, 0x20, 0x3d, 0x20, 0x61, 0x20, + 0x2f, 0x20, 0x33, 0x2e, 0x30, 0x3b, 0x0d, 0x0a, 0x0d, 0x0a, 0x20, 0x20, + 0x20, 0x20, 0x69, 0x66, 0x20, 0x64, 0x69, 0x73, 0x63, 0x20, 0x3e, 0x20, + 0x30, 0x2e, 0x30, 0x20, 0x7b, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x6c, 0x65, 0x74, 0x20, 0x73, 0x64, 0x20, 0x3d, 0x20, + 0x73, 0x71, 0x72, 0x74, 0x28, 0x64, 0x69, 0x73, 0x63, 0x29, 0x3b, 0x0d, + 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x65, 0x74, + 0x20, 0x75, 0x20, 0x3d, 0x20, 0x73, 0x69, 0x67, 0x6e, 0x28, 0x2d, 0x71, + 0x2f, 0x32, 0x2e, 0x30, 0x20, 0x2b, 0x20, 0x73, 0x64, 0x29, 0x20, 0x2a, + 0x20, 0x70, 0x6f, 0x77, 0x28, 0x61, 0x62, 0x73, 0x28, 0x2d, 0x71, 0x2f, + 0x32, 0x2e, 0x30, 0x20, 0x2b, 0x20, 0x73, 0x64, 0x29, 0x2c, 0x20, 0x31, + 0x2e, 0x30, 0x2f, 0x33, 0x2e, 0x30, 0x29, 0x3b, 0x0d, 0x0a, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x65, 0x74, 0x20, 0x76, 0x20, + 0x3d, 0x20, 0x73, 0x69, 0x67, 0x6e, 0x28, 0x2d, 0x71, 0x2f, 0x32, 0x2e, + 0x30, 0x20, 0x2d, 0x20, 0x73, 0x64, 0x29, 0x20, 0x2a, 0x20, 0x70, 0x6f, + 0x77, 0x28, 0x61, 0x62, 0x73, 0x28, 0x2d, 0x71, 0x2f, 0x32, 0x2e, 0x30, + 0x20, 0x2d, 0x20, 0x73, 0x64, 0x29, 0x2c, 0x20, 0x31, 0x2e, 0x30, 0x2f, + 0x33, 0x2e, 0x30, 0x29, 0x3b, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x6c, 0x65, 0x74, 0x20, 0x78, 0x31, 0x20, 0x3d, 0x20, + 0x75, 0x20, 0x2b, 0x20, 0x76, 0x3b, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x6c, 0x65, 0x74, 0x20, 0x74, 0x20, 0x3d, 0x20, + 0x78, 0x31, 0x20, 0x2d, 0x20, 0x73, 0x68, 0x69, 0x66, 0x74, 0x3b, 0x0d, + 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, + 0x74, 0x20, 0x3e, 0x3d, 0x20, 0x30, 0x2e, 0x30, 0x20, 0x26, 0x26, 0x20, + 0x74, 0x20, 0x3c, 0x3d, 0x20, 0x31, 0x2e, 0x30, 0x20, 0x7b, 0x20, 0x28, + 0x2a, 0x72, 0x6f, 0x6f, 0x74, 0x73, 0x29, 0x5b, 0x63, 0x6f, 0x75, 0x6e, + 0x74, 0x5d, 0x20, 0x3d, 0x20, 0x74, 0x3b, 0x20, 0x63, 0x6f, 0x75, 0x6e, + 0x74, 0x2b, 0x2b, 0x3b, 0x20, 0x7d, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, + 0x7d, 0x20, 0x65, 0x6c, 0x73, 0x65, 0x20, 0x69, 0x66, 0x20, 0x64, 0x69, + 0x73, 0x63, 0x20, 0x3d, 0x3d, 0x20, 0x30, 0x2e, 0x30, 0x20, 0x7b, 0x0d, + 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x65, 0x74, + 0x20, 0x75, 0x20, 0x3d, 0x20, 0x73, 0x69, 0x67, 0x6e, 0x28, 0x2d, 0x71, + 0x2f, 0x32, 0x2e, 0x30, 0x29, 0x20, 0x2a, 0x20, 0x70, 0x6f, 0x77, 0x28, + 0x61, 0x62, 0x73, 0x28, 0x2d, 0x71, 0x2f, 0x32, 0x2e, 0x30, 0x29, 0x2c, + 0x20, 0x31, 0x2e, 0x30, 0x2f, 0x33, 0x2e, 0x30, 0x29, 0x3b, 0x0d, 0x0a, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x65, 0x74, 0x20, + 0x78, 0x31, 0x20, 0x3d, 0x20, 0x32, 0x2e, 0x30, 0x20, 0x2a, 0x20, 0x75, + 0x3b, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x6c, + 0x65, 0x74, 0x20, 0x78, 0x32, 0x20, 0x3d, 0x20, 0x2d, 0x75, 0x3b, 0x0d, + 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x65, 0x74, + 0x20, 0x74, 0x31, 0x20, 0x3d, 0x20, 0x78, 0x31, 0x20, 0x2d, 0x20, 0x73, + 0x68, 0x69, 0x66, 0x74, 0x3b, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x6c, 0x65, 0x74, 0x20, 0x74, 0x32, 0x20, 0x3d, 0x20, + 0x78, 0x32, 0x20, 0x2d, 0x20, 0x73, 0x68, 0x69, 0x66, 0x74, 0x3b, 0x0d, + 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, + 0x74, 0x31, 0x20, 0x3e, 0x3d, 0x20, 0x30, 0x2e, 0x30, 0x20, 0x26, 0x26, + 0x20, 0x74, 0x31, 0x20, 0x3c, 0x3d, 0x20, 0x31, 0x2e, 0x30, 0x20, 0x7b, + 0x20, 0x28, 0x2a, 0x72, 0x6f, 0x6f, 0x74, 0x73, 0x29, 0x5b, 0x63, 0x6f, + 0x75, 0x6e, 0x74, 0x5d, 0x20, 0x3d, 0x20, 0x74, 0x31, 0x3b, 0x20, 0x63, + 0x6f, 0x75, 0x6e, 0x74, 0x2b, 0x2b, 0x3b, 0x20, 0x7d, 0x0d, 0x0a, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, 0x74, 0x32, + 0x20, 0x3e, 0x3d, 0x20, 0x30, 0x2e, 0x30, 0x20, 0x26, 0x26, 0x20, 0x74, + 0x32, 0x20, 0x3c, 0x3d, 0x20, 0x31, 0x2e, 0x30, 0x20, 0x7b, 0x20, 0x28, + 0x2a, 0x72, 0x6f, 0x6f, 0x74, 0x73, 0x29, 0x5b, 0x63, 0x6f, 0x75, 0x6e, + 0x74, 0x5d, 0x20, 0x3d, 0x20, 0x74, 0x32, 0x3b, 0x20, 0x63, 0x6f, 0x75, + 0x6e, 0x74, 0x2b, 0x2b, 0x3b, 0x20, 0x7d, 0x0d, 0x0a, 0x20, 0x20, 0x20, + 0x20, 0x7d, 0x20, 0x65, 0x6c, 0x73, 0x65, 0x20, 0x7b, 0x0d, 0x0a, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x65, 0x74, 0x20, 0x70, + 0x68, 0x69, 0x20, 0x3d, 0x20, 0x61, 0x63, 0x6f, 0x73, 0x28, 0x20, 0x2d, + 0x71, 0x20, 0x2f, 0x20, 0x28, 0x32, 0x2e, 0x30, 0x20, 0x2a, 0x20, 0x73, + 0x71, 0x72, 0x74, 0x28, 0x2d, 0x70, 0x2a, 0x70, 0x2a, 0x70, 0x2f, 0x32, + 0x37, 0x2e, 0x30, 0x29, 0x29, 0x20, 0x29, 0x3b, 0x0d, 0x0a, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x65, 0x74, 0x20, 0x72, 0x20, + 0x3d, 0x20, 0x32, 0x2e, 0x30, 0x20, 0x2a, 0x20, 0x73, 0x71, 0x72, 0x74, + 0x28, 0x2d, 0x70, 0x2f, 0x33, 0x2e, 0x30, 0x29, 0x3b, 0x0d, 0x0a, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x28, + 0x76, 0x61, 0x72, 0x20, 0x6b, 0x20, 0x3d, 0x20, 0x30, 0x75, 0x3b, 0x20, + 0x6b, 0x20, 0x3c, 0x20, 0x33, 0x75, 0x3b, 0x20, 0x6b, 0x2b, 0x2b, 0x29, + 0x20, 0x7b, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x6c, 0x65, 0x74, 0x20, 0x78, 0x20, 0x3d, 0x20, + 0x72, 0x20, 0x2a, 0x20, 0x63, 0x6f, 0x73, 0x28, 0x28, 0x70, 0x68, 0x69, + 0x20, 0x2b, 0x20, 0x32, 0x2e, 0x30, 0x20, 0x2a, 0x20, 0x33, 0x2e, 0x31, + 0x34, 0x31, 0x35, 0x39, 0x32, 0x36, 0x35, 0x33, 0x35, 0x20, 0x2a, 0x20, + 0x66, 0x33, 0x32, 0x28, 0x6b, 0x29, 0x29, 0x20, 0x2f, 0x20, 0x33, 0x2e, + 0x30, 0x29, 0x3b, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x65, 0x74, 0x20, 0x74, 0x20, 0x3d, + 0x20, 0x78, 0x20, 0x2d, 0x20, 0x73, 0x68, 0x69, 0x66, 0x74, 0x3b, 0x0d, + 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, 0x74, 0x20, 0x3e, 0x3d, 0x20, 0x30, 0x2e, 0x30, 0x20, 0x26, 0x26, 0x20, 0x74, 0x20, 0x3c, 0x3d, 0x20, 0x31, 0x2e, 0x30, 0x20, 0x7b, 0x20, 0x28, 0x2a, 0x72, 0x6f, 0x6f, 0x74, 0x73, 0x29, 0x5b, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x5d, 0x20, 0x3d, 0x20, 0x74, 0x3b, 0x20, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x2b, 0x2b, 0x3b, 0x20, 0x7d, 0x0d, 0x0a, - 0x20, 0x20, 0x20, 0x20, 0x7d, 0x20, 0x65, 0x6c, 0x73, 0x65, 0x20, 0x69, - 0x66, 0x20, 0x64, 0x69, 0x73, 0x63, 0x20, 0x3d, 0x3d, 0x20, 0x30, 0x2e, - 0x30, 0x20, 0x7b, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x6c, 0x65, 0x74, 0x20, 0x75, 0x20, 0x3d, 0x20, 0x73, 0x69, 0x67, - 0x6e, 0x28, 0x2d, 0x71, 0x2f, 0x32, 0x2e, 0x30, 0x29, 0x20, 0x2a, 0x20, - 0x70, 0x6f, 0x77, 0x28, 0x61, 0x62, 0x73, 0x28, 0x2d, 0x71, 0x2f, 0x32, - 0x2e, 0x30, 0x29, 0x2c, 0x20, 0x31, 0x2e, 0x30, 0x2f, 0x33, 0x2e, 0x30, - 0x29, 0x3b, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x6c, 0x65, 0x74, 0x20, 0x78, 0x31, 0x20, 0x3d, 0x20, 0x32, 0x2e, 0x30, - 0x20, 0x2a, 0x20, 0x75, 0x3b, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x6c, 0x65, 0x74, 0x20, 0x78, 0x32, 0x20, 0x3d, 0x20, - 0x2d, 0x75, 0x3b, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x6c, 0x65, 0x74, 0x20, 0x74, 0x31, 0x20, 0x3d, 0x20, 0x78, 0x31, - 0x20, 0x2d, 0x20, 0x73, 0x68, 0x69, 0x66, 0x74, 0x3b, 0x0d, 0x0a, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x65, 0x74, 0x20, 0x74, - 0x32, 0x20, 0x3d, 0x20, 0x78, 0x32, 0x20, 0x2d, 0x20, 0x73, 0x68, 0x69, - 0x66, 0x74, 0x3b, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x69, 0x66, 0x20, 0x74, 0x31, 0x20, 0x3e, 0x3d, 0x20, 0x30, 0x2e, - 0x30, 0x20, 0x26, 0x26, 0x20, 0x74, 0x31, 0x20, 0x3c, 0x3d, 0x20, 0x31, - 0x2e, 0x30, 0x20, 0x7b, 0x20, 0x28, 0x2a, 0x72, 0x6f, 0x6f, 0x74, 0x73, - 0x29, 0x5b, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x5d, 0x20, 0x3d, 0x20, 0x74, - 0x31, 0x3b, 0x20, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x2b, 0x2b, 0x3b, 0x20, - 0x7d, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x69, - 0x66, 0x20, 0x74, 0x32, 0x20, 0x3e, 0x3d, 0x20, 0x30, 0x2e, 0x30, 0x20, - 0x26, 0x26, 0x20, 0x74, 0x32, 0x20, 0x3c, 0x3d, 0x20, 0x31, 0x2e, 0x30, - 0x20, 0x7b, 0x20, 0x28, 0x2a, 0x72, 0x6f, 0x6f, 0x74, 0x73, 0x29, 0x5b, - 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x5d, 0x20, 0x3d, 0x20, 0x74, 0x32, 0x3b, - 0x20, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x2b, 0x2b, 0x3b, 0x20, 0x7d, 0x0d, - 0x0a, 0x20, 0x20, 0x20, 0x20, 0x7d, 0x20, 0x65, 0x6c, 0x73, 0x65, 0x20, - 0x7b, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x6c, - 0x65, 0x74, 0x20, 0x70, 0x68, 0x69, 0x20, 0x3d, 0x20, 0x61, 0x63, 0x6f, - 0x73, 0x28, 0x20, 0x2d, 0x71, 0x20, 0x2f, 0x20, 0x28, 0x32, 0x2e, 0x30, - 0x20, 0x2a, 0x20, 0x73, 0x71, 0x72, 0x74, 0x28, 0x2d, 0x70, 0x2a, 0x70, - 0x2a, 0x70, 0x2f, 0x32, 0x37, 0x2e, 0x30, 0x29, 0x29, 0x20, 0x29, 0x3b, - 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x65, - 0x74, 0x20, 0x72, 0x20, 0x3d, 0x20, 0x32, 0x2e, 0x30, 0x20, 0x2a, 0x20, - 0x73, 0x71, 0x72, 0x74, 0x28, 0x2d, 0x70, 0x2f, 0x33, 0x2e, 0x30, 0x29, - 0x3b, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x66, - 0x6f, 0x72, 0x20, 0x28, 0x76, 0x61, 0x72, 0x20, 0x6b, 0x20, 0x3d, 0x20, - 0x30, 0x75, 0x3b, 0x20, 0x6b, 0x20, 0x3c, 0x20, 0x33, 0x75, 0x3b, 0x20, - 0x6b, 0x2b, 0x2b, 0x29, 0x20, 0x7b, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x65, 0x74, 0x20, - 0x78, 0x20, 0x3d, 0x20, 0x72, 0x20, 0x2a, 0x20, 0x63, 0x6f, 0x73, 0x28, - 0x28, 0x70, 0x68, 0x69, 0x20, 0x2b, 0x20, 0x32, 0x2e, 0x30, 0x20, 0x2a, - 0x20, 0x33, 0x2e, 0x31, 0x34, 0x31, 0x35, 0x39, 0x32, 0x36, 0x35, 0x33, - 0x35, 0x20, 0x2a, 0x20, 0x66, 0x33, 0x32, 0x28, 0x6b, 0x29, 0x29, 0x20, - 0x2f, 0x20, 0x33, 0x2e, 0x30, 0x29, 0x3b, 0x0d, 0x0a, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x65, 0x74, - 0x20, 0x74, 0x20, 0x3d, 0x20, 0x78, 0x20, 0x2d, 0x20, 0x73, 0x68, 0x69, - 0x66, 0x74, 0x3b, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, 0x74, 0x20, 0x3e, 0x3d, - 0x20, 0x30, 0x2e, 0x30, 0x20, 0x26, 0x26, 0x20, 0x74, 0x20, 0x3c, 0x3d, - 0x20, 0x31, 0x2e, 0x30, 0x20, 0x7b, 0x20, 0x28, 0x2a, 0x72, 0x6f, 0x6f, - 0x74, 0x73, 0x29, 0x5b, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x5d, 0x20, 0x3d, - 0x20, 0x74, 0x3b, 0x20, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x2b, 0x2b, 0x3b, - 0x20, 0x7d, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x7d, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x7d, 0x0d, 0x0a, 0x20, 0x20, - 0x20, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x63, 0x6f, 0x75, - 0x6e, 0x74, 0x3b, 0x0d, 0x0a, 0x7d, 0x0d, 0x0a, 0x0d, 0x0a, 0x2f, 0x2f, - 0x20, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x20, - 0x57, 0x69, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x20, 0x6e, 0x75, 0x6d, 0x62, - 0x65, 0x72, 0x20, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, - 0x69, 0x6f, 0x6e, 0x20, 0x66, 0x72, 0x6f, 0x6d, 0x20, 0x6f, 0x6e, 0x65, - 0x20, 0x63, 0x75, 0x62, 0x69, 0x63, 0x20, 0x73, 0x65, 0x67, 0x6d, 0x65, - 0x6e, 0x74, 0x20, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, - 0x2d, 0x0d, 0x0a, 0x66, 0x6e, 0x20, 0x72, 0x61, 0x79, 0x5f, 0x69, 0x6e, - 0x74, 0x65, 0x72, 0x73, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x5f, - 0x63, 0x75, 0x62, 0x69, 0x63, 0x28, 0x70, 0x3a, 0x20, 0x76, 0x65, 0x63, - 0x32, 0x66, 0x2c, 0x20, 0x73, 0x65, 0x67, 0x3a, 0x20, 0x53, 0x65, 0x67, - 0x6d, 0x65, 0x6e, 0x74, 0x29, 0x20, 0x2d, 0x3e, 0x20, 0x69, 0x33, 0x32, - 0x20, 0x7b, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x2f, 0x2f, 0x20, 0x57, - 0x65, 0x20, 0x63, 0x61, 0x73, 0x74, 0x20, 0x61, 0x20, 0x68, 0x6f, 0x72, - 0x69, 0x7a, 0x6f, 0x6e, 0x74, 0x61, 0x6c, 0x20, 0x72, 0x61, 0x79, 0x20, - 0x66, 0x72, 0x6f, 0x6d, 0x20, 0x70, 0x20, 0x74, 0x6f, 0x20, 0x2b, 0x78, - 0x3b, 0x20, 0x66, 0x69, 0x6e, 0x64, 0x20, 0x74, 0x20, 0x77, 0x68, 0x65, - 0x72, 0x65, 0x20, 0x79, 0x28, 0x74, 0x29, 0x20, 0x3d, 0x20, 0x70, 0x2e, - 0x79, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x65, 0x74, 0x20, 0x79, - 0x30, 0x20, 0x3d, 0x20, 0x73, 0x65, 0x67, 0x2e, 0x70, 0x30, 0x2e, 0x79, - 0x20, 0x2d, 0x20, 0x70, 0x2e, 0x79, 0x3b, 0x0d, 0x0a, 0x20, 0x20, 0x20, - 0x20, 0x6c, 0x65, 0x74, 0x20, 0x79, 0x31, 0x20, 0x3d, 0x20, 0x73, 0x65, - 0x67, 0x2e, 0x70, 0x31, 0x2e, 0x79, 0x20, 0x2d, 0x20, 0x70, 0x2e, 0x79, - 0x3b, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x65, 0x74, 0x20, 0x79, - 0x32, 0x20, 0x3d, 0x20, 0x73, 0x65, 0x67, 0x2e, 0x70, 0x32, 0x2e, 0x79, - 0x20, 0x2d, 0x20, 0x70, 0x2e, 0x79, 0x3b, 0x0d, 0x0a, 0x20, 0x20, 0x20, - 0x20, 0x6c, 0x65, 0x74, 0x20, 0x79, 0x33, 0x20, 0x3d, 0x20, 0x73, 0x65, - 0x67, 0x2e, 0x70, 0x33, 0x2e, 0x79, 0x20, 0x2d, 0x20, 0x70, 0x2e, 0x79, - 0x3b, 0x0d, 0x0a, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x2f, 0x2f, 0x20, - 0x79, 0x28, 0x74, 0x29, 0x20, 0x3d, 0x20, 0x28, 0x31, 0x2d, 0x74, 0x29, - 0x5e, 0x33, 0x2a, 0x79, 0x30, 0x20, 0x2b, 0x20, 0x33, 0x28, 0x31, 0x2d, - 0x74, 0x29, 0x5e, 0x32, 0x20, 0x74, 0x20, 0x2a, 0x20, 0x79, 0x31, 0x20, - 0x2b, 0x20, 0x33, 0x28, 0x31, 0x2d, 0x74, 0x29, 0x20, 0x74, 0x5e, 0x32, - 0x20, 0x2a, 0x20, 0x79, 0x32, 0x20, 0x2b, 0x20, 0x74, 0x5e, 0x33, 0x20, - 0x2a, 0x20, 0x79, 0x33, 0x20, 0x3d, 0x20, 0x30, 0x0d, 0x0a, 0x20, 0x20, - 0x20, 0x20, 0x2f, 0x2f, 0x20, 0x45, 0x78, 0x70, 0x61, 0x6e, 0x64, 0x20, - 0x70, 0x6f, 0x6c, 0x79, 0x6e, 0x6f, 0x6d, 0x69, 0x61, 0x6c, 0x3a, 0x20, - 0x63, 0x33, 0x20, 0x74, 0x5e, 0x33, 0x20, 0x2b, 0x20, 0x63, 0x32, 0x20, - 0x74, 0x5e, 0x32, 0x20, 0x2b, 0x20, 0x63, 0x31, 0x20, 0x74, 0x20, 0x2b, - 0x20, 0x63, 0x30, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x65, 0x74, - 0x20, 0x63, 0x30, 0x20, 0x3d, 0x20, 0x79, 0x30, 0x3b, 0x0d, 0x0a, 0x20, - 0x20, 0x20, 0x20, 0x6c, 0x65, 0x74, 0x20, 0x63, 0x31, 0x20, 0x3d, 0x20, - 0x33, 0x2e, 0x30, 0x20, 0x2a, 0x20, 0x28, 0x79, 0x31, 0x20, 0x2d, 0x20, - 0x79, 0x30, 0x29, 0x3b, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x65, - 0x74, 0x20, 0x63, 0x32, 0x20, 0x3d, 0x20, 0x33, 0x2e, 0x30, 0x20, 0x2a, - 0x20, 0x28, 0x79, 0x32, 0x20, 0x2d, 0x20, 0x32, 0x2e, 0x30, 0x20, 0x2a, - 0x20, 0x79, 0x31, 0x20, 0x2b, 0x20, 0x79, 0x30, 0x29, 0x3b, 0x0d, 0x0a, - 0x20, 0x20, 0x20, 0x20, 0x6c, 0x65, 0x74, 0x20, 0x63, 0x33, 0x20, 0x3d, - 0x20, 0x79, 0x33, 0x20, 0x2d, 0x20, 0x33, 0x2e, 0x30, 0x20, 0x2a, 0x20, - 0x79, 0x32, 0x20, 0x2b, 0x20, 0x33, 0x2e, 0x30, 0x20, 0x2a, 0x20, 0x79, - 0x31, 0x20, 0x2d, 0x20, 0x79, 0x30, 0x3b, 0x0d, 0x0a, 0x0d, 0x0a, 0x20, - 0x20, 0x20, 0x20, 0x76, 0x61, 0x72, 0x20, 0x72, 0x6f, 0x6f, 0x74, 0x73, - 0x3a, 0x20, 0x61, 0x72, 0x72, 0x61, 0x79, 0x3c, 0x66, 0x33, 0x32, 0x2c, - 0x20, 0x33, 0x3e, 0x3b, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x65, - 0x74, 0x20, 0x6e, 0x75, 0x6d, 0x20, 0x3d, 0x20, 0x73, 0x6f, 0x6c, 0x76, - 0x65, 0x5f, 0x63, 0x75, 0x62, 0x69, 0x63, 0x5f, 0x69, 0x6e, 0x5f, 0x30, - 0x31, 0x28, 0x63, 0x33, 0x2c, 0x20, 0x63, 0x32, 0x2c, 0x20, 0x63, 0x31, - 0x2c, 0x20, 0x63, 0x30, 0x2c, 0x20, 0x26, 0x72, 0x6f, 0x6f, 0x74, 0x73, - 0x29, 0x3b, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x76, 0x61, 0x72, 0x20, - 0x77, 0x69, 0x6e, 0x64, 0x20, 0x3d, 0x20, 0x30, 0x69, 0x3b, 0x0d, 0x0a, - 0x20, 0x20, 0x20, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x28, 0x76, 0x61, 0x72, - 0x20, 0x69, 0x20, 0x3d, 0x20, 0x30, 0x75, 0x3b, 0x20, 0x69, 0x20, 0x3c, - 0x20, 0x6e, 0x75, 0x6d, 0x3b, 0x20, 0x69, 0x2b, 0x2b, 0x29, 0x20, 0x7b, - 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x65, - 0x74, 0x20, 0x74, 0x20, 0x3d, 0x20, 0x72, 0x6f, 0x6f, 0x74, 0x73, 0x5b, - 0x69, 0x5d, 0x3b, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x6c, 0x65, 0x74, 0x20, 0x78, 0x20, 0x3d, 0x20, 0x65, 0x76, 0x61, - 0x6c, 0x5f, 0x63, 0x75, 0x62, 0x69, 0x63, 0x28, 0x74, 0x2c, 0x20, 0x73, - 0x65, 0x67, 0x2e, 0x70, 0x30, 0x2c, 0x20, 0x73, 0x65, 0x67, 0x2e, 0x70, - 0x31, 0x2c, 0x20, 0x73, 0x65, 0x67, 0x2e, 0x70, 0x32, 0x2c, 0x20, 0x73, - 0x65, 0x67, 0x2e, 0x70, 0x33, 0x29, 0x2e, 0x78, 0x3b, 0x0d, 0x0a, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, 0x78, 0x20, - 0x3e, 0x20, 0x70, 0x2e, 0x78, 0x20, 0x7b, 0x0d, 0x0a, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x65, 0x74, - 0x20, 0x64, 0x79, 0x20, 0x3d, 0x20, 0x65, 0x76, 0x61, 0x6c, 0x5f, 0x63, - 0x75, 0x62, 0x69, 0x63, 0x5f, 0x64, 0x65, 0x72, 0x69, 0x76, 0x61, 0x74, - 0x69, 0x76, 0x65, 0x28, 0x74, 0x2c, 0x20, 0x73, 0x65, 0x67, 0x2e, 0x70, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7d, 0x0d, 0x0a, 0x20, + 0x20, 0x20, 0x20, 0x7d, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, + 0x74, 0x75, 0x72, 0x6e, 0x20, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x3b, 0x0d, + 0x0a, 0x7d, 0x0d, 0x0a, 0x0d, 0x0a, 0x2f, 0x2f, 0x20, 0x2d, 0x2d, 0x2d, + 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x20, 0x57, 0x69, 0x6e, 0x64, + 0x69, 0x6e, 0x67, 0x20, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x20, 0x63, + 0x6f, 0x6e, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x20, + 0x66, 0x72, 0x6f, 0x6d, 0x20, 0x6f, 0x6e, 0x65, 0x20, 0x63, 0x75, 0x62, + 0x69, 0x63, 0x20, 0x73, 0x65, 0x67, 0x6d, 0x65, 0x6e, 0x74, 0x20, 0x2d, + 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0d, 0x0a, 0x66, + 0x6e, 0x20, 0x72, 0x61, 0x79, 0x5f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x73, + 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x5f, 0x63, 0x75, 0x62, 0x69, + 0x63, 0x28, 0x70, 0x3a, 0x20, 0x76, 0x65, 0x63, 0x32, 0x66, 0x2c, 0x20, + 0x73, 0x65, 0x67, 0x3a, 0x20, 0x53, 0x65, 0x67, 0x6d, 0x65, 0x6e, 0x74, + 0x29, 0x20, 0x2d, 0x3e, 0x20, 0x69, 0x33, 0x32, 0x20, 0x7b, 0x0d, 0x0a, + 0x20, 0x20, 0x20, 0x20, 0x2f, 0x2f, 0x20, 0x57, 0x65, 0x20, 0x63, 0x61, + 0x73, 0x74, 0x20, 0x61, 0x20, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x6f, 0x6e, + 0x74, 0x61, 0x6c, 0x20, 0x72, 0x61, 0x79, 0x20, 0x66, 0x72, 0x6f, 0x6d, + 0x20, 0x70, 0x20, 0x74, 0x6f, 0x20, 0x2b, 0x78, 0x3b, 0x20, 0x66, 0x69, + 0x6e, 0x64, 0x20, 0x74, 0x20, 0x77, 0x68, 0x65, 0x72, 0x65, 0x20, 0x79, + 0x28, 0x74, 0x29, 0x20, 0x3d, 0x20, 0x70, 0x2e, 0x79, 0x0d, 0x0a, 0x20, + 0x20, 0x20, 0x20, 0x6c, 0x65, 0x74, 0x20, 0x79, 0x30, 0x20, 0x3d, 0x20, + 0x73, 0x65, 0x67, 0x2e, 0x70, 0x30, 0x2e, 0x79, 0x20, 0x2d, 0x20, 0x70, + 0x2e, 0x79, 0x3b, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x65, 0x74, + 0x20, 0x79, 0x31, 0x20, 0x3d, 0x20, 0x73, 0x65, 0x67, 0x2e, 0x70, 0x31, + 0x2e, 0x79, 0x20, 0x2d, 0x20, 0x70, 0x2e, 0x79, 0x3b, 0x0d, 0x0a, 0x20, + 0x20, 0x20, 0x20, 0x6c, 0x65, 0x74, 0x20, 0x79, 0x32, 0x20, 0x3d, 0x20, + 0x73, 0x65, 0x67, 0x2e, 0x70, 0x32, 0x2e, 0x79, 0x20, 0x2d, 0x20, 0x70, + 0x2e, 0x79, 0x3b, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x65, 0x74, + 0x20, 0x79, 0x33, 0x20, 0x3d, 0x20, 0x73, 0x65, 0x67, 0x2e, 0x70, 0x33, + 0x2e, 0x79, 0x20, 0x2d, 0x20, 0x70, 0x2e, 0x79, 0x3b, 0x0d, 0x0a, 0x0d, + 0x0a, 0x20, 0x20, 0x20, 0x20, 0x2f, 0x2f, 0x20, 0x79, 0x28, 0x74, 0x29, + 0x20, 0x3d, 0x20, 0x28, 0x31, 0x2d, 0x74, 0x29, 0x5e, 0x33, 0x2a, 0x79, + 0x30, 0x20, 0x2b, 0x20, 0x33, 0x28, 0x31, 0x2d, 0x74, 0x29, 0x5e, 0x32, + 0x20, 0x74, 0x20, 0x2a, 0x20, 0x79, 0x31, 0x20, 0x2b, 0x20, 0x33, 0x28, + 0x31, 0x2d, 0x74, 0x29, 0x20, 0x74, 0x5e, 0x32, 0x20, 0x2a, 0x20, 0x79, + 0x32, 0x20, 0x2b, 0x20, 0x74, 0x5e, 0x33, 0x20, 0x2a, 0x20, 0x79, 0x33, + 0x20, 0x3d, 0x20, 0x30, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x2f, 0x2f, + 0x20, 0x45, 0x78, 0x70, 0x61, 0x6e, 0x64, 0x20, 0x70, 0x6f, 0x6c, 0x79, + 0x6e, 0x6f, 0x6d, 0x69, 0x61, 0x6c, 0x3a, 0x20, 0x63, 0x33, 0x20, 0x74, + 0x5e, 0x33, 0x20, 0x2b, 0x20, 0x63, 0x32, 0x20, 0x74, 0x5e, 0x32, 0x20, + 0x2b, 0x20, 0x63, 0x31, 0x20, 0x74, 0x20, 0x2b, 0x20, 0x63, 0x30, 0x0d, + 0x0a, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x65, 0x74, 0x20, 0x63, 0x30, 0x20, + 0x3d, 0x20, 0x79, 0x30, 0x3b, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x6c, + 0x65, 0x74, 0x20, 0x63, 0x31, 0x20, 0x3d, 0x20, 0x33, 0x2e, 0x30, 0x20, + 0x2a, 0x20, 0x28, 0x79, 0x31, 0x20, 0x2d, 0x20, 0x79, 0x30, 0x29, 0x3b, + 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x65, 0x74, 0x20, 0x63, 0x32, + 0x20, 0x3d, 0x20, 0x33, 0x2e, 0x30, 0x20, 0x2a, 0x20, 0x28, 0x79, 0x32, + 0x20, 0x2d, 0x20, 0x32, 0x2e, 0x30, 0x20, 0x2a, 0x20, 0x79, 0x31, 0x20, + 0x2b, 0x20, 0x79, 0x30, 0x29, 0x3b, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, + 0x6c, 0x65, 0x74, 0x20, 0x63, 0x33, 0x20, 0x3d, 0x20, 0x79, 0x33, 0x20, + 0x2d, 0x20, 0x33, 0x2e, 0x30, 0x20, 0x2a, 0x20, 0x79, 0x32, 0x20, 0x2b, + 0x20, 0x33, 0x2e, 0x30, 0x20, 0x2a, 0x20, 0x79, 0x31, 0x20, 0x2d, 0x20, + 0x79, 0x30, 0x3b, 0x0d, 0x0a, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x76, + 0x61, 0x72, 0x20, 0x72, 0x6f, 0x6f, 0x74, 0x73, 0x3a, 0x20, 0x61, 0x72, + 0x72, 0x61, 0x79, 0x3c, 0x66, 0x33, 0x32, 0x2c, 0x20, 0x33, 0x3e, 0x3b, + 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x65, 0x74, 0x20, 0x6e, 0x75, + 0x6d, 0x20, 0x3d, 0x20, 0x73, 0x6f, 0x6c, 0x76, 0x65, 0x5f, 0x63, 0x75, + 0x62, 0x69, 0x63, 0x5f, 0x69, 0x6e, 0x5f, 0x30, 0x31, 0x28, 0x63, 0x33, + 0x2c, 0x20, 0x63, 0x32, 0x2c, 0x20, 0x63, 0x31, 0x2c, 0x20, 0x63, 0x30, + 0x2c, 0x20, 0x26, 0x72, 0x6f, 0x6f, 0x74, 0x73, 0x29, 0x3b, 0x0d, 0x0a, + 0x20, 0x20, 0x20, 0x20, 0x76, 0x61, 0x72, 0x20, 0x77, 0x69, 0x6e, 0x64, + 0x20, 0x3d, 0x20, 0x30, 0x69, 0x3b, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, + 0x66, 0x6f, 0x72, 0x20, 0x28, 0x76, 0x61, 0x72, 0x20, 0x69, 0x20, 0x3d, + 0x20, 0x30, 0x75, 0x3b, 0x20, 0x69, 0x20, 0x3c, 0x20, 0x6e, 0x75, 0x6d, + 0x3b, 0x20, 0x69, 0x2b, 0x2b, 0x29, 0x20, 0x7b, 0x0d, 0x0a, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x65, 0x74, 0x20, 0x74, 0x20, + 0x3d, 0x20, 0x72, 0x6f, 0x6f, 0x74, 0x73, 0x5b, 0x69, 0x5d, 0x3b, 0x0d, + 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x65, 0x74, + 0x20, 0x78, 0x20, 0x3d, 0x20, 0x65, 0x76, 0x61, 0x6c, 0x5f, 0x63, 0x75, + 0x62, 0x69, 0x63, 0x28, 0x74, 0x2c, 0x20, 0x73, 0x65, 0x67, 0x2e, 0x70, 0x30, 0x2c, 0x20, 0x73, 0x65, 0x67, 0x2e, 0x70, 0x31, 0x2c, 0x20, 0x73, 0x65, 0x67, 0x2e, 0x70, 0x32, 0x2c, 0x20, 0x73, 0x65, 0x67, 0x2e, 0x70, - 0x33, 0x29, 0x2e, 0x79, 0x3b, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, 0x64, 0x79, - 0x20, 0x3e, 0x20, 0x30, 0x2e, 0x30, 0x20, 0x7b, 0x20, 0x77, 0x69, 0x6e, - 0x64, 0x20, 0x2b, 0x3d, 0x20, 0x31, 0x69, 0x3b, 0x20, 0x7d, 0x0d, 0x0a, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x65, 0x6c, 0x73, 0x65, 0x20, 0x69, 0x66, 0x20, 0x64, 0x79, 0x20, 0x3c, - 0x20, 0x30, 0x2e, 0x30, 0x20, 0x7b, 0x20, 0x77, 0x69, 0x6e, 0x64, 0x20, - 0x2d, 0x3d, 0x20, 0x31, 0x69, 0x3b, 0x20, 0x7d, 0x0d, 0x0a, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7d, 0x0d, 0x0a, 0x20, 0x20, 0x20, - 0x20, 0x7d, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x74, 0x75, - 0x72, 0x6e, 0x20, 0x77, 0x69, 0x6e, 0x64, 0x3b, 0x0d, 0x0a, 0x7d, 0x0d, - 0x0a, 0x0d, 0x0a, 0x2f, 0x2f, 0x20, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, - 0x2d, 0x2d, 0x2d, 0x2d, 0x20, 0x4d, 0x61, 0x69, 0x6e, 0x20, 0x63, 0x6f, - 0x6d, 0x70, 0x75, 0x74, 0x65, 0x20, 0x73, 0x68, 0x61, 0x64, 0x65, 0x72, - 0x20, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0d, - 0x0a, 0x40, 0x63, 0x6f, 0x6d, 0x70, 0x75, 0x74, 0x65, 0x20, 0x40, 0x77, - 0x6f, 0x72, 0x6b, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x5f, 0x73, 0x69, 0x7a, - 0x65, 0x28, 0x31, 0x2c, 0x20, 0x31, 0x29, 0x0d, 0x0a, 0x66, 0x6e, 0x20, - 0x6d, 0x61, 0x69, 0x6e, 0x28, 0x40, 0x62, 0x75, 0x69, 0x6c, 0x74, 0x69, - 0x6e, 0x28, 0x67, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x5f, 0x69, 0x6e, 0x76, - 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x29, 0x20, - 0x69, 0x64, 0x3a, 0x20, 0x76, 0x65, 0x63, 0x33, 0x3c, 0x75, 0x33, 0x32, - 0x3e, 0x29, 0x20, 0x7b, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x65, - 0x74, 0x20, 0x74, 0x69, 0x6c, 0x65, 0x5f, 0x64, 0x69, 0x6d, 0x20, 0x3d, - 0x20, 0x76, 0x65, 0x63, 0x32, 0x66, 0x28, 0x74, 0x69, 0x6c, 0x65, 0x5f, - 0x70, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x2e, 0x74, 0x69, 0x6c, 0x65, 0x5f, - 0x73, 0x69, 0x7a, 0x65, 0x29, 0x3b, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, - 0x69, 0x66, 0x20, 0x69, 0x64, 0x2e, 0x78, 0x20, 0x3e, 0x3d, 0x20, 0x75, - 0x33, 0x32, 0x28, 0x74, 0x69, 0x6c, 0x65, 0x5f, 0x64, 0x69, 0x6d, 0x2e, - 0x78, 0x29, 0x20, 0x7c, 0x7c, 0x20, 0x69, 0x64, 0x2e, 0x79, 0x20, 0x3e, - 0x3d, 0x20, 0x75, 0x33, 0x32, 0x28, 0x74, 0x69, 0x6c, 0x65, 0x5f, 0x64, - 0x69, 0x6d, 0x2e, 0x79, 0x29, 0x20, 0x7b, 0x0d, 0x0a, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x3b, - 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x7d, 0x0d, 0x0a, 0x0d, 0x0a, 0x20, - 0x20, 0x20, 0x20, 0x2f, 0x2f, 0x20, 0x50, 0x69, 0x78, 0x65, 0x6c, 0x20, - 0x63, 0x65, 0x6e, 0x74, 0x65, 0x72, 0x20, 0x55, 0x56, 0x2c, 0x20, 0x74, - 0x68, 0x65, 0x6e, 0x20, 0x6d, 0x61, 0x70, 0x20, 0x74, 0x6f, 0x20, 0x77, - 0x6f, 0x72, 0x6c, 0x64, 0x20, 0x73, 0x70, 0x61, 0x63, 0x65, 0x0d, 0x0a, + 0x33, 0x29, 0x2e, 0x78, 0x3b, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, 0x78, 0x20, 0x3e, 0x20, 0x70, 0x2e, + 0x78, 0x20, 0x7b, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x65, 0x74, 0x20, 0x64, 0x79, 0x20, + 0x3d, 0x20, 0x65, 0x76, 0x61, 0x6c, 0x5f, 0x63, 0x75, 0x62, 0x69, 0x63, + 0x5f, 0x64, 0x65, 0x72, 0x69, 0x76, 0x61, 0x74, 0x69, 0x76, 0x65, 0x28, + 0x74, 0x2c, 0x20, 0x73, 0x65, 0x67, 0x2e, 0x70, 0x30, 0x2c, 0x20, 0x73, + 0x65, 0x67, 0x2e, 0x70, 0x31, 0x2c, 0x20, 0x73, 0x65, 0x67, 0x2e, 0x70, + 0x32, 0x2c, 0x20, 0x73, 0x65, 0x67, 0x2e, 0x70, 0x33, 0x29, 0x2e, 0x79, + 0x3b, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, 0x64, 0x79, 0x20, 0x3e, 0x20, 0x30, + 0x2e, 0x30, 0x20, 0x7b, 0x20, 0x77, 0x69, 0x6e, 0x64, 0x20, 0x2b, 0x3d, + 0x20, 0x31, 0x69, 0x3b, 0x20, 0x7d, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x65, 0x6c, 0x73, 0x65, + 0x20, 0x69, 0x66, 0x20, 0x64, 0x79, 0x20, 0x3c, 0x20, 0x30, 0x2e, 0x30, + 0x20, 0x7b, 0x20, 0x77, 0x69, 0x6e, 0x64, 0x20, 0x2d, 0x3d, 0x20, 0x31, + 0x69, 0x3b, 0x20, 0x7d, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x7d, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x7d, 0x0d, 0x0a, + 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x77, + 0x69, 0x6e, 0x64, 0x3b, 0x0d, 0x0a, 0x7d, 0x0d, 0x0a, 0x0d, 0x0a, 0x2f, + 0x2f, 0x20, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, + 0x20, 0x4d, 0x61, 0x69, 0x6e, 0x20, 0x63, 0x6f, 0x6d, 0x70, 0x75, 0x74, + 0x65, 0x20, 0x73, 0x68, 0x61, 0x64, 0x65, 0x72, 0x20, 0x2d, 0x2d, 0x2d, + 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0d, 0x0a, 0x40, 0x63, 0x6f, + 0x6d, 0x70, 0x75, 0x74, 0x65, 0x20, 0x40, 0x77, 0x6f, 0x72, 0x6b, 0x67, + 0x72, 0x6f, 0x75, 0x70, 0x5f, 0x73, 0x69, 0x7a, 0x65, 0x28, 0x38, 0x2c, + 0x20, 0x38, 0x29, 0x0d, 0x0a, 0x66, 0x6e, 0x20, 0x6d, 0x61, 0x69, 0x6e, + 0x28, 0x40, 0x62, 0x75, 0x69, 0x6c, 0x74, 0x69, 0x6e, 0x28, 0x77, 0x6f, + 0x72, 0x6b, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x5f, 0x69, 0x64, 0x29, 0x20, + 0x77, 0x67, 0x3a, 0x20, 0x76, 0x65, 0x63, 0x33, 0x3c, 0x75, 0x33, 0x32, + 0x3e, 0x2c, 0x20, 0x2f, 0x2f, 0x20, 0x65, 0x61, 0x63, 0x68, 0x20, 0x77, + 0x6f, 0x72, 0x6b, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x20, 0x69, 0x73, 0x20, + 0x61, 0x20, 0x74, 0x69, 0x6c, 0x65, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x40, 0x62, 0x75, 0x69, 0x6c, 0x74, 0x69, 0x6e, + 0x28, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x5f, 0x69, 0x6e, 0x76, 0x6f, 0x63, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x29, 0x20, 0x6c, 0x6f, + 0x63, 0x61, 0x6c, 0x3a, 0x20, 0x76, 0x65, 0x63, 0x33, 0x3c, 0x75, 0x33, + 0x32, 0x3e, 0x29, 0x20, 0x2f, 0x2f, 0x20, 0x65, 0x61, 0x63, 0x68, 0x20, + 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x69, 0x6e, 0x76, 0x6f, 0x63, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x69, 0x73, 0x20, 0x61, 0x20, 0x70, 0x69, + 0x78, 0x65, 0x6c, 0x0d, 0x0a, 0x7b, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, + 0x6c, 0x65, 0x74, 0x20, 0x74, 0x69, 0x6c, 0x65, 0x5f, 0x69, 0x64, 0x78, + 0x20, 0x3d, 0x20, 0x77, 0x67, 0x2e, 0x78, 0x20, 0x2f, 0x20, 0x31, 0x36, + 0x75, 0x3b, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x65, 0x74, 0x20, + 0x74, 0x69, 0x6c, 0x65, 0x20, 0x3d, 0x20, 0x74, 0x69, 0x6c, 0x65, 0x73, + 0x5b, 0x74, 0x69, 0x6c, 0x65, 0x5f, 0x69, 0x64, 0x78, 0x5d, 0x3b, 0x0d, + 0x0a, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x65, 0x74, 0x20, 0x70, + 0x78, 0x20, 0x3d, 0x20, 0x28, 0x77, 0x67, 0x2e, 0x78, 0x20, 0x25, 0x20, + 0x31, 0x36, 0x75, 0x29, 0x20, 0x2a, 0x20, 0x38, 0x75, 0x20, 0x2b, 0x20, + 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x2e, 0x78, 0x3b, 0x0d, 0x0a, 0x20, 0x20, + 0x20, 0x20, 0x6c, 0x65, 0x74, 0x20, 0x70, 0x79, 0x20, 0x3d, 0x20, 0x77, + 0x67, 0x2e, 0x79, 0x20, 0x2a, 0x20, 0x38, 0x75, 0x20, 0x2b, 0x20, 0x6c, + 0x6f, 0x63, 0x61, 0x6c, 0x2e, 0x79, 0x3b, 0x0d, 0x0a, 0x0d, 0x0a, 0x20, + 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, 0x28, 0x70, 0x78, 0x20, 0x3e, 0x3d, + 0x20, 0x54, 0x49, 0x4c, 0x45, 0x5f, 0x53, 0x49, 0x5a, 0x45, 0x20, 0x7c, + 0x7c, 0x20, 0x70, 0x79, 0x20, 0x3e, 0x3d, 0x20, 0x54, 0x49, 0x4c, 0x45, + 0x5f, 0x53, 0x49, 0x5a, 0x45, 0x29, 0x20, 0x7b, 0x0d, 0x0a, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, + 0x3b, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x7d, 0x0d, 0x0a, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x65, 0x74, 0x20, 0x75, 0x76, 0x20, 0x3d, - 0x20, 0x28, 0x76, 0x65, 0x63, 0x32, 0x66, 0x28, 0x69, 0x64, 0x2e, 0x78, - 0x79, 0x29, 0x20, 0x2b, 0x20, 0x30, 0x2e, 0x35, 0x29, 0x20, 0x2f, 0x20, - 0x74, 0x69, 0x6c, 0x65, 0x5f, 0x64, 0x69, 0x6d, 0x3b, 0x0d, 0x0a, 0x20, - 0x20, 0x20, 0x20, 0x6c, 0x65, 0x74, 0x20, 0x77, 0x6f, 0x72, 0x6c, 0x64, - 0x20, 0x3d, 0x20, 0x6d, 0x69, 0x78, 0x28, 0x74, 0x69, 0x6c, 0x65, 0x5f, - 0x70, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x2e, 0x77, 0x6f, 0x72, 0x6c, 0x64, - 0x5f, 0x6d, 0x69, 0x6e, 0x2c, 0x20, 0x74, 0x69, 0x6c, 0x65, 0x5f, 0x70, - 0x61, 0x72, 0x61, 0x6d, 0x73, 0x2e, 0x77, 0x6f, 0x72, 0x6c, 0x64, 0x5f, - 0x6d, 0x61, 0x78, 0x2c, 0x20, 0x75, 0x76, 0x29, 0x3b, 0x0d, 0x0a, 0x0d, - 0x0a, 0x20, 0x20, 0x20, 0x20, 0x76, 0x61, 0x72, 0x20, 0x6d, 0x69, 0x6e, - 0x44, 0x69, 0x73, 0x74, 0x3a, 0x20, 0x66, 0x33, 0x32, 0x20, 0x3d, 0x20, - 0x31, 0x65, 0x32, 0x30, 0x3b, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x76, - 0x61, 0x72, 0x20, 0x77, 0x69, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x3a, 0x20, - 0x69, 0x33, 0x32, 0x20, 0x3d, 0x20, 0x30, 0x3b, 0x0d, 0x0a, 0x0d, 0x0a, - 0x20, 0x20, 0x20, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x28, 0x76, 0x61, 0x72, - 0x20, 0x73, 0x20, 0x3d, 0x20, 0x30, 0x75, 0x3b, 0x20, 0x73, 0x20, 0x3c, - 0x20, 0x61, 0x72, 0x72, 0x61, 0x79, 0x4c, 0x65, 0x6e, 0x67, 0x74, 0x68, - 0x28, 0x26, 0x73, 0x68, 0x61, 0x70, 0x65, 0x73, 0x29, 0x3b, 0x20, 0x73, - 0x2b, 0x2b, 0x29, 0x20, 0x7b, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x6c, 0x65, 0x74, 0x20, 0x73, 0x68, 0x61, 0x70, 0x65, - 0x20, 0x3d, 0x20, 0x73, 0x68, 0x61, 0x70, 0x65, 0x73, 0x5b, 0x73, 0x5d, - 0x3b, 0x0d, 0x0a, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x2f, 0x2f, 0x20, 0x51, 0x75, 0x69, 0x63, 0x6b, 0x20, 0x62, 0x62, - 0x6f, 0x78, 0x20, 0x63, 0x75, 0x6c, 0x6c, 0x69, 0x6e, 0x67, 0x20, 0x69, - 0x6e, 0x20, 0x77, 0x6f, 0x72, 0x6c, 0x64, 0x20, 0x73, 0x70, 0x61, 0x63, - 0x65, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x6c, - 0x65, 0x74, 0x20, 0x62, 0x62, 0x6f, 0x78, 0x5f, 0x6d, 0x69, 0x6e, 0x20, - 0x3d, 0x20, 0x73, 0x68, 0x61, 0x70, 0x65, 0x2e, 0x62, 0x62, 0x6f, 0x78, - 0x5f, 0x6d, 0x69, 0x6e, 0x3b, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x6c, 0x65, 0x74, 0x20, 0x62, 0x62, 0x6f, 0x78, 0x5f, - 0x6d, 0x61, 0x78, 0x20, 0x3d, 0x20, 0x73, 0x68, 0x61, 0x70, 0x65, 0x2e, - 0x62, 0x62, 0x6f, 0x78, 0x5f, 0x6d, 0x61, 0x78, 0x3b, 0x0d, 0x0a, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x65, 0x74, 0x20, 0x64, - 0x78, 0x20, 0x3d, 0x20, 0x6d, 0x61, 0x78, 0x28, 0x62, 0x62, 0x6f, 0x78, - 0x5f, 0x6d, 0x69, 0x6e, 0x2e, 0x78, 0x20, 0x2d, 0x20, 0x77, 0x6f, 0x72, - 0x6c, 0x64, 0x2e, 0x78, 0x2c, 0x20, 0x6d, 0x61, 0x78, 0x28, 0x30, 0x2e, - 0x30, 0x2c, 0x20, 0x77, 0x6f, 0x72, 0x6c, 0x64, 0x2e, 0x78, 0x20, 0x2d, - 0x20, 0x62, 0x62, 0x6f, 0x78, 0x5f, 0x6d, 0x61, 0x78, 0x2e, 0x78, 0x29, - 0x29, 0x3b, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x6c, 0x65, 0x74, 0x20, 0x64, 0x79, 0x20, 0x3d, 0x20, 0x6d, 0x61, 0x78, - 0x28, 0x62, 0x62, 0x6f, 0x78, 0x5f, 0x6d, 0x69, 0x6e, 0x2e, 0x79, 0x20, - 0x2d, 0x20, 0x77, 0x6f, 0x72, 0x6c, 0x64, 0x2e, 0x79, 0x2c, 0x20, 0x6d, - 0x61, 0x78, 0x28, 0x30, 0x2e, 0x30, 0x2c, 0x20, 0x77, 0x6f, 0x72, 0x6c, - 0x64, 0x2e, 0x79, 0x20, 0x2d, 0x20, 0x62, 0x62, 0x6f, 0x78, 0x5f, 0x6d, - 0x61, 0x78, 0x2e, 0x79, 0x29, 0x29, 0x3b, 0x0d, 0x0a, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x65, 0x74, 0x20, 0x64, 0x69, 0x73, - 0x74, 0x5f, 0x74, 0x6f, 0x5f, 0x62, 0x6f, 0x78, 0x20, 0x3d, 0x20, 0x73, - 0x71, 0x72, 0x74, 0x28, 0x64, 0x78, 0x20, 0x2a, 0x20, 0x64, 0x78, 0x20, - 0x2b, 0x20, 0x64, 0x79, 0x20, 0x2a, 0x20, 0x64, 0x79, 0x29, 0x3b, 0x0d, - 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, - 0x64, 0x69, 0x73, 0x74, 0x5f, 0x74, 0x6f, 0x5f, 0x62, 0x6f, 0x78, 0x20, - 0x3e, 0x3d, 0x20, 0x6d, 0x69, 0x6e, 0x44, 0x69, 0x73, 0x74, 0x20, 0x7b, + 0x20, 0x28, 0x76, 0x65, 0x63, 0x32, 0x66, 0x28, 0x66, 0x33, 0x32, 0x28, + 0x70, 0x78, 0x29, 0x2c, 0x20, 0x66, 0x33, 0x32, 0x28, 0x70, 0x79, 0x29, + 0x29, 0x20, 0x2b, 0x20, 0x30, 0x2e, 0x35, 0x29, 0x20, 0x2f, 0x20, 0x66, + 0x33, 0x32, 0x28, 0x54, 0x49, 0x4c, 0x45, 0x5f, 0x53, 0x49, 0x5a, 0x45, + 0x29, 0x3b, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x65, 0x74, 0x20, + 0x77, 0x6f, 0x72, 0x6c, 0x64, 0x20, 0x3d, 0x20, 0x6d, 0x69, 0x78, 0x28, + 0x74, 0x69, 0x6c, 0x65, 0x2e, 0x77, 0x6f, 0x72, 0x6c, 0x64, 0x5f, 0x6d, + 0x69, 0x6e, 0x2c, 0x20, 0x74, 0x69, 0x6c, 0x65, 0x2e, 0x77, 0x6f, 0x72, + 0x6c, 0x64, 0x5f, 0x6d, 0x61, 0x78, 0x2c, 0x20, 0x75, 0x76, 0x29, 0x3b, + 0x0d, 0x0a, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x76, 0x61, 0x72, 0x20, + 0x6d, 0x69, 0x6e, 0x44, 0x69, 0x73, 0x74, 0x3a, 0x20, 0x66, 0x33, 0x32, + 0x20, 0x3d, 0x20, 0x31, 0x65, 0x32, 0x30, 0x3b, 0x0d, 0x0a, 0x20, 0x20, + 0x20, 0x20, 0x76, 0x61, 0x72, 0x20, 0x73, 0x64, 0x66, 0x3a, 0x20, 0x66, + 0x33, 0x32, 0x20, 0x3d, 0x20, 0x31, 0x65, 0x32, 0x30, 0x3b, 0x0d, 0x0a, + 0x20, 0x20, 0x20, 0x20, 0x76, 0x61, 0x72, 0x20, 0x77, 0x69, 0x6e, 0x64, + 0x69, 0x6e, 0x67, 0x3a, 0x20, 0x69, 0x33, 0x32, 0x20, 0x3d, 0x20, 0x30, + 0x3b, 0x0d, 0x0a, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x66, 0x6f, 0x72, + 0x20, 0x28, 0x76, 0x61, 0x72, 0x20, 0x73, 0x20, 0x3d, 0x20, 0x30, 0x75, + 0x3b, 0x20, 0x73, 0x20, 0x3c, 0x20, 0x74, 0x69, 0x6c, 0x65, 0x2e, 0x63, + 0x6f, 0x75, 0x6e, 0x74, 0x3b, 0x20, 0x73, 0x2b, 0x2b, 0x29, 0x20, 0x7b, + 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x2f, 0x2f, + 0x20, 0x55, 0x73, 0x65, 0x20, 0x61, 0x20, 0x70, 0x72, 0x65, 0x2d, 0x63, + 0x75, 0x6c, 0x6c, 0x65, 0x64, 0x20, 0x73, 0x68, 0x61, 0x70, 0x65, 0x20, + 0x72, 0x61, 0x6e, 0x67, 0x65, 0x20, 0x70, 0x65, 0x72, 0x20, 0x74, 0x69, + 0x6c, 0x65, 0x20, 0x74, 0x6f, 0x20, 0x72, 0x65, 0x64, 0x75, 0x63, 0x65, + 0x20, 0x74, 0x68, 0x65, 0x20, 0x70, 0x65, 0x72, 0x2d, 0x70, 0x69, 0x78, + 0x65, 0x6c, 0x20, 0x70, 0x72, 0x6f, 0x63, 0x65, 0x73, 0x73, 0x69, 0x6e, + 0x67, 0x20, 0x74, 0x69, 0x6d, 0x65, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x6c, 0x65, 0x74, 0x20, 0x69, 0x6e, 0x64, 0x65, + 0x78, 0x20, 0x3d, 0x20, 0x69, 0x6e, 0x64, 0x69, 0x63, 0x65, 0x73, 0x5b, + 0x74, 0x69, 0x6c, 0x65, 0x2e, 0x6f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x20, + 0x2b, 0x20, 0x73, 0x5d, 0x3b, 0x0d, 0x0a, 0x0d, 0x0a, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x2f, 0x2f, 0x20, 0x49, 0x66, 0x20, 0x74, + 0x68, 0x65, 0x20, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x20, 0x69, 0x73, 0x20, + 0x6c, 0x6f, 0x77, 0x65, 0x72, 0x20, 0x74, 0x68, 0x61, 0x6e, 0x20, 0x74, + 0x68, 0x65, 0x20, 0x63, 0x69, 0x72, 0x63, 0x6c, 0x65, 0x20, 0x63, 0x6f, + 0x75, 0x6e, 0x74, 0x2c, 0x20, 0x69, 0x74, 0x20, 0x6d, 0x65, 0x61, 0x6e, + 0x20, 0x77, 0x65, 0x20, 0x61, 0x72, 0x65, 0x20, 0x70, 0x72, 0x6f, 0x63, + 0x65, 0x73, 0x73, 0x69, 0x6e, 0x67, 0x20, 0x63, 0x69, 0x72, 0x63, 0x6c, + 0x65, 0x73, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x69, 0x66, 0x28, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x20, 0x3c, 0x20, 0x74, + 0x69, 0x6c, 0x65, 0x2e, 0x63, 0x69, 0x72, 0x63, 0x6c, 0x65, 0x5f, 0x63, + 0x6f, 0x75, 0x6e, 0x74, 0x29, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x7b, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x65, 0x74, 0x20, 0x63, 0x20, + 0x3d, 0x20, 0x63, 0x69, 0x72, 0x63, 0x6c, 0x65, 0x73, 0x5b, 0x69, 0x6e, + 0x64, 0x65, 0x78, 0x5d, 0x3b, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x73, 0x64, 0x66, 0x20, 0x3d, + 0x20, 0x6d, 0x69, 0x6e, 0x28, 0x73, 0x64, 0x66, 0x2c, 0x20, 0x6c, 0x65, + 0x6e, 0x67, 0x74, 0x68, 0x28, 0x77, 0x6f, 0x72, 0x6c, 0x64, 0x20, 0x2d, + 0x20, 0x63, 0x2e, 0x63, 0x65, 0x6e, 0x74, 0x65, 0x72, 0x29, 0x20, 0x2d, + 0x20, 0x63, 0x2e, 0x72, 0x61, 0x64, 0x69, 0x75, 0x73, 0x29, 0x3b, 0x0d, + 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7d, 0x0d, 0x0a, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x65, 0x6c, 0x73, 0x65, + 0x20, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7b, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x63, 0x6f, 0x6e, 0x74, 0x69, 0x6e, 0x75, 0x65, 0x3b, 0x20, - 0x20, 0x20, 0x2f, 0x2f, 0x20, 0x54, 0x68, 0x69, 0x73, 0x20, 0x73, 0x68, - 0x61, 0x70, 0x65, 0x20, 0x63, 0x61, 0x6e, 0x6e, 0x6f, 0x74, 0x20, 0x69, - 0x6d, 0x70, 0x72, 0x6f, 0x76, 0x65, 0x20, 0x74, 0x68, 0x65, 0x20, 0x64, - 0x69, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x0d, 0x0a, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x6c, 0x65, 0x74, 0x20, 0x73, 0x68, 0x61, 0x70, 0x65, 0x20, + 0x3d, 0x20, 0x73, 0x68, 0x61, 0x70, 0x65, 0x73, 0x5b, 0x69, 0x6e, 0x64, + 0x65, 0x78, 0x5d, 0x3b, 0x0d, 0x0a, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x2f, 0x2a, 0x6c, 0x65, + 0x74, 0x20, 0x62, 0x62, 0x6f, 0x78, 0x5f, 0x6d, 0x69, 0x6e, 0x20, 0x3d, + 0x20, 0x73, 0x68, 0x61, 0x70, 0x65, 0x2e, 0x62, 0x62, 0x6f, 0x78, 0x5f, + 0x6d, 0x69, 0x6e, 0x3b, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x65, 0x74, 0x20, 0x62, 0x62, + 0x6f, 0x78, 0x5f, 0x6d, 0x61, 0x78, 0x20, 0x3d, 0x20, 0x73, 0x68, 0x61, + 0x70, 0x65, 0x2e, 0x62, 0x62, 0x6f, 0x78, 0x5f, 0x6d, 0x61, 0x78, 0x3b, + 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x6c, 0x65, 0x74, 0x20, 0x64, 0x78, 0x20, 0x3d, 0x20, 0x6d, + 0x61, 0x78, 0x28, 0x62, 0x62, 0x6f, 0x78, 0x5f, 0x6d, 0x69, 0x6e, 0x2e, + 0x78, 0x20, 0x2d, 0x20, 0x77, 0x6f, 0x72, 0x6c, 0x64, 0x2e, 0x78, 0x2c, + 0x20, 0x6d, 0x61, 0x78, 0x28, 0x30, 0x2e, 0x30, 0x2c, 0x20, 0x77, 0x6f, + 0x72, 0x6c, 0x64, 0x2e, 0x78, 0x20, 0x2d, 0x20, 0x62, 0x62, 0x6f, 0x78, + 0x5f, 0x6d, 0x61, 0x78, 0x2e, 0x78, 0x29, 0x29, 0x3b, 0x0d, 0x0a, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x6c, + 0x65, 0x74, 0x20, 0x64, 0x79, 0x20, 0x3d, 0x20, 0x6d, 0x61, 0x78, 0x28, + 0x62, 0x62, 0x6f, 0x78, 0x5f, 0x6d, 0x69, 0x6e, 0x2e, 0x79, 0x20, 0x2d, + 0x20, 0x77, 0x6f, 0x72, 0x6c, 0x64, 0x2e, 0x79, 0x2c, 0x20, 0x6d, 0x61, + 0x78, 0x28, 0x30, 0x2e, 0x30, 0x2c, 0x20, 0x77, 0x6f, 0x72, 0x6c, 0x64, + 0x2e, 0x79, 0x20, 0x2d, 0x20, 0x62, 0x62, 0x6f, 0x78, 0x5f, 0x6d, 0x61, + 0x78, 0x2e, 0x79, 0x29, 0x29, 0x3b, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x65, 0x74, 0x20, + 0x64, 0x69, 0x73, 0x74, 0x5f, 0x74, 0x6f, 0x5f, 0x62, 0x6f, 0x78, 0x20, + 0x3d, 0x20, 0x73, 0x71, 0x72, 0x74, 0x28, 0x64, 0x78, 0x20, 0x2a, 0x20, + 0x64, 0x78, 0x20, 0x2b, 0x20, 0x64, 0x79, 0x20, 0x2a, 0x20, 0x64, 0x79, + 0x29, 0x3b, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, 0x64, 0x69, 0x73, 0x74, 0x5f, + 0x74, 0x6f, 0x5f, 0x62, 0x6f, 0x78, 0x20, 0x3e, 0x3d, 0x20, 0x6d, 0x69, + 0x6e, 0x44, 0x69, 0x73, 0x74, 0x20, 0x7b, 0x0d, 0x0a, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x63, 0x6f, 0x6e, 0x74, 0x69, 0x6e, 0x75, 0x65, 0x3b, 0x0d, 0x0a, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x7d, 0x2a, 0x2f, 0x0d, 0x0a, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x2f, 0x2f, 0x20, 0x50, 0x72, + 0x6f, 0x63, 0x65, 0x73, 0x73, 0x20, 0x61, 0x6c, 0x6c, 0x20, 0x73, 0x65, + 0x67, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68, + 0x65, 0x20, 0x73, 0x68, 0x61, 0x70, 0x65, 0x0d, 0x0a, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x66, 0x6f, 0x72, + 0x20, 0x28, 0x76, 0x61, 0x72, 0x20, 0x69, 0x20, 0x3d, 0x20, 0x73, 0x68, + 0x61, 0x70, 0x65, 0x2e, 0x73, 0x74, 0x61, 0x72, 0x74, 0x5f, 0x73, 0x65, + 0x67, 0x6d, 0x65, 0x6e, 0x74, 0x3b, 0x20, 0x69, 0x20, 0x3c, 0x20, 0x73, + 0x68, 0x61, 0x70, 0x65, 0x2e, 0x73, 0x74, 0x61, 0x72, 0x74, 0x5f, 0x73, + 0x65, 0x67, 0x6d, 0x65, 0x6e, 0x74, 0x20, 0x2b, 0x20, 0x73, 0x68, 0x61, + 0x70, 0x65, 0x2e, 0x73, 0x65, 0x67, 0x6d, 0x65, 0x6e, 0x74, 0x5f, 0x63, + 0x6f, 0x75, 0x6e, 0x74, 0x3b, 0x20, 0x69, 0x2b, 0x2b, 0x29, 0x20, 0x7b, + 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x65, 0x74, 0x20, 0x73, 0x65, + 0x67, 0x20, 0x3d, 0x20, 0x73, 0x65, 0x67, 0x6d, 0x65, 0x6e, 0x74, 0x73, + 0x5b, 0x69, 0x5d, 0x3b, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x65, + 0x74, 0x20, 0x64, 0x20, 0x3d, 0x20, 0x64, 0x69, 0x73, 0x74, 0x61, 0x6e, + 0x63, 0x65, 0x5f, 0x74, 0x6f, 0x5f, 0x63, 0x75, 0x62, 0x69, 0x63, 0x28, + 0x77, 0x6f, 0x72, 0x6c, 0x64, 0x2c, 0x20, 0x73, 0x65, 0x67, 0x29, 0x3b, + 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x6d, 0x69, 0x6e, 0x44, 0x69, 0x73, + 0x74, 0x20, 0x3d, 0x20, 0x6d, 0x69, 0x6e, 0x28, 0x6d, 0x69, 0x6e, 0x44, + 0x69, 0x73, 0x74, 0x2c, 0x20, 0x64, 0x29, 0x3b, 0x0d, 0x0a, 0x0d, 0x0a, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x77, 0x69, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x20, + 0x2b, 0x3d, 0x20, 0x72, 0x61, 0x79, 0x5f, 0x69, 0x6e, 0x74, 0x65, 0x72, + 0x73, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x5f, 0x63, 0x75, 0x62, + 0x69, 0x63, 0x28, 0x77, 0x6f, 0x72, 0x6c, 0x64, 0x2c, 0x20, 0x73, 0x65, + 0x67, 0x29, 0x3b, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7d, 0x0d, 0x0a, 0x0d, 0x0a, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x2f, 0x2f, 0x20, 0x50, 0x72, 0x6f, - 0x63, 0x65, 0x73, 0x73, 0x20, 0x61, 0x6c, 0x6c, 0x20, 0x73, 0x65, 0x67, - 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68, 0x65, - 0x20, 0x73, 0x68, 0x61, 0x70, 0x65, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x28, 0x76, 0x61, 0x72, - 0x20, 0x69, 0x20, 0x3d, 0x20, 0x73, 0x68, 0x61, 0x70, 0x65, 0x2e, 0x73, - 0x74, 0x61, 0x72, 0x74, 0x5f, 0x73, 0x65, 0x67, 0x6d, 0x65, 0x6e, 0x74, - 0x3b, 0x20, 0x69, 0x20, 0x3c, 0x20, 0x73, 0x68, 0x61, 0x70, 0x65, 0x2e, - 0x73, 0x74, 0x61, 0x72, 0x74, 0x5f, 0x73, 0x65, 0x67, 0x6d, 0x65, 0x6e, - 0x74, 0x20, 0x2b, 0x20, 0x73, 0x68, 0x61, 0x70, 0x65, 0x2e, 0x73, 0x65, - 0x67, 0x6d, 0x65, 0x6e, 0x74, 0x5f, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x3b, - 0x20, 0x69, 0x2b, 0x2b, 0x29, 0x20, 0x7b, 0x0d, 0x0a, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x65, 0x74, - 0x20, 0x73, 0x65, 0x67, 0x20, 0x3d, 0x20, 0x73, 0x65, 0x67, 0x6d, 0x65, - 0x6e, 0x74, 0x73, 0x5b, 0x69, 0x5d, 0x3b, 0x0d, 0x0a, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x65, 0x74, - 0x20, 0x64, 0x20, 0x3d, 0x20, 0x64, 0x69, 0x73, 0x74, 0x61, 0x6e, 0x63, - 0x65, 0x5f, 0x74, 0x6f, 0x5f, 0x63, 0x75, 0x62, 0x69, 0x63, 0x28, 0x77, - 0x6f, 0x72, 0x6c, 0x64, 0x2c, 0x20, 0x73, 0x65, 0x67, 0x29, 0x3b, 0x0d, - 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x6d, 0x69, 0x6e, 0x44, 0x69, 0x73, 0x74, 0x20, 0x3d, 0x20, 0x6d, - 0x69, 0x6e, 0x28, 0x6d, 0x69, 0x6e, 0x44, 0x69, 0x73, 0x74, 0x2c, 0x20, - 0x64, 0x29, 0x3b, 0x0d, 0x0a, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x77, 0x69, 0x6e, 0x64, 0x69, - 0x6e, 0x67, 0x20, 0x2b, 0x3d, 0x20, 0x72, 0x61, 0x79, 0x5f, 0x69, 0x6e, - 0x74, 0x65, 0x72, 0x73, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x5f, - 0x63, 0x75, 0x62, 0x69, 0x63, 0x28, 0x77, 0x6f, 0x72, 0x6c, 0x64, 0x2c, - 0x20, 0x73, 0x65, 0x67, 0x29, 0x3b, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x7d, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x7d, - 0x0d, 0x0a, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x65, 0x74, 0x20, - 0x73, 0x69, 0x67, 0x6e, 0x20, 0x3d, 0x20, 0x73, 0x65, 0x6c, 0x65, 0x63, - 0x74, 0x28, 0x31, 0x2e, 0x30, 0x2c, 0x20, 0x2d, 0x31, 0x2e, 0x30, 0x2c, - 0x20, 0x77, 0x69, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x20, 0x21, 0x3d, 0x20, - 0x30, 0x69, 0x29, 0x3b, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x65, - 0x74, 0x20, 0x73, 0x64, 0x66, 0x20, 0x3d, 0x20, 0x73, 0x69, 0x67, 0x6e, - 0x20, 0x2a, 0x20, 0x6d, 0x69, 0x6e, 0x44, 0x69, 0x73, 0x74, 0x3b, 0x0d, - 0x0a, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x74, 0x65, 0x78, 0x74, 0x75, - 0x72, 0x65, 0x53, 0x74, 0x6f, 0x72, 0x65, 0x28, 0x73, 0x64, 0x66, 0x5f, - 0x62, 0x75, 0x66, 0x66, 0x65, 0x72, 0x2c, 0x20, 0x69, 0x64, 0x2c, 0x20, - 0x75, 0x6e, 0x69, 0x66, 0x6f, 0x72, 0x6d, 0x73, 0x2e, 0x62, 0x75, 0x66, - 0x66, 0x65, 0x72, 0x5f, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x2c, 0x20, 0x76, - 0x65, 0x63, 0x34, 0x66, 0x28, 0x73, 0x64, 0x66, 0x2c, 0x20, 0x30, 0x2e, - 0x30, 0x2c, 0x20, 0x30, 0x2e, 0x30, 0x2c, 0x20, 0x31, 0x2e, 0x30, 0x29, - 0x29, 0x3b, 0x0d, 0x0a, 0x7d + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x65, + 0x74, 0x20, 0x73, 0x69, 0x67, 0x6e, 0x20, 0x3d, 0x20, 0x73, 0x65, 0x6c, + 0x65, 0x63, 0x74, 0x28, 0x31, 0x2e, 0x30, 0x2c, 0x20, 0x2d, 0x31, 0x2e, + 0x30, 0x2c, 0x20, 0x77, 0x69, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x20, 0x21, + 0x3d, 0x20, 0x30, 0x69, 0x29, 0x3b, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x73, 0x64, 0x66, 0x20, + 0x3d, 0x20, 0x6d, 0x69, 0x6e, 0x28, 0x73, 0x64, 0x66, 0x2c, 0x20, 0x73, + 0x69, 0x67, 0x6e, 0x20, 0x2a, 0x20, 0x6d, 0x69, 0x6e, 0x44, 0x69, 0x73, + 0x74, 0x29, 0x3b, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x7d, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x7d, 0x0d, 0x0a, 0x0d, + 0x0a, 0x20, 0x20, 0x20, 0x20, 0x74, 0x65, 0x78, 0x74, 0x75, 0x72, 0x65, + 0x53, 0x74, 0x6f, 0x72, 0x65, 0x28, 0x73, 0x64, 0x66, 0x5f, 0x62, 0x75, + 0x66, 0x66, 0x65, 0x72, 0x2c, 0x20, 0x76, 0x65, 0x63, 0x32, 0x28, 0x75, + 0x33, 0x32, 0x28, 0x77, 0x6f, 0x72, 0x6c, 0x64, 0x2e, 0x78, 0x29, 0x2c, + 0x20, 0x75, 0x33, 0x32, 0x28, 0x77, 0x6f, 0x72, 0x6c, 0x64, 0x2e, 0x79, + 0x29, 0x29, 0x2c, 0x20, 0x76, 0x65, 0x63, 0x34, 0x66, 0x28, 0x73, 0x64, + 0x66, 0x2c, 0x20, 0x30, 0x2e, 0x30, 0x2c, 0x20, 0x30, 0x2e, 0x30, 0x2c, + 0x20, 0x31, 0x2e, 0x30, 0x29, 0x29, 0x3b, 0x0d, 0x0a, 0x7d }; -unsigned int src_shaders_compute_wgsl_len = 7493; +unsigned int src_shaders_compute_wgsl_len = 8194; diff --git a/src/generated/display.h b/src/generated/display.h index 7a66b30..71e39b6 100644 --- a/src/generated/display.h +++ b/src/generated/display.h @@ -1,55 +1,59 @@ unsigned char src_shaders_display_wgsl[] = { 0x73, 0x74, 0x72, 0x75, 0x63, 0x74, 0x20, 0x55, 0x6e, 0x69, 0x66, 0x6f, - 0x72, 0x6d, 0x73, 0x20, 0x7b, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x70, - 0x61, 0x6e, 0x3a, 0x20, 0x76, 0x65, 0x63, 0x32, 0x66, 0x2c, 0x0d, 0x0a, - 0x20, 0x20, 0x20, 0x20, 0x7a, 0x6f, 0x6f, 0x6d, 0x3a, 0x20, 0x66, 0x33, - 0x32, 0x2c, 0x0d, 0x0a, 0x7d, 0x0d, 0x0a, 0x73, 0x74, 0x72, 0x75, 0x63, - 0x74, 0x20, 0x54, 0x69, 0x6c, 0x65, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x73, - 0x20, 0x7b, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x6f, 0x64, 0x3a, - 0x20, 0x75, 0x33, 0x32, 0x2c, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x74, - 0x69, 0x6c, 0x65, 0x5f, 0x73, 0x69, 0x7a, 0x65, 0x3a, 0x20, 0x66, 0x33, - 0x32, 0x2c, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x77, 0x6f, 0x72, 0x6c, - 0x64, 0x5f, 0x6d, 0x69, 0x6e, 0x3a, 0x20, 0x76, 0x65, 0x63, 0x32, 0x66, - 0x2c, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x77, 0x6f, 0x72, 0x6c, 0x64, - 0x5f, 0x6d, 0x61, 0x78, 0x3a, 0x20, 0x76, 0x65, 0x63, 0x32, 0x66, 0x2c, - 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x62, 0x75, 0x66, 0x66, 0x65, 0x72, - 0x5f, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x3a, 0x20, 0x75, 0x33, 0x32, 0x2c, - 0x0d, 0x0a, 0x7d, 0x0d, 0x0a, 0x0d, 0x0a, 0x40, 0x67, 0x72, 0x6f, 0x75, - 0x70, 0x28, 0x30, 0x29, 0x20, 0x40, 0x62, 0x69, 0x6e, 0x64, 0x69, 0x6e, - 0x67, 0x28, 0x30, 0x29, 0x20, 0x76, 0x61, 0x72, 0x3c, 0x75, 0x6e, 0x69, - 0x66, 0x6f, 0x72, 0x6d, 0x3e, 0x20, 0x75, 0x6e, 0x69, 0x66, 0x6f, 0x72, - 0x6d, 0x73, 0x3a, 0x20, 0x55, 0x6e, 0x69, 0x66, 0x6f, 0x72, 0x6d, 0x73, - 0x3b, 0x0d, 0x0a, 0x40, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x28, 0x30, 0x29, - 0x20, 0x40, 0x62, 0x69, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x28, 0x31, 0x29, - 0x20, 0x76, 0x61, 0x72, 0x3c, 0x75, 0x6e, 0x69, 0x66, 0x6f, 0x72, 0x6d, - 0x3e, 0x20, 0x74, 0x69, 0x6c, 0x65, 0x5f, 0x70, 0x61, 0x72, 0x61, 0x6d, - 0x73, 0x3a, 0x20, 0x54, 0x69, 0x6c, 0x65, 0x50, 0x61, 0x72, 0x61, 0x6d, - 0x73, 0x3b, 0x0d, 0x0a, 0x0d, 0x0a, 0x40, 0x76, 0x65, 0x72, 0x74, 0x65, - 0x78, 0x20, 0x66, 0x6e, 0x20, 0x76, 0x73, 0x5f, 0x6d, 0x61, 0x69, 0x6e, - 0x28, 0x40, 0x62, 0x75, 0x69, 0x6c, 0x74, 0x69, 0x6e, 0x28, 0x76, 0x65, - 0x72, 0x74, 0x65, 0x78, 0x5f, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x29, 0x20, - 0x76, 0x65, 0x72, 0x74, 0x65, 0x78, 0x5f, 0x69, 0x6e, 0x64, 0x65, 0x78, - 0x20, 0x3a, 0x20, 0x75, 0x33, 0x32, 0x29, 0x20, 0x2d, 0x3e, 0x20, 0x40, - 0x62, 0x75, 0x69, 0x6c, 0x74, 0x69, 0x6e, 0x28, 0x70, 0x6f, 0x73, 0x69, - 0x74, 0x69, 0x6f, 0x6e, 0x29, 0x20, 0x76, 0x65, 0x63, 0x34, 0x66, 0x20, - 0x7b, 0x0d, 0x0a, 0x20, 0x20, 0x63, 0x6f, 0x6e, 0x73, 0x74, 0x20, 0x70, - 0x6f, 0x73, 0x20, 0x3d, 0x20, 0x61, 0x72, 0x72, 0x61, 0x79, 0x28, 0x0d, - 0x0a, 0x20, 0x20, 0x20, 0x20, 0x76, 0x65, 0x63, 0x32, 0x28, 0x20, 0x30, - 0x2e, 0x30, 0x2c, 0x20, 0x20, 0x30, 0x2e, 0x35, 0x29, 0x2c, 0x0d, 0x0a, - 0x20, 0x20, 0x20, 0x20, 0x76, 0x65, 0x63, 0x32, 0x28, 0x2d, 0x30, 0x2e, - 0x35, 0x2c, 0x20, 0x2d, 0x30, 0x2e, 0x35, 0x29, 0x2c, 0x0d, 0x0a, 0x20, - 0x20, 0x20, 0x20, 0x76, 0x65, 0x63, 0x32, 0x28, 0x20, 0x30, 0x2e, 0x35, - 0x2c, 0x20, 0x2d, 0x30, 0x2e, 0x35, 0x29, 0x0d, 0x0a, 0x20, 0x20, 0x29, - 0x3b, 0x0d, 0x0a, 0x0d, 0x0a, 0x20, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, - 0x6e, 0x20, 0x76, 0x65, 0x63, 0x34, 0x66, 0x28, 0x70, 0x6f, 0x73, 0x5b, - 0x76, 0x65, 0x72, 0x74, 0x65, 0x78, 0x5f, 0x69, 0x6e, 0x64, 0x65, 0x78, - 0x5d, 0x2c, 0x20, 0x30, 0x2c, 0x20, 0x31, 0x29, 0x3b, 0x0d, 0x0a, 0x7d, + 0x72, 0x6d, 0x73, 0x20, 0x7b, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x74, + 0x69, 0x6d, 0x65, 0x3a, 0x20, 0x75, 0x33, 0x32, 0x2c, 0x0d, 0x0a, 0x20, + 0x20, 0x20, 0x20, 0x66, 0x72, 0x61, 0x6d, 0x65, 0x3a, 0x20, 0x75, 0x33, + 0x32, 0x2c, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x6d, 0x76, 0x70, 0x3a, + 0x20, 0x6d, 0x61, 0x74, 0x34, 0x78, 0x34, 0x66, 0x2c, 0x0d, 0x0a, 0x7d, + 0x0d, 0x0a, 0x73, 0x74, 0x72, 0x75, 0x63, 0x74, 0x20, 0x54, 0x69, 0x6c, + 0x65, 0x20, 0x7b, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x77, 0x6f, 0x72, + 0x6c, 0x64, 0x5f, 0x6d, 0x69, 0x6e, 0x3a, 0x20, 0x76, 0x65, 0x63, 0x32, + 0x66, 0x2c, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x77, 0x6f, 0x72, 0x6c, + 0x64, 0x5f, 0x6d, 0x61, 0x78, 0x3a, 0x20, 0x76, 0x65, 0x63, 0x32, 0x66, + 0x2c, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x6f, 0x66, 0x66, 0x73, 0x65, + 0x74, 0x3a, 0x20, 0x75, 0x33, 0x32, 0x2c, 0x0d, 0x0a, 0x20, 0x20, 0x20, + 0x20, 0x63, 0x69, 0x72, 0x63, 0x6c, 0x65, 0x5f, 0x63, 0x6f, 0x75, 0x6e, + 0x74, 0x3a, 0x20, 0x75, 0x33, 0x32, 0x2c, 0x0d, 0x0a, 0x20, 0x20, 0x20, + 0x20, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x3a, 0x20, 0x75, 0x33, 0x32, 0x2c, + 0x0d, 0x0a, 0x7d, 0x3b, 0x0d, 0x0a, 0x0d, 0x0a, 0x40, 0x67, 0x72, 0x6f, + 0x75, 0x70, 0x28, 0x30, 0x29, 0x20, 0x40, 0x62, 0x69, 0x6e, 0x64, 0x69, + 0x6e, 0x67, 0x28, 0x30, 0x29, 0x20, 0x76, 0x61, 0x72, 0x3c, 0x75, 0x6e, + 0x69, 0x66, 0x6f, 0x72, 0x6d, 0x3e, 0x20, 0x75, 0x6e, 0x69, 0x66, 0x6f, + 0x72, 0x6d, 0x73, 0x3a, 0x20, 0x55, 0x6e, 0x69, 0x66, 0x6f, 0x72, 0x6d, + 0x73, 0x3b, 0x0d, 0x0a, 0x0d, 0x0a, 0x40, 0x67, 0x72, 0x6f, 0x75, 0x70, + 0x28, 0x31, 0x29, 0x20, 0x40, 0x62, 0x69, 0x6e, 0x64, 0x69, 0x6e, 0x67, + 0x28, 0x30, 0x29, 0x20, 0x76, 0x61, 0x72, 0x3c, 0x73, 0x74, 0x6f, 0x72, + 0x61, 0x67, 0x65, 0x3e, 0x20, 0x74, 0x69, 0x6c, 0x65, 0x73, 0x3a, 0x20, + 0x61, 0x72, 0x72, 0x61, 0x79, 0x3c, 0x54, 0x69, 0x6c, 0x65, 0x3e, 0x3b, + 0x0d, 0x0a, 0x40, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x28, 0x31, 0x29, 0x20, + 0x40, 0x62, 0x69, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x28, 0x31, 0x29, 0x20, + 0x76, 0x61, 0x72, 0x20, 0x73, 0x64, 0x66, 0x5f, 0x62, 0x75, 0x66, 0x66, + 0x65, 0x72, 0x20, 0x3a, 0x20, 0x74, 0x65, 0x78, 0x74, 0x75, 0x72, 0x65, + 0x5f, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x5f, 0x32, 0x64, 0x3c, + 0x72, 0x31, 0x36, 0x66, 0x6c, 0x6f, 0x61, 0x74, 0x2c, 0x20, 0x72, 0x65, + 0x61, 0x64, 0x3e, 0x3b, 0x0d, 0x0a, 0x40, 0x67, 0x72, 0x6f, 0x75, 0x70, + 0x28, 0x31, 0x29, 0x20, 0x40, 0x62, 0x69, 0x6e, 0x64, 0x69, 0x6e, 0x67, + 0x28, 0x32, 0x29, 0x20, 0x76, 0x61, 0x72, 0x20, 0x73, 0x64, 0x66, 0x5f, + 0x73, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x72, 0x3a, 0x20, 0x73, 0x61, 0x6d, + 0x70, 0x6c, 0x65, 0x72, 0x3b, 0x0d, 0x0a, 0x0d, 0x0a, 0x40, 0x76, 0x65, + 0x72, 0x74, 0x65, 0x78, 0x20, 0x66, 0x6e, 0x20, 0x76, 0x73, 0x5f, 0x6d, + 0x61, 0x69, 0x6e, 0x28, 0x40, 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, + 0x6e, 0x28, 0x30, 0x29, 0x20, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, + 0x6e, 0x3a, 0x20, 0x76, 0x65, 0x63, 0x32, 0x66, 0x29, 0x20, 0x2d, 0x3e, + 0x20, 0x40, 0x62, 0x75, 0x69, 0x6c, 0x74, 0x69, 0x6e, 0x28, 0x70, 0x6f, + 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x29, 0x20, 0x76, 0x65, 0x63, 0x34, + 0x66, 0x20, 0x7b, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x74, + 0x75, 0x72, 0x6e, 0x20, 0x76, 0x65, 0x63, 0x34, 0x66, 0x28, 0x70, 0x6f, + 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x2c, 0x20, 0x30, 0x2e, 0x30, 0x2c, + 0x20, 0x31, 0x2e, 0x30, 0x29, 0x20, 0x2a, 0x20, 0x75, 0x6e, 0x69, 0x66, + 0x6f, 0x72, 0x6d, 0x73, 0x2e, 0x6d, 0x76, 0x70, 0x3b, 0x0d, 0x0a, 0x7d, 0x0d, 0x0a, 0x0d, 0x0a, 0x40, 0x66, 0x72, 0x61, 0x67, 0x6d, 0x65, 0x6e, 0x74, 0x20, 0x66, 0x6e, 0x20, 0x66, 0x73, 0x5f, 0x6d, 0x61, 0x69, 0x6e, 0x28, 0x29, 0x20, 0x2d, 0x3e, 0x20, 0x40, 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x30, 0x29, 0x20, 0x76, 0x65, 0x63, 0x34, 0x66, - 0x20, 0x7b, 0x0d, 0x0a, 0x20, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, - 0x20, 0x76, 0x65, 0x63, 0x34, 0x28, 0x31, 0x2c, 0x20, 0x30, 0x2c, 0x20, - 0x30, 0x2c, 0x20, 0x31, 0x29, 0x3b, 0x0d, 0x0a, 0x7d, 0x0d, 0x0a + 0x20, 0x7b, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x74, 0x75, + 0x72, 0x6e, 0x20, 0x76, 0x65, 0x63, 0x34, 0x66, 0x28, 0x31, 0x2e, 0x30, + 0x2c, 0x20, 0x30, 0x2e, 0x30, 0x2c, 0x20, 0x30, 0x2e, 0x30, 0x2c, 0x20, + 0x31, 0x2e, 0x30, 0x29, 0x3b, 0x0d, 0x0a, 0x7d }; -unsigned int src_shaders_display_wgsl_len = 623; +unsigned int src_shaders_display_wgsl_len = 668; diff --git a/src/main.c b/src/main.c index b073473..d18813e 100644 --- a/src/main.c +++ b/src/main.c @@ -1,16 +1,8 @@ #include "api.h" -#define COMPUTE_VIEWIDX_segments 0 -#define COMPUTE_VIEWIDX_shapes 1 -#define COMPUTE_VIEWIDX_tiles 2 -#define COMPUTE_VIEWIDX_SDF 3 - -#define DISPLAY_VIEWIDX_tiles 0 -#define DISPLAY_VIEWIDX_SDF 1 - typedef struct display_uniforms { - uint64_t frame; - uint64_t time; + uint32_t frame; + uint32_t time; float mvp[16]; } display_uniforms; @@ -23,19 +15,10 @@ typedef struct renderer_t { display_uniforms uniforms; } renderer_t; -typedef struct compute_uniforms { - uint64_t frame; - uint64_t time; - - float pan_x, pan_y; - float zoom, rotation; -} compute_uniforms; - typedef struct compute_t { sg_pipeline pipeline; sg_bindings bindings; - - compute_uniforms uniforms; + sg_pass pass; } compute_t; typedef struct userdata_t { @@ -59,12 +42,6 @@ static void _free(void* ptr, void* userdata) emmalloc_free(ptr); } -static void log_fn(const char* tag, uint32_t log_level, uint32_t log_item_id, const char* message_or_null, uint32_t line_nr, const char* filename_or_null, void* user_data) -{ - if(log_level < 2) return; - fprintf(stderr, "[%s - %s]: (%d) %s \nat %s:%d", tag, log_level == 0 ? "FATAL" : log_level == 1 ? "ERROR" : "WARNING", log_item_id, message_or_null, filename_or_null, line_nr); -} - static void refresh_SDF(userdata_t* ud) { //Get visible tiles @@ -77,56 +54,116 @@ static void refresh_SDF(userdata_t* ud) ud->pan_y + view_world_h * 0.5f, }; + bool dirty = false; if(ud->scene.segment_dirty) { - sg_buffer seg_buffer = sg_query_view_buffer(ud->compute.bindings.views[COMPUTE_VIEWIDX_segments]); - sg_update_buffer(seg_buffer, &(sg_range) { .ptr = ud->scene.segments, .size = sizeof(segment_t) * ud->scene.num_segments }); + pool_view_grow(ud->compute.bindings.views[COMPUTE_VIEWIDX_segments], sizeof(segment_t), ud->scene.shapes.num_segments, ud->scene.shapes.segments); ud->scene.segment_dirty = false; + dirty = true; } if(ud->scene.shape_dirty) { - sg_buffer shape_buffer = sg_query_view_buffer(ud->compute.bindings.views[COMPUTE_VIEWIDX_shapes]); - sg_update_buffer(shape_buffer, &(sg_range) { .ptr = ud->scene.shapes, .size = sizeof(shape_meta_t) * ud->scene.num_shapes }); + pool_view_grow(ud->compute.bindings.views[COMPUTE_VIEWIDX_shapes], sizeof(shape_meta_t), ud->scene.shapes.num_shapes, ud->scene.shapes.shapes); ud->scene.shape_dirty = false; + dirty = true; + } + + if(ud->scene.circle_dirty) + { + pool_view_grow(ud->compute.bindings.views[COMPUTE_VIEWIDX_circles], sizeof(circle_t), ud->scene.circles.num_circles, ud->scene.circles.circles); + ud->scene.circle_dirty = false; + dirty = true; } - sg_begin_pass(&(sg_pass){ .compute = true, .label = "Compute Pass" }); - sg_apply_pipeline(ud->compute.pipeline); - sg_apply_uniforms(0, &SG_RANGE(ud->renderer.uniforms)); - sg_apply_bindings(&ud->compute.bindings); + if(dirty) + { + uint32_t tile_count = scene_process_tiles(&ud->scene, ud->pan_x, ud->pan_y, ud->zoom, &ud->compute.bindings); - sg_dispatch((uint32_t) 16 /* num_tiles */ * 16, 16, 1); + if(tile_count > 0) + { + pool_view_grow(ud->compute.bindings.views[COMPUTE_VIEWIDX_tiles], sizeof(tile_task_t), tile_count, ud->scene.cache.tiles); + pool_view_grow(ud->compute.bindings.views[COMPUTE_VIEWIDX_indices], sizeof(uint32_t), ud->scene.cache.num_indices, ud->scene.cache.indices); - sg_end_pass(); + ud->compute.bindings.views[COMPUTE_VIEWIDX_SDF] = ud->scene.texture; + + sg_begin_pass(&ud->compute.pass); + sg_apply_pipeline(ud->compute.pipeline); + sg_apply_bindings(&ud->compute.bindings); + + sg_dispatch(tile_count * 16, 16, 1); + + sg_end_pass(); + } + dirty = false; + } +} + +static sg_pass pass = (sg_pass){ + .label = "Render pass", +}; +static simgui_frame_desc_t imgui_frame = {0}; + +static void compute_mvp(userdata_t *ud) +{ + const float w = sapp_widthf(); + const float h = sapp_heightf(); + const float z = ud->zoom; + const float px = ud->pan_x; + const float py = ud->pan_y; + float* mvp = ud->renderer.uniforms.mvp; + + mvp[0] = (2.0f / w) * z; + mvp[1] = 0.0f; + mvp[2] = 0.0f; + mvp[3] = (2.0f / w) * px; + + mvp[4] = 0.0f; + mvp[5] = (2.0f / h) * z; + mvp[6] = 0.0f; + mvp[7] = (2.0f / h) * py; + + mvp[8] = 0.0f; + mvp[9] = 0.0f; + mvp[10] = 0.0f; + mvp[11] = 0.0f; + + mvp[12] = 0.0f; + mvp[13] = 0.0f; + mvp[14] = 0.0f; + mvp[15] = 1.0f; } static void frame(void* _userdata) { userdata_t* ud = (userdata_t*) _userdata; - ud->renderer.uniforms.frame = ud->compute.uniforms.frame = sapp_frame_count(); - ud->renderer.uniforms.time = ud->compute.uniforms.time += sapp_frame_duration_unfiltered(); + ud->renderer.uniforms.frame = sapp_frame_count(); + ud->renderer.uniforms.time += sapp_frame_duration_unfiltered(); - draw_scene(ud); + refresh_SDF(ud); - sg_begin_pass(&(sg_pass){ - .action = ud->renderer.clear_pass, - .swapchain = sglue_swapchain(), - }); + pass.swapchain = sglue_swapchain(); + sg_begin_pass(&pass); - simgui_new_frame(&(simgui_frame_desc_t){ - .width = sapp_width(), - .height = sapp_height(), - .delta_time = sapp_frame_duration_unfiltered(), - .dpi_scale = sapp_dpi_scale(), - }); + imgui_frame.width = sapp_width(), + imgui_frame.height = sapp_height(), + imgui_frame.delta_time = sapp_frame_duration_unfiltered(), + imgui_frame.dpi_scale = sapp_dpi_scale(), + simgui_new_frame(&imgui_frame); igBegin("Framerate", (bool*) true, ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoTitleBar); igText("%.0f FPS", 1 / sapp_frame_duration_unfiltered()); igText("%.3fms", sapp_frame_duration_unfiltered() * 1000); igEnd(); + ud->renderer.uniforms.frame = sapp_frame_count(); + ud->renderer.uniforms.time += (uint32_t) ceil(sapp_frame_duration_unfiltered() / 1000.0f); + sg_apply_pipeline(ud->renderer.pipeline); + sg_apply_uniforms(0, &SG_RANGE(ud->renderer.uniforms)); + sg_apply_bindings(&ud->renderer.bindings); + sg_draw(0, 4, 1); + simgui_render(); sg_end_pass(); sg_commit(); @@ -152,7 +189,7 @@ static void init(void* _userdata) }); ud->scene = (scene_t) {0}; - if(!scene_init(&ud->scene, 128, 1024, (vec2) { 8192.0f, 8192.0f })) return; + if(!scene_init(&ud->scene, (vec2) { 8192.0f, 8192.0f })) return; ud->compute = (compute_t) { .pipeline = sg_make_pipeline(&(sg_pipeline_desc){ @@ -170,10 +207,17 @@ static void init(void* _userdata) .readonly = true, } }, - [COMPUTE_VIEWIDX_segments] = { + [COMPUTE_VIEWIDX_shapes] = { .storage_buffer = { .stage = SG_SHADERSTAGE_COMPUTE, - .wgsl_group1_binding_n = COMPUTE_VIEWIDX_segments, + .wgsl_group1_binding_n = COMPUTE_VIEWIDX_shapes, + .readonly = true, + } + }, + [COMPUTE_VIEWIDX_circles] = { + .storage_buffer = { + .stage = SG_SHADERSTAGE_COMPUTE, + .wgsl_group1_binding_n = COMPUTE_VIEWIDX_circles, .readonly = true, } }, @@ -181,15 +225,22 @@ static void init(void* _userdata) .storage_buffer = { .stage = SG_SHADERSTAGE_COMPUTE, .wgsl_group1_binding_n = COMPUTE_VIEWIDX_tiles, - .readonly = false, + .readonly = true, + } + }, + [COMPUTE_VIEWIDX_indices] = { + .storage_buffer = { + .stage = SG_SHADERSTAGE_COMPUTE, + .wgsl_group1_binding_n = COMPUTE_VIEWIDX_indices, + .readonly = true, } }, [COMPUTE_VIEWIDX_SDF] = { .storage_image = { .stage = SG_SHADERSTAGE_COMPUTE, .wgsl_group1_binding_n = COMPUTE_VIEWIDX_SDF, - .access_format = SG_PIXELFORMAT_R32F, - .image_type = SG_IMAGETYPE_ARRAY, + .access_format = SG_PIXELFORMAT_R16F, + .image_type = SG_IMAGETYPE_2D, .writeonly = true, } } @@ -208,7 +259,7 @@ static void init(void* _userdata) .storage_buffer = true, .stream_update = true, }, - .size = sizeof(segment_t) * 1024 * 1024, + .size = sizeof(segment_t) * INITIAL_SEGMENTS_SIZE, }), }, }), @@ -221,7 +272,20 @@ static void init(void* _userdata) .storage_buffer = true, .stream_update = true, }, - .size = sizeof(shape_meta_t) * 1024 * 256, + .size = sizeof(shape_meta_t) * INITIAL_SHAPE_SIZE, + }), + }, + }), + .views[COMPUTE_VIEWIDX_circles] = sg_make_view(&(sg_view_desc) { + .label = "Circles view", + .storage_buffer = { + .buffer = sg_make_buffer(&(sg_buffer_desc) { + .label = "Circles buffer", + .usage = { + .storage_buffer = true, + .stream_update = true, + }, + .size = sizeof(circle_t) * INITIAL_CIRCLE_SIZE, }), }, }), @@ -234,26 +298,26 @@ static void init(void* _userdata) .storage_buffer = true, .stream_update = true, }, - .size = sizeof(tile_info_t) * TILE_LAYERS, + .size = sizeof(tile_task_t) * 256, }), }, }), - .views[COMPUTE_VIEWIDX_SDF] = sg_make_view(&(sg_view_desc) { - .label = "SDF tiles view", - .texture = { - .image = sg_make_image(&(sg_image_desc) { - .height = TILE_SIZE, - .width = TILE_SIZE, - .label = "SDF tiles texture", - .num_slices = TILE_LAYERS, - .pixel_format = SG_PIXELFORMAT_R32F, - .type = SG_IMAGETYPE_ARRAY, - .usage = { .storage_image = true }, + .views[COMPUTE_VIEWIDX_indices] = sg_make_view(&(sg_view_desc) { + .label = "Culling indices view", + .storage_buffer = { + .buffer = sg_make_buffer(&(sg_buffer_desc) { + .label = "Culling indices buffer", + .usage = { + .storage_buffer = true, + .stream_update = true, + }, + .size = sizeof(uint32_t) * INITIAL_INDICES_SIZE, }), - .slices = { .base = 0, .count = TILE_LAYERS }, }, }), - } + .views[COMPUTE_VIEWIDX_SDF] = (sg_view) {0}, + }, + .pass = { .compute = true, .label = "Compute Pass" } }; const vec2 quad[4] = { @@ -267,7 +331,7 @@ static void init(void* _userdata) }; ud->renderer = (renderer_t) { - .pipeline = sg_make_pipeline(&(sg_pipeline_desc){ + .pipeline = sg_make_pipeline(&(sg_pipeline_desc) { .shader = sg_make_shader(&(sg_shader_desc) { .vertex_func = { .source = (const char*) src_shaders_display_wgsl, @@ -277,6 +341,9 @@ static void init(void* _userdata) .source = (const char*) src_shaders_display_wgsl, .entry = "fs_main", }, + .attrs[0] = { + .base_type = SG_SHADERATTRBASETYPE_FLOAT, + }, .views = { [DISPLAY_VIEWIDX_tiles] = { .storage_buffer = { @@ -284,21 +351,36 @@ static void init(void* _userdata) .wgsl_group1_binding_n = DISPLAY_VIEWIDX_tiles, .readonly = true, } - } + }, [DISPLAY_VIEWIDX_SDF] = { - .storage_buffer = { + .texture = { + .image_type = SG_IMAGETYPE_ARRAY, .stage = SG_SHADERSTAGE_FRAGMENT, .wgsl_group1_binding_n = DISPLAY_VIEWIDX_SDF, - .readonly = true, + .sample_type = SG_IMAGESAMPLETYPE_FLOAT, } } }, + .samplers = { + [0] = { + .sampler_type = SG_SAMPLERTYPE_FILTERING, + .stage = SG_SHADERSTAGE_FRAGMENT, + .wgsl_group1_binding_n = DISPLAY_VIEWIDX_Sampler, + } + }, + .texture_sampler_pairs = { + [0] = { + .sampler_slot = 0, + .view_slot = DISPLAY_VIEWIDX_SDF, + .stage = SG_SHADERSTAGE_FRAGMENT, + } + }, .uniform_blocks = { [0] = { .size = sizeof(display_uniforms), .stage = SG_SHADERSTAGE_VERTEX, .wgsl_group0_binding_n = 0, - } + }, }, .label = "Display Shader", }), @@ -309,9 +391,6 @@ static void init(void* _userdata) }, .label = "Render pipeline", }), - .clear_pass = (sg_pass_action) { - .colors[0] = { .clear_value = { 0.0f, 0.0f, 0.0f, 1.0f }, .load_action = SG_LOADACTION_CLEAR } - }, .bindings = { .index_buffer = sg_make_buffer(&(sg_buffer_desc) { .label = "Index buffer", @@ -329,7 +408,17 @@ static void init(void* _userdata) [DISPLAY_VIEWIDX_tiles] = ud->compute.bindings.views[COMPUTE_VIEWIDX_tiles], [DISPLAY_VIEWIDX_SDF] = ud->compute.bindings.views[COMPUTE_VIEWIDX_SDF], } - } + }, + .uniforms = { + .frame = 0, + .time = 0, + .mvp = { 0, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0 }, + }, + }; + compute_mvp(ud); + + pass.action = (sg_pass_action) { + .colors[0] = { .clear_value = { 0.0f, 0.0f, 0.0f, 1.0f }, .load_action = SG_LOADACTION_CLEAR } }; add_rectangle(&ud->scene, (vec2) { 200.0f, 100.0f }, (vec2) { 100.0f, 150.0f }); diff --git a/src/pool.h b/src/pool.h new file mode 100644 index 0000000..7d558a3 --- /dev/null +++ b/src/pool.h @@ -0,0 +1,36 @@ +#include "api.h" + +#define MAX_BUFFER_SIZE 1024 * 1024 * 1024 // 1GB + +static void pool_buffer_grow(sg_buffer buffer, uint32_t stripe, uint32_t count, void* data) +{ + size_t size = sg_query_buffer_size(buffer); + if(size == MAX_BUFFER_SIZE) return sg_update_buffer(buffer, &(sg_range) { data, MAX_BUFFER_SIZE }); + if(size < stripe * count) + { + sg_buffer_desc desc = sg_query_buffer_desc(buffer); + while(desc.size < stripe * count) desc.size = fmaxf(MAX_BUFFER_SIZE, size * 2); + + sg_uninit_buffer(buffer); + sg_init_buffer(buffer, &desc); + } + + sg_update_buffer(buffer, &(sg_range) { data, stripe * count }); +} +static void pool_view_grow(sg_view view, uint32_t stripe, uint32_t count, void* data) +{ + sg_buffer buffer = sg_query_view_buffer(view); + + size_t size = sg_query_buffer_size(buffer); + if(size == MAX_BUFFER_SIZE) return sg_update_buffer(buffer, &(sg_range) { data, MAX_BUFFER_SIZE }); + if(size < stripe * count) + { + sg_buffer_desc desc = sg_query_buffer_desc(buffer); + while(desc.size < stripe * count) desc.size = fmaxf(MAX_BUFFER_SIZE, size * 2); + + sg_uninit_buffer(buffer); + sg_init_buffer(buffer, &desc); + } + + sg_update_buffer(buffer, &(sg_range) { data, stripe * count }); +} \ No newline at end of file diff --git a/src/shaders/compute.wgsl b/src/shaders/compute.wgsl index b73f386..04cb6d8 100644 --- a/src/shaders/compute.wgsl +++ b/src/shaders/compute.wgsl @@ -4,22 +4,30 @@ struct Segment { p2: vec2f, p3: vec2f, } -struct ShapeMeta { - start_segment: u32, +struct ShapeMeta { + start_segment: u32, //Offset in the segments buffer segment_count: u32, bbox_min: vec2f, bbox_max: vec2f, } +struct Circle { + center: vec2f, + radius: f32, +} struct Tile { world_min: vec2f, world_max: vec2f, - layer: u32, + offset: u32, + circle_count: u32, + count: u32, }; @group(1) @binding(0) var segments: array; @group(1) @binding(1) var shapes: array; -@group(1) @binding(2) var tiles: array; -@group(1) @binding(3) var sdf_buffer: texture_storage_2d_array; +@group(1) @binding(2) var circles: array; +@group(1) @binding(3) var tiles: array; +@group(1) @binding(4) var indices: array; +@group(1) @binding(5) var sdf_buffer: texture_storage_2d; override TILE_SIZE: u32 = 256u; @@ -166,7 +174,9 @@ fn ray_intersections_cubic(p: vec2f, seg: Segment) -> i32 { // ---------- Main compute shader ---------- @compute @workgroup_size(8, 8) -fn main(@builtin(workgroup_id) wg: vec3, @builtin(local_invocation_id) local: vec3) { +fn main(@builtin(workgroup_id) wg: vec3, // each workgroup is a tile + @builtin(local_invocation_id) local: vec3) // each local invocation is a pixel +{ let tile_idx = wg.x / 16u; let tile = tiles[tile_idx]; @@ -177,37 +187,49 @@ fn main(@builtin(workgroup_id) wg: vec3, @builtin(local_invocation_id) loca return; } - let uv = (vec2f(px, py) + 0.5) / f32(TILE_SIZE); + let uv = (vec2f(f32(px), f32(py)) + 0.5) / f32(TILE_SIZE); let world = mix(tile.world_min, tile.world_max, uv); var minDist: f32 = 1e20; + var sdf: f32 = 1e20; var winding: i32 = 0; - for (var s = 0u; s < arrayLength(&shapes); s++) { - let shape = shapes[s]; + for (var s = 0u; s < tile.count; s++) { + // Use a pre-culled shape range per tile to reduce the per-pixel processing time + let index = indices[tile.offset + s]; - // Quick bbox culling in world space - let bbox_min = shape.bbox_min; - let bbox_max = shape.bbox_max; - let dx = max(bbox_min.x - world.x, max(0.0, world.x - bbox_max.x)); - let dy = max(bbox_min.y - world.y, max(0.0, world.y - bbox_max.y)); - let dist_to_box = sqrt(dx * dx + dy * dy); - if dist_to_box >= minDist { - continue; // This shape cannot improve the distance + // If the index is lower than the circle count, it mean we are processing circles + if(index < tile.circle_count) + { + let c = circles[index]; + sdf = min(sdf, length(world - c.center) - c.radius); } + else + { + let shape = shapes[index]; - // Process all segments of the shape - for (var i = shape.start_segment; i < shape.start_segment + shape.segment_count; i++) { - let seg = segments[i]; - let d = distance_to_cubic(world, seg); - minDist = min(minDist, d); + /*let bbox_min = shape.bbox_min; + let bbox_max = shape.bbox_max; + let dx = max(bbox_min.x - world.x, max(0.0, world.x - bbox_max.x)); + let dy = max(bbox_min.y - world.y, max(0.0, world.y - bbox_max.y)); + let dist_to_box = sqrt(dx * dx + dy * dy); + if dist_to_box >= minDist { + continue; + }*/ - winding += ray_intersections_cubic(world, seg); + // Process all segments of the shape + for (var i = shape.start_segment; i < shape.start_segment + shape.segment_count; i++) { + let seg = segments[i]; + let d = distance_to_cubic(world, seg); + minDist = min(minDist, d); + + winding += ray_intersections_cubic(world, seg); + } + + let sign = select(1.0, -1.0, winding != 0i); + sdf = min(sdf, sign * minDist); } } - let sign = select(1.0, -1.0, winding != 0i); - let sdf = sign * minDist; - - textureStore(sdf_buffer, vec2(px, py), tile.layer, vec4f(sdf, 0.0, 0.0, 1.0)); + textureStore(sdf_buffer, vec2(u32(world.x), u32(world.y)), vec4f(sdf, 0.0, 0.0, 1.0)); } \ No newline at end of file diff --git a/src/shaders/display.wgsl b/src/shaders/display.wgsl index 452d014..01d81c5 100644 --- a/src/shaders/display.wgsl +++ b/src/shaders/display.wgsl @@ -1,28 +1,26 @@ struct Uniforms { - pan: vec2f, - zoom: f32, + time: u32, + frame: u32, + mvp: mat4x4f, } -struct TileParams { - lod: u32, - tile_size: f32, +struct Tile { world_min: vec2f, world_max: vec2f, - buffer_index: u32, -} + offset: u32, + circle_count: u32, + count: u32, +}; @group(0) @binding(0) var uniforms: Uniforms; -@group(0) @binding(1) var tile_params: TileParams; -@vertex fn vs_main(@builtin(vertex_index) vertex_index : u32) -> @builtin(position) vec4f { - const pos = array( - vec2( 0.0, 0.5), - vec2(-0.5, -0.5), - vec2( 0.5, -0.5) - ); +@group(1) @binding(0) var tiles: array; +@group(1) @binding(1) var sdf_buffer : texture_storage_2d; +@group(1) @binding(2) var sdf_sampler: sampler; - return vec4f(pos[vertex_index], 0, 1); +@vertex fn vs_main(@location(0) position: vec2f) -> @builtin(position) vec4f { + return vec4f(position, 0.0, 1.0) * uniforms.mvp; } @fragment fn fs_main() -> @location(0) vec4f { - return vec4(1, 0, 0, 1); -} + return vec4f(1.0, 0.0, 0.0, 1.0); +} \ No newline at end of file diff --git a/src/shape.h b/src/shape.h index 8613a13..1a38535 100644 --- a/src/shape.h +++ b/src/shape.h @@ -3,6 +3,9 @@ typedef struct uvec2 { uint32_t x, y; } uvec2; typedef struct vec2 { float x, y; } vec2; +typedef struct ubox_t { + uint32_t min_x, min_y, max_x, max_y; +} ubox_t; typedef struct box_t { float min_x, min_y, max_x, max_y; } box_t; @@ -12,6 +15,11 @@ typedef struct box_t { || b.min_y > a.max_y \ || b.max_y < a.min_y) +#define CIRCLE_INTERSECTS(box, circle) !(circle.center.x - circle.radius > box.max_x \ + || circle.center.x + circle.radius < box.min_x \ + || circle.center.y - circle.radius > box.max_y \ + || circle.center.y + circle.radius < box.min_y) + typedef struct segment_t { vec2 p0, p1, p2, p3; // cubic Bézier: start, control1, control2, end } segment_t; @@ -22,167 +30,232 @@ typedef struct shape_meta_t { box_t aabb; } shape_meta_t; -#define TILE_SIZE 256 // pixels per tile (same for all LODs) -#define TILE_LAYERS 128 // texture_2d_array length with TILE_SIZE dimensions in r32float pixel format (TILE_SIZE² * 4 * TILE_LAYERS bytes) = 32 MB buffer +typedef struct circle_t { + vec2 center; + float radius; +} circle_t; -typedef struct __attribute__((packed)) tile_key_t { - uint32_t lod, tx, ty; -} tile_key_t; +#define TILE_SIZE 256 // texels per tile -// Tile descriptor (separated from tile_cache_entry to be sent to the GPU) -typedef struct tile_t { - tile_key_t key; - float texel_size, tile_world; -} tile_t; +#define TILE_COUNT(size) (uint32_t)ceilf(size.x / TILE_SIZE) * (uint32_t)ceilf(size.y / TILE_SIZE) -typedef struct LOD_t { - tile_t* tiles; +#define INITIAL_SHAPE_SIZE 256 +#define INITIAL_SEGMENTS_SIZE 8192 +#define INITIAL_CIRCLE_SIZE 1024 +#define INITIAL_INDICES_SIZE 16384 - uvec2 dimension; //Tile amount per dimension - vec2 range; //Zoom min-max range -} LOD_t; - -typedef struct tile_slot_t { - uint64_t last_used; //Last frame number for LURA - tile_key_t key; - uint32_t layer; - bool ready; -} tile_slot_t; - -// Used for storage buffer/uniform upload -typedef struct tile_info_t { +// Tile metadata for targetted updates +typedef struct tile_task_t { box_t bounds; - uint32_t layer; -} tile_info_t; + uint32_t offset; + uint32_t circle_count; + uint32_t count; +} tile_task_t; typedef struct scene_t { vec2 world_size; - uint32_t num_shapes; - uint32_t max_shapes; - shape_meta_t* shapes; + struct { + uint32_t num_shapes; + uint32_t max_shapes; + shape_meta_t* shapes; - uint32_t num_segments; - uint32_t max_segments; - segment_t* segments; - - //Theorically, the LOD amount and tile per LOD are computable, so it's not relevant to store them. - uint32_t num_LOD; - LOD_t* LODs; - - sg_view texture_cache; + uint32_t num_segments; + uint32_t max_segments; + segment_t* segments; + } shapes; struct { - tile_slot_t slots[TILE_LAYERS]; - uint32_t lru_head, lru_tail; + uint32_t num_circles; + uint32_t max_circles; + circle_t* circles; + } circles; - struct { tile_key_t key; uint32_t value; }* map; - - uint32_t free_layers[TILE_LAYERS]; - uint32_t free_count; + struct { + tile_task_t* tiles; // Array of tiles metadata for the compute buffer + bool* tile_dirty; // Array of tiles state, since this info don't needs to be uploaded to the GPU, it is stored separately + + uint32_t max_indices; + uint32_t num_indices; + uint32_t* indices; // Array of shapes/circles indices per tile, pre culled on the CPU side } cache; - bool shape_dirty, segment_dirty; + sg_view texture; //Layer count depends on the world size so the texture has to be allocate on the scene side + + bool shape_dirty, segment_dirty, circle_dirty; } scene_t; // Initialise a scene_t with a given capacity for shapes and segments. -static int scene_init(scene_t* s, int init_shape_cap, int init_seg_cap, vec2 world_size) { - s->num_shapes = 0; - s->max_shapes = init_shape_cap; - s->shapes = (shape_meta_t*) emmalloc_malloc(init_shape_cap * sizeof(shape_meta_t)); +static uint32_t scene_init(scene_t* s, vec2 world_size) { + s->shapes.num_shapes = 0; + s->shapes.max_shapes = INITIAL_SHAPE_SIZE; + s->shapes.shapes = (shape_meta_t*) emmalloc_malloc(INITIAL_SHAPE_SIZE * sizeof(shape_meta_t)); - s->num_segments = 0; - s->max_segments = init_seg_cap; - s->segments = (segment_t*) emmalloc_malloc(init_seg_cap * sizeof(segment_t)); + s->shapes.num_segments = 0; + s->shapes.max_segments = INITIAL_SEGMENTS_SIZE; + s->shapes.segments = (segment_t*) emmalloc_malloc(INITIAL_SEGMENTS_SIZE * sizeof(segment_t)); - const uint32_t max_LOD = fmax(ceilf(log2(world_size.x / TILE_SIZE)), ceilf(log2(world_size.y / TILE_SIZE))); - s->num_LOD = max_LOD; - s->LODs = emmalloc_malloc(max_LOD * sizeof(LOD_t)); - for(int i = 0; i < max_LOD; ++i) + s->circles.num_circles = 0; + s->circles.max_circles = INITIAL_SEGMENTS_SIZE; + s->circles.circles = (circle_t*) emmalloc_malloc(INITIAL_CIRCLE_SIZE * sizeof(circle_t)); + + const uint32_t tile_count_x = (uint32_t)ceilf(world_size.x / TILE_SIZE), tile_count_y = (uint32_t)ceilf(world_size.y / TILE_SIZE); + const uint32_t tile_count = tile_count_x * tile_count_y; + s->cache.tiles = (tile_task_t*) emmalloc_malloc(sizeof(tile_task_t) * tile_count); + s->cache.tile_dirty = (bool*) emmalloc_malloc(sizeof(bool) * tile_count); + + uint32_t idx = 0; + for(uint32_t y = 0; y < tile_count_y; y++) { - const float factor = 1 << i; - s->LODs[i].dimension = (uvec2) { (uint32_t) ceilf(world_size.x * factor / TILE_SIZE), (uint32_t) ceilf(world_size.y * factor / TILE_SIZE) }; - - const uint32_t tiles_count = s->LODs[i].dimension.x * s->LODs[i].dimension.y; - s->LODs[i].tiles = emmalloc_malloc(sizeof(tile_t) * tiles_count); - - s->LODs[i].range = (vec2) { }; //TODO - - uint32_t x = 0; uint32_t y = 0; - for(int j = 0; j < tiles_count; j++) + for(uint32_t x = 0; x < tile_count_x; x++) { - x++; - if(x >= s->LODs[i].dimension.x) { x = 0; y++; } - - //s->LODs[i].tiles[j] = (tile_t) { .lod = i, .tile = { x, y }, . }; + s->cache.tile_dirty[idx] = true; + idx++; } } - s->cache.map = NULL; - s->cache.free_count = TILE_LAYERS; - for(uint32_t i = 0; i < TILE_LAYERS; i++) - { - s->cache.free_layers[i] = i; - - s->cache.slots[i].key = (tile_key_t) { UINT32_MAX, 0, 0 }; - s->cache.slots[i].last_used = UINT32_MAX; - s->cache.slots[i].layer = UINT32_MAX; - s->cache.slots[i].ready = false; - } + s->cache.max_indices = INITIAL_INDICES_SIZE; + s->cache.num_indices = 0; + s->cache.indices = (uint32_t*) emmalloc_malloc(sizeof(uint32_t) * INITIAL_INDICES_SIZE); s->world_size = world_size; + s->texture = sg_make_view(&(sg_view_desc) { + .label = "SDF tiles view", + .texture = { + .image = sg_make_image(&(sg_image_desc) { + .width = (uint32_t) ceilf(world_size.x), + .height = (uint32_t) ceilf(world_size.y), + .label = "SDF tiles texture", + .pixel_format = SG_PIXELFORMAT_R16F, + .type = SG_IMAGETYPE_2D, + .usage = { .storage_image = true }, + }), + }, + }); - if (!s->shapes || !s->segments || !s->LODs) return 0; // allocation failure + if (!s->shapes.shapes || !s->shapes.segments || !s->circles.circles || !s->cache.indices || !s->cache.tiles || !s->cache.tile_dirty) return 0; // allocation failure return 1; } -// Append a segment, returns its index. (Reallocs if needed, simplified.) -static int scene_add_segment(scene_t* s, segment_t seg) { - if (s->num_segments >= s->max_segments) { - int new_cap = s->max_segments * 2; - segment_t* tmp = (segment_t*) realloc(s->segments, new_cap * sizeof(segment_t)); - if (!tmp) return -1; - s->segments = tmp; - s->max_segments = new_cap; +#define COORD_TO_INDEX(x, y, scene) y * ceilf(s->world_size.x / TILE_SIZE) + x + +static void scene_compute_culling(scene_t* s, tile_task_t* task) +{ + task->count = 0; + for(uint32_t i = 0; i < s->circles.num_circles; i++) + { + if(CIRCLE_INTERSECTS(task->bounds, s->circles.circles[i])) + { + if(s->cache.num_indices >= s->cache.max_indices) + { + s->cache.max_indices *= 2; + s->cache.indices = emmalloc_realloc(s->cache.indices, s->cache.max_indices * sizeof(uint32_t)); + } + s->cache.indices[s->cache.num_indices++] = i; + task->count++; + } } - int idx = s->num_segments++; - s->segments[idx] = seg; + task->circle_count = task->count; + for(uint32_t i = 0; i < s->shapes.num_shapes; i++) + { + if(BOX_INTERSECTS(task->bounds, s->shapes.shapes[i].aabb)) + { + if(s->cache.num_indices >= s->cache.max_indices) + { + s->cache.max_indices *= 2; + s->cache.indices = emmalloc_realloc(s->cache.indices, s->cache.max_indices * sizeof(uint32_t)); + } + s->cache.indices[s->cache.num_indices++] = i; + task->count++; + } + } +} + +// Find the proper LOD, the relevant tiles then run the culling process for the dirty tiles and upload data to the GPU for SDF rendering +static uint32_t scene_process_tiles(scene_t* s, float pan_x, float pan_y, float zoom, sg_bindings* bindings) +{ + const float width = (float)sapp_width(), height = (float) sapp_height(); + const float wpp = fmaxf(s->world_size.y / zoom / height, s->world_size.x / zoom / width); //World point per pixel + + float view_w = width * wpp, view_h = height * wpp; + box_t frustum = { + .min_x = ceilf((pan_x - view_w * 0.5) / TILE_SIZE), + .min_y = ceilf((pan_y - view_h * 0.5) / TILE_SIZE), + .max_x = ceilf((pan_x + view_w * 0.5) / TILE_SIZE), + .max_y = ceilf((pan_y + view_h * 0.5) / TILE_SIZE) + }; + + uint32_t dirty_tile_count = 0, offset = 0; + for(uint32_t y = frustum.min_y; y < frustum.max_y; y++) + { + for(uint32_t x = frustum.min_x; x < frustum.max_x; x++) + { + uint32_t idx = COORD_TO_INDEX(x, y, s); + if(s->cache.tile_dirty[idx]) + { + tile_task_t* task = &s->cache.tiles[dirty_tile_count++]; + task->bounds.min_x = x * TILE_SIZE; + task->bounds.min_y = y * TILE_SIZE; + task->bounds.max_x = fminf((x + 1) * TILE_SIZE, s->world_size.x); + task->bounds.max_y = fminf((y + 1) * TILE_SIZE, s->world_size.y); + + task->offset = offset; + scene_compute_culling(s, task); + offset += task->count; + + s->cache.tile_dirty[idx] = false; + } + } + } + + return dirty_tile_count; +} + +// Append a segment, returns its index. (Reallocs if needed, simplified.) +static uint32_t scene_add_segment(scene_t* s, segment_t seg) { + if (s->shapes.num_segments >= s->shapes.max_segments) { + int new_cap = s->shapes.max_segments * 2; + segment_t* tmp = (segment_t*) realloc(s->shapes.segments, new_cap * sizeof(segment_t)); + if (!tmp) return -1; + s->shapes.segments = tmp; + s->shapes.max_segments = new_cap; + } + int idx = s->shapes.num_segments++; + s->shapes.segments[idx] = seg; return idx; } // Append a shape (meta data) and return its index. -static int scene_add_shape(scene_t* s, shape_meta_t meta) { - if (s->num_shapes >= s->max_shapes) { - int new_cap = s->max_shapes * 2; - shape_meta_t* tmp = (shape_meta_t*) realloc(s->shapes, new_cap * sizeof(shape_meta_t)); +static uint32_t scene_add_shape(scene_t* s, shape_meta_t meta) { + if (s->shapes.num_shapes >= s->shapes.max_shapes) { + int new_cap = s->shapes.max_shapes * 2; + shape_meta_t* tmp = (shape_meta_t*) emmalloc_realloc(s->shapes.shapes, new_cap * sizeof(shape_meta_t)); if (!tmp) return -1; - s->shapes = tmp; - s->max_shapes = new_cap; + s->shapes.shapes = tmp; + s->shapes.max_shapes = new_cap; } - int idx = s->num_shapes++; - s->shapes[idx] = meta; + int idx = s->shapes.num_shapes++; + s->shapes.shapes[idx] = meta; return idx; } -static int scene_shutdown(scene_t* s) { - emmalloc_free(s->segments); - emmalloc_free(s->shapes); - - for(uint32_t i = 0; i < s->num_LOD; ++i) - emmalloc_free(s->LODs[i].tiles); - - emmalloc_free(s->LODs); +static uint32_t scene_shutdown(scene_t* s) { + emmalloc_free(s->shapes.segments); + emmalloc_free(s->shapes.shapes); + emmalloc_free(s->circles.circles); + emmalloc_free(s->cache.indices); + emmalloc_free(s->cache.tiles); + emmalloc_free(s->cache.tile_dirty); emmalloc_free(s); return 1; } // Compute axis-aligned bounding box for a set of segments (used after adding a shape). -static void compute_bbox(segment_t* segs, int start, int count, - float* minx, float* miny, float* maxx, float* maxy) { +static void compute_bbox(segment_t* segs, uint32_t start, uint32_t count, float* minx, float* miny, float* maxx, float* maxy) { float mx = 1e30f, my = 1e30f, Mx = -1e30f, My = -1e30f; for (int i = 0; i < count; i++) { segment_t s = segs[start + i]; @@ -200,7 +273,7 @@ static void compute_bbox(segment_t* segs, int start, int count, // Add an axis‑aligned rectangle centred at `center` with given width and height. // Returns the shape index, or -1 on error. -int add_rectangle(scene_t* s, vec2 center, vec2 size) { +uint32_t add_rectangle(scene_t* s, vec2 center, vec2 size) { float hw = size.x * 0.5f, hh = size.y * 0.5f; vec2 corners[4] = { {center.x - hw, center.y - hh}, // bottom‑left @@ -228,14 +301,14 @@ int add_rectangle(scene_t* s, vec2 center, vec2 size) { shape_meta_t meta; meta.start_segment = start; meta.segment_count = 4; - compute_bbox(s->segments, start, 4, &meta.aabb.min_x, &meta.aabb.min_y, &meta.aabb.max_x, &meta.aabb.max_y); + meta.aabb = (box_t) { center.x - hw, center.y - hh, center.x + hw, center.y + hh }; return scene_add_shape(s, meta); } // Add a circle centred at `center` with given radius. // approximated by 4 cubic Bézier segments (one per quadrant). // Returns shape index or -1. -int add_circle(scene_t* s, vec2 center, float radius) { +uint32_t add_circle_as_shape(scene_t* s, vec2 center, float radius) { const float k = 0.552284749831f; // magic constant for 90° arc (4/3 * (sqrt(2)-1)) float rk = radius * k; @@ -279,6 +352,12 @@ int add_circle(scene_t* s, vec2 center, float radius) { shape_meta_t meta; meta.start_segment = start; meta.segment_count = 4; - compute_bbox(s->segments, start, 4, &meta.aabb.min_x, &meta.aabb.min_y, &meta.aabb.max_x, &meta.aabb.max_y); + compute_bbox(s->shapes.segments, start, 4, &meta.aabb.min_x, &meta.aabb.min_y, &meta.aabb.max_x, &meta.aabb.max_y); return scene_add_shape(s, meta); +} + +uint32_t add_circle(scene_t* s, vec2 center, float radius) { + s->circles.circles[s->circles.num_circles++] = (circle_t) { center, radius }; + + return s->circles.num_circles - 1; } \ No newline at end of file