diff --git a/bridge/.gitignore b/bridge/.gitignore new file mode 100644 index 00000000..f87cb569 --- /dev/null +++ b/bridge/.gitignore @@ -0,0 +1,6 @@ +# Do not track Nodejs output files +node_modules/ +*.json + +# Do not track js2c.py output files +*.js diff --git a/bridge/README.md b/bridge/README.md new file mode 100644 index 00000000..b3e1aac3 --- /dev/null +++ b/bridge/README.md @@ -0,0 +1,31 @@ + +# WebUI Bridge + +The WebUI Bridge connects the UI (_Web Browser_) with the backend application through WebSocket. This bridge is written in TypeScript, and it needs to be transpiled to JavaScript using [ESBuild](https://esbuild.github.io/) to produce `webui_bridge.js`, then converted to C99 header using the Python script `js2c.py` to generate `webui_bridge.h`. + +### Windows + +- Install [Python](https://www.python.org/downloads/) +- Install [Node.js](https://nodejs.org/en/download) +- cd `webui\bridge` +- Run `npm install esbuild` +- Run `.\node_modules\.bin\esbuild --bundle --target="chrome90,firefox90,safari15" --format=esm --tree-shaking=false --outdir=.\ .\webui_bridge.ts` +- Run `python js2c.py` + +### Linux + +- Install [Python](https://www.python.org/downloads/) +- Install [Node.js](https://nodejs.org/en/download) +- cd `webui/bridge` +- Run `npm install esbuild` +- Run `./node_modules/.bin/esbuild --bundle --target="chrome90,firefox90,safari15" --format=esm --tree-shaking=false --outdir=./ ./webui_bridge.ts` +- Run `python js2c.py` + +### macOS + +- Install [Python](https://www.python.org/downloads/) +- Install [Node.js](https://nodejs.org/en/download) +- cd `webui/bridge` +- Run `npm install esbuild` +- Run `./node_modules/.bin/esbuild --bundle --target="chrome90,firefox90,safari15" --format=esm --tree-shaking=false --outdir=./ ./webui_bridge.ts` +- Run `python js2c.py` diff --git a/bridge/js2c.py b/bridge/js2c.py new file mode 100644 index 00000000..bd0ebee3 --- /dev/null +++ b/bridge/js2c.py @@ -0,0 +1,38 @@ +# WebUI JavaScript to C99 Header + +def js_to_c_header(input_filename, output_filename): + try: + # Read JS file content + with open(input_filename, 'r', encoding='utf-8') as f: + content = f.read() + + print(f"Converting '{input_filename}' to '{output_filename}'...") + + # Convert each character in JS content to its hexadecimal value + hex_values = ["0x{:02x}".format(ord(char)) for char in content] + + # Prepare the content for the C header file + header_content = ( + "// --- PLEASE DO NOT EDIT THIS FILE -------\n" + "// --- THIS FILE IS GENERATED BY JS2C.PY --\n\n" + "#ifndef WEBUI_BRIDGE_H\n" + "#define WEBUI_BRIDGE_H\n" + "unsigned char webui_javascript_bridge[] = { " + ) + + # Split the hexadecimal values to make the output more readable, adding a new line every 10 values + for i in range(0, len(hex_values), 10): + header_content += "\n " + ', '.join(hex_values[i:i+10]) + ',' + + header_content += "\n};\n\n#endif // WEBUI_BRIDGE_H" + + # Write the header content to the output file + with open(output_filename, 'w', encoding='utf-8') as f: + f.write(header_content) + + except FileNotFoundError: + print(f"Error: File '{input_filename}' not found.") + return + +# Main +js_to_c_header('webui_bridge.js', 'webui_bridge.h') diff --git a/bridge/utils.ts b/bridge/utils.ts new file mode 100644 index 00000000..41a2bb5e --- /dev/null +++ b/bridge/utils.ts @@ -0,0 +1,54 @@ +/* + WebUI Bridge Utils + + Copyright (c) 2023 Oculi Julien. + Licensed under MIT License. + All rights reserved. +*/ + +/** + * Allows you to automatically bind an event listener to newly added + * elements that match a specific selector within a given root element. + * Track dom update to rebind event listeners automatically. + * + * @param {HTMLElement} root - The root element to observe for changes. + * @param {string} targetSelector - Query selector matching elements that you want to bind the event listener to. + * @param {K} type - Type of event listener to bind (same as for addEventListener). + * @param listener - Event listener to bind (same as for addEventListener). + * @param {boolean | AddEventListenerOptions} [options] - Event listener options (same as for addEventListener). + * @returns the used observer to allow disconnect. + */ +export function addRefreshableEventListener< + K extends keyof HTMLElementEventMap +>( + root: HTMLElement, + targetSelector: string, + type: K, + listener: (this: HTMLElement, ev: HTMLElementEventMap[K]) => unknown, + options?: boolean | AddEventListenerOptions +) { + function rebindListener(mutations: MutationRecord[]) { + for (const mutation of mutations) { + for (const node of mutation.addedNodes) { + if (!(node instanceof HTMLElement)) return // Target only html elements + if (node.matches(targetSelector)) { + // Bind event on added nodes + node.addEventListener(type, listener, options) + } + for (const child of node.querySelectorAll(targetSelector)) { + if (!(child instanceof HTMLElement)) continue //Target only html elements + child.addEventListener(type, listener, options) + } + } + } + } + + const observer = new MutationObserver(rebindListener) //Set mutation observer callback + observer.observe(root, { subtree: true, childList: true }) // Observe root element and all his children + return observer // Allow user to stop observer for performance issues +} + +/** + * Async function constructor + */ +export const AsyncFunction = async function () {}.constructor diff --git a/bridge/webui_bridge.h b/bridge/webui_bridge.h new file mode 100644 index 00000000..0ed7c7d8 --- /dev/null +++ b/bridge/webui_bridge.h @@ -0,0 +1,1316 @@ +// --- PLEASE DO NOT EDIT THIS FILE ------- +// --- THIS FILE IS GENERATED BY JS2C.PY -- + +#ifndef WEBUI_BRIDGE_H +#define WEBUI_BRIDGE_H +unsigned char webui_javascript_bridge[] = { + 0x22, 0x75, 0x73, 0x65, 0x2d, 0x73, 0x74, 0x72, 0x69, 0x63, + 0x74, 0x22, 0x3b, 0x0a, 0x0a, 0x2f, 0x2f, 0x20, 0x75, 0x74, + 0x69, 0x6c, 0x73, 0x2e, 0x74, 0x73, 0x0a, 0x66, 0x75, 0x6e, + 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x61, 0x64, 0x64, 0x52, + 0x65, 0x66, 0x72, 0x65, 0x73, 0x68, 0x61, 0x62, 0x6c, 0x65, + 0x45, 0x76, 0x65, 0x6e, 0x74, 0x4c, 0x69, 0x73, 0x74, 0x65, + 0x6e, 0x65, 0x72, 0x28, 0x72, 0x6f, 0x6f, 0x74, 0x2c, 0x20, + 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x53, 0x65, 0x6c, 0x65, + 0x63, 0x74, 0x6f, 0x72, 0x2c, 0x20, 0x74, 0x79, 0x70, 0x65, + 0x2c, 0x20, 0x6c, 0x69, 0x73, 0x74, 0x65, 0x6e, 0x65, 0x72, + 0x2c, 0x20, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x29, + 0x20, 0x7b, 0x0a, 0x20, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, + 0x69, 0x6f, 0x6e, 0x20, 0x72, 0x65, 0x62, 0x69, 0x6e, 0x64, + 0x4c, 0x69, 0x73, 0x74, 0x65, 0x6e, 0x65, 0x72, 0x28, 0x6d, + 0x75, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x29, 0x20, + 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x66, 0x6f, 0x72, 0x20, + 0x28, 0x63, 0x6f, 0x6e, 0x73, 0x74, 0x20, 0x6d, 0x75, 0x74, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x6f, 0x66, 0x20, 0x6d, + 0x75, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x29, 0x20, + 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x66, 0x6f, + 0x72, 0x20, 0x28, 0x63, 0x6f, 0x6e, 0x73, 0x74, 0x20, 0x6e, + 0x6f, 0x64, 0x65, 0x20, 0x6f, 0x66, 0x20, 0x6d, 0x75, 0x74, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x61, 0x64, 0x64, 0x65, + 0x64, 0x4e, 0x6f, 0x64, 0x65, 0x73, 0x29, 0x20, 0x7b, 0x0a, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, + 0x20, 0x28, 0x21, 0x28, 0x6e, 0x6f, 0x64, 0x65, 0x20, 0x69, + 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x6f, 0x66, 0x20, + 0x48, 0x54, 0x4d, 0x4c, 0x45, 0x6c, 0x65, 0x6d, 0x65, 0x6e, + 0x74, 0x29, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, + 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x69, 0x66, 0x20, 0x28, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x6d, + 0x61, 0x74, 0x63, 0x68, 0x65, 0x73, 0x28, 0x74, 0x61, 0x72, + 0x67, 0x65, 0x74, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x6f, + 0x72, 0x29, 0x29, 0x20, 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x6e, 0x6f, 0x64, 0x65, + 0x2e, 0x61, 0x64, 0x64, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x4c, + 0x69, 0x73, 0x74, 0x65, 0x6e, 0x65, 0x72, 0x28, 0x74, 0x79, + 0x70, 0x65, 0x2c, 0x20, 0x6c, 0x69, 0x73, 0x74, 0x65, 0x6e, + 0x65, 0x72, 0x2c, 0x20, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, + 0x73, 0x29, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x7d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x28, 0x63, 0x6f, 0x6e, + 0x73, 0x74, 0x20, 0x63, 0x68, 0x69, 0x6c, 0x64, 0x20, 0x6f, + 0x66, 0x20, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x71, 0x75, 0x65, + 0x72, 0x79, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x6f, 0x72, + 0x41, 0x6c, 0x6c, 0x28, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, + 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x29, 0x29, + 0x20, 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, 0x28, 0x21, 0x28, 0x63, + 0x68, 0x69, 0x6c, 0x64, 0x20, 0x69, 0x6e, 0x73, 0x74, 0x61, + 0x6e, 0x63, 0x65, 0x6f, 0x66, 0x20, 0x48, 0x54, 0x4d, 0x4c, + 0x45, 0x6c, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x29, 0x29, 0x0a, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x63, 0x6f, 0x6e, 0x74, 0x69, 0x6e, 0x75, 0x65, + 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x63, 0x68, 0x69, 0x6c, 0x64, 0x2e, 0x61, 0x64, + 0x64, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x4c, 0x69, 0x73, 0x74, + 0x65, 0x6e, 0x65, 0x72, 0x28, 0x74, 0x79, 0x70, 0x65, 0x2c, + 0x20, 0x6c, 0x69, 0x73, 0x74, 0x65, 0x6e, 0x65, 0x72, 0x2c, + 0x20, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x29, 0x3b, + 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7d, + 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7d, 0x0a, 0x20, + 0x20, 0x20, 0x20, 0x7d, 0x0a, 0x20, 0x20, 0x7d, 0x0a, 0x20, + 0x20, 0x63, 0x6f, 0x6e, 0x73, 0x74, 0x20, 0x6f, 0x62, 0x73, + 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x3d, 0x20, 0x6e, 0x65, + 0x77, 0x20, 0x4d, 0x75, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x4f, 0x62, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x28, 0x72, + 0x65, 0x62, 0x69, 0x6e, 0x64, 0x4c, 0x69, 0x73, 0x74, 0x65, + 0x6e, 0x65, 0x72, 0x29, 0x3b, 0x0a, 0x20, 0x20, 0x6f, 0x62, + 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x6f, 0x62, 0x73, + 0x65, 0x72, 0x76, 0x65, 0x28, 0x72, 0x6f, 0x6f, 0x74, 0x2c, + 0x20, 0x7b, 0x20, 0x73, 0x75, 0x62, 0x74, 0x72, 0x65, 0x65, + 0x3a, 0x20, 0x74, 0x72, 0x75, 0x65, 0x2c, 0x20, 0x63, 0x68, + 0x69, 0x6c, 0x64, 0x4c, 0x69, 0x73, 0x74, 0x3a, 0x20, 0x74, + 0x72, 0x75, 0x65, 0x20, 0x7d, 0x29, 0x3b, 0x0a, 0x20, 0x20, + 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x6f, 0x62, 0x73, + 0x65, 0x72, 0x76, 0x65, 0x72, 0x3b, 0x0a, 0x7d, 0x0a, 0x76, + 0x61, 0x72, 0x20, 0x41, 0x73, 0x79, 0x6e, 0x63, 0x46, 0x75, + 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x3d, 0x20, 0x28, + 0x61, 0x73, 0x79, 0x6e, 0x63, 0x20, 0x66, 0x75, 0x6e, 0x63, + 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x29, 0x20, 0x7b, 0x0a, 0x7d, + 0x29, 0x2e, 0x63, 0x6f, 0x6e, 0x73, 0x74, 0x72, 0x75, 0x63, + 0x74, 0x6f, 0x72, 0x3b, 0x0a, 0x0a, 0x2f, 0x2f, 0x20, 0x77, + 0x65, 0x62, 0x75, 0x69, 0x5f, 0x62, 0x72, 0x69, 0x64, 0x67, + 0x65, 0x2e, 0x74, 0x73, 0x0a, 0x76, 0x61, 0x72, 0x20, 0x57, + 0x65, 0x62, 0x55, 0x69, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, + 0x20, 0x3d, 0x20, 0x63, 0x6c, 0x61, 0x73, 0x73, 0x20, 0x7b, + 0x0a, 0x20, 0x20, 0x2f, 0x2f, 0x20, 0x57, 0x65, 0x62, 0x55, + 0x49, 0x20, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, + 0x0a, 0x20, 0x20, 0x23, 0x70, 0x6f, 0x72, 0x74, 0x3b, 0x0a, + 0x20, 0x20, 0x23, 0x77, 0x69, 0x6e, 0x4e, 0x75, 0x6d, 0x3b, + 0x0a, 0x20, 0x20, 0x23, 0x6c, 0x6f, 0x67, 0x3b, 0x0a, 0x20, + 0x20, 0x23, 0x62, 0x69, 0x6e, 0x64, 0x4c, 0x69, 0x73, 0x74, + 0x20, 0x3d, 0x20, 0x5b, 0x5d, 0x3b, 0x0a, 0x20, 0x20, 0x2f, + 0x2f, 0x20, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, + 0x73, 0x0a, 0x20, 0x20, 0x23, 0x77, 0x73, 0x3b, 0x0a, 0x20, + 0x20, 0x23, 0x77, 0x73, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, + 0x20, 0x3d, 0x20, 0x66, 0x61, 0x6c, 0x73, 0x65, 0x3b, 0x0a, + 0x20, 0x20, 0x23, 0x77, 0x73, 0x53, 0x74, 0x61, 0x74, 0x75, + 0x73, 0x4f, 0x6e, 0x63, 0x65, 0x20, 0x3d, 0x20, 0x66, 0x61, + 0x6c, 0x73, 0x65, 0x3b, 0x0a, 0x20, 0x20, 0x23, 0x63, 0x6c, + 0x6f, 0x73, 0x65, 0x52, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x20, + 0x3d, 0x20, 0x30, 0x3b, 0x0a, 0x20, 0x20, 0x23, 0x63, 0x6c, + 0x6f, 0x73, 0x65, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x3b, 0x0a, + 0x20, 0x20, 0x23, 0x68, 0x61, 0x73, 0x45, 0x76, 0x65, 0x6e, + 0x74, 0x73, 0x20, 0x3d, 0x20, 0x66, 0x61, 0x6c, 0x73, 0x65, + 0x3b, 0x0a, 0x20, 0x20, 0x23, 0x66, 0x6e, 0x49, 0x64, 0x20, + 0x3d, 0x20, 0x31, 0x3b, 0x0a, 0x20, 0x20, 0x23, 0x66, 0x6e, + 0x50, 0x72, 0x6f, 0x6d, 0x69, 0x73, 0x65, 0x52, 0x65, 0x73, + 0x6f, 0x6c, 0x76, 0x65, 0x20, 0x3d, 0x20, 0x5b, 0x5d, 0x3b, + 0x0a, 0x20, 0x20, 0x2f, 0x2f, 0x20, 0x57, 0x65, 0x62, 0x55, + 0x49, 0x20, 0x63, 0x6f, 0x6e, 0x73, 0x74, 0x0a, 0x20, 0x20, + 0x23, 0x48, 0x45, 0x41, 0x44, 0x45, 0x52, 0x5f, 0x53, 0x49, + 0x47, 0x4e, 0x41, 0x54, 0x55, 0x52, 0x45, 0x20, 0x3d, 0x20, + 0x32, 0x32, 0x31, 0x3b, 0x0a, 0x20, 0x20, 0x23, 0x48, 0x45, + 0x41, 0x44, 0x45, 0x52, 0x5f, 0x4a, 0x53, 0x20, 0x3d, 0x20, + 0x32, 0x35, 0x34, 0x3b, 0x0a, 0x20, 0x20, 0x23, 0x48, 0x45, + 0x41, 0x44, 0x45, 0x52, 0x5f, 0x4a, 0x53, 0x5f, 0x51, 0x55, + 0x49, 0x43, 0x4b, 0x20, 0x3d, 0x20, 0x32, 0x35, 0x33, 0x3b, + 0x0a, 0x20, 0x20, 0x23, 0x48, 0x45, 0x41, 0x44, 0x45, 0x52, + 0x5f, 0x43, 0x4c, 0x49, 0x43, 0x4b, 0x20, 0x3d, 0x20, 0x32, + 0x35, 0x32, 0x3b, 0x0a, 0x20, 0x20, 0x23, 0x48, 0x45, 0x41, + 0x44, 0x45, 0x52, 0x5f, 0x53, 0x57, 0x49, 0x54, 0x43, 0x48, + 0x20, 0x3d, 0x20, 0x32, 0x35, 0x31, 0x3b, 0x0a, 0x20, 0x20, + 0x23, 0x48, 0x45, 0x41, 0x44, 0x45, 0x52, 0x5f, 0x43, 0x4c, + 0x4f, 0x53, 0x45, 0x20, 0x3d, 0x20, 0x32, 0x35, 0x30, 0x3b, + 0x0a, 0x20, 0x20, 0x23, 0x48, 0x45, 0x41, 0x44, 0x45, 0x52, + 0x5f, 0x43, 0x41, 0x4c, 0x4c, 0x5f, 0x46, 0x55, 0x4e, 0x43, + 0x20, 0x3d, 0x20, 0x32, 0x34, 0x39, 0x3b, 0x0a, 0x20, 0x20, + 0x23, 0x48, 0x45, 0x41, 0x44, 0x45, 0x52, 0x5f, 0x53, 0x45, + 0x4e, 0x44, 0x5f, 0x52, 0x41, 0x57, 0x20, 0x3d, 0x20, 0x32, + 0x34, 0x38, 0x3b, 0x0a, 0x20, 0x20, 0x63, 0x6f, 0x6e, 0x73, + 0x74, 0x72, 0x75, 0x63, 0x74, 0x6f, 0x72, 0x28, 0x7b, 0x0a, + 0x20, 0x20, 0x20, 0x20, 0x70, 0x6f, 0x72, 0x74, 0x2c, 0x0a, + 0x20, 0x20, 0x20, 0x20, 0x77, 0x69, 0x6e, 0x4e, 0x75, 0x6d, + 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x62, 0x69, 0x6e, 0x64, + 0x4c, 0x69, 0x73, 0x74, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, + 0x6c, 0x6f, 0x67, 0x20, 0x3d, 0x20, 0x66, 0x61, 0x6c, 0x73, + 0x65, 0x0a, 0x20, 0x20, 0x7d, 0x29, 0x20, 0x7b, 0x0a, 0x20, + 0x20, 0x20, 0x20, 0x74, 0x68, 0x69, 0x73, 0x2e, 0x23, 0x70, + 0x6f, 0x72, 0x74, 0x20, 0x3d, 0x20, 0x70, 0x6f, 0x72, 0x74, + 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x74, 0x68, 0x69, 0x73, + 0x2e, 0x23, 0x77, 0x69, 0x6e, 0x4e, 0x75, 0x6d, 0x20, 0x3d, + 0x20, 0x77, 0x69, 0x6e, 0x4e, 0x75, 0x6d, 0x3b, 0x0a, 0x20, + 0x20, 0x20, 0x20, 0x74, 0x68, 0x69, 0x73, 0x2e, 0x23, 0x62, + 0x69, 0x6e, 0x64, 0x4c, 0x69, 0x73, 0x74, 0x20, 0x3d, 0x20, + 0x62, 0x69, 0x6e, 0x64, 0x4c, 0x69, 0x73, 0x74, 0x3b, 0x0a, + 0x20, 0x20, 0x20, 0x20, 0x74, 0x68, 0x69, 0x73, 0x2e, 0x23, + 0x6c, 0x6f, 0x67, 0x20, 0x3d, 0x20, 0x6c, 0x6f, 0x67, 0x3b, + 0x0a, 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, 0x28, 0x22, + 0x77, 0x65, 0x62, 0x75, 0x69, 0x22, 0x20, 0x69, 0x6e, 0x20, + 0x67, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x54, 0x68, 0x69, 0x73, + 0x29, 0x20, 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x74, 0x68, 0x72, 0x6f, 0x77, 0x20, 0x6e, 0x65, 0x77, 0x20, + 0x45, 0x72, 0x72, 0x6f, 0x72, 0x28, 0x0a, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x53, 0x6f, 0x72, 0x72, + 0x79, 0x2e, 0x20, 0x57, 0x65, 0x62, 0x55, 0x49, 0x20, 0x69, + 0x73, 0x20, 0x61, 0x6c, 0x72, 0x65, 0x61, 0x64, 0x79, 0x20, + 0x64, 0x65, 0x66, 0x69, 0x6e, 0x65, 0x64, 0x2c, 0x20, 0x6f, + 0x6e, 0x6c, 0x79, 0x20, 0x6f, 0x6e, 0x65, 0x20, 0x69, 0x6e, + 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x20, 0x69, 0x73, 0x20, + 0x61, 0x6c, 0x6c, 0x6f, 0x77, 0x65, 0x64, 0x2e, 0x22, 0x0a, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x29, 0x3b, 0x0a, 0x20, + 0x20, 0x20, 0x20, 0x7d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x69, + 0x66, 0x20, 0x28, 0x21, 0x28, 0x22, 0x57, 0x65, 0x62, 0x53, + 0x6f, 0x63, 0x6b, 0x65, 0x74, 0x22, 0x20, 0x69, 0x6e, 0x20, + 0x77, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x29, 0x29, 0x20, 0x7b, + 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x61, 0x6c, 0x65, + 0x72, 0x74, 0x28, 0x22, 0x53, 0x6f, 0x72, 0x72, 0x79, 0x2e, + 0x20, 0x57, 0x65, 0x62, 0x53, 0x6f, 0x63, 0x6b, 0x65, 0x74, + 0x20, 0x69, 0x73, 0x20, 0x6e, 0x6f, 0x74, 0x20, 0x73, 0x75, + 0x70, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x20, 0x62, 0x79, + 0x20, 0x79, 0x6f, 0x75, 0x72, 0x20, 0x77, 0x65, 0x62, 0x20, + 0x62, 0x72, 0x6f, 0x77, 0x73, 0x65, 0x72, 0x2e, 0x22, 0x29, + 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, + 0x20, 0x28, 0x21, 0x74, 0x68, 0x69, 0x73, 0x2e, 0x23, 0x6c, + 0x6f, 0x67, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x67, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x54, 0x68, + 0x69, 0x73, 0x2e, 0x63, 0x6c, 0x6f, 0x73, 0x65, 0x28, 0x29, + 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x7d, 0x0a, 0x20, 0x20, + 0x20, 0x20, 0x74, 0x68, 0x69, 0x73, 0x2e, 0x23, 0x73, 0x74, + 0x61, 0x72, 0x74, 0x28, 0x29, 0x3b, 0x0a, 0x20, 0x20, 0x20, + 0x20, 0x69, 0x66, 0x20, 0x28, 0x22, 0x6e, 0x61, 0x76, 0x69, + 0x67, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x20, 0x69, 0x6e, + 0x20, 0x67, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x54, 0x68, 0x69, + 0x73, 0x29, 0x20, 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x67, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x54, 0x68, 0x69, + 0x73, 0x2e, 0x6e, 0x61, 0x76, 0x69, 0x67, 0x61, 0x74, 0x69, + 0x6f, 0x6e, 0x2e, 0x61, 0x64, 0x64, 0x45, 0x76, 0x65, 0x6e, + 0x74, 0x4c, 0x69, 0x73, 0x74, 0x65, 0x6e, 0x65, 0x72, 0x28, + 0x22, 0x6e, 0x61, 0x76, 0x69, 0x67, 0x61, 0x74, 0x65, 0x22, + 0x2c, 0x20, 0x28, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x29, 0x20, + 0x3d, 0x3e, 0x20, 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x63, 0x6f, 0x6e, 0x73, 0x74, 0x20, 0x75, + 0x72, 0x6c, 0x20, 0x3d, 0x20, 0x6e, 0x65, 0x77, 0x20, 0x55, + 0x52, 0x4c, 0x28, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x2e, 0x64, + 0x65, 0x73, 0x74, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x2e, 0x75, 0x72, 0x6c, 0x29, 0x3b, 0x0a, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x74, 0x68, 0x69, 0x73, 0x2e, + 0x23, 0x73, 0x65, 0x6e, 0x64, 0x45, 0x76, 0x65, 0x6e, 0x74, + 0x4e, 0x61, 0x76, 0x69, 0x67, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x28, 0x75, 0x72, 0x6c, 0x2e, 0x68, 0x72, 0x65, 0x66, 0x29, + 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7d, 0x29, + 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x7d, 0x20, 0x65, 0x6c, + 0x73, 0x65, 0x20, 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x61, 0x64, 0x64, 0x52, 0x65, 0x66, 0x72, 0x65, 0x73, + 0x68, 0x61, 0x62, 0x6c, 0x65, 0x45, 0x76, 0x65, 0x6e, 0x74, + 0x4c, 0x69, 0x73, 0x74, 0x65, 0x6e, 0x65, 0x72, 0x28, 0x0a, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x64, 0x6f, + 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x62, 0x6f, 0x64, + 0x79, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x22, 0x61, 0x22, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x22, 0x63, 0x6c, 0x69, 0x63, 0x6b, + 0x22, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x28, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x29, 0x20, 0x3d, + 0x3e, 0x20, 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x2e, + 0x70, 0x72, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x44, 0x65, 0x66, + 0x61, 0x75, 0x6c, 0x74, 0x28, 0x29, 0x3b, 0x0a, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x63, 0x6f, + 0x6e, 0x73, 0x74, 0x20, 0x7b, 0x20, 0x68, 0x72, 0x65, 0x66, + 0x20, 0x7d, 0x20, 0x3d, 0x20, 0x65, 0x76, 0x65, 0x6e, 0x74, + 0x2e, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x3b, 0x0a, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x69, + 0x66, 0x20, 0x28, 0x74, 0x68, 0x69, 0x73, 0x2e, 0x23, 0x69, + 0x73, 0x45, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x4c, + 0x69, 0x6e, 0x6b, 0x28, 0x68, 0x72, 0x65, 0x66, 0x29, 0x29, + 0x20, 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x74, 0x68, 0x69, 0x73, 0x2e, + 0x23, 0x63, 0x6c, 0x6f, 0x73, 0x65, 0x28, 0x74, 0x68, 0x69, + 0x73, 0x2e, 0x23, 0x48, 0x45, 0x41, 0x44, 0x45, 0x52, 0x5f, + 0x53, 0x57, 0x49, 0x54, 0x43, 0x48, 0x2c, 0x20, 0x68, 0x72, + 0x65, 0x66, 0x29, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x7d, 0x20, 0x65, 0x6c, 0x73, + 0x65, 0x20, 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x74, 0x68, 0x69, 0x73, + 0x2e, 0x23, 0x73, 0x65, 0x6e, 0x64, 0x45, 0x76, 0x65, 0x6e, + 0x74, 0x4e, 0x61, 0x76, 0x69, 0x67, 0x61, 0x74, 0x69, 0x6f, + 0x6e, 0x28, 0x68, 0x72, 0x65, 0x66, 0x29, 0x3b, 0x0a, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7d, + 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7d, + 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x29, 0x3b, 0x0a, + 0x20, 0x20, 0x20, 0x20, 0x7d, 0x0a, 0x20, 0x20, 0x20, 0x20, + 0x64, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x61, + 0x64, 0x64, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x4c, 0x69, 0x73, + 0x74, 0x65, 0x6e, 0x65, 0x72, 0x28, 0x22, 0x6b, 0x65, 0x79, + 0x64, 0x6f, 0x77, 0x6e, 0x22, 0x2c, 0x20, 0x28, 0x65, 0x76, + 0x65, 0x6e, 0x74, 0x29, 0x20, 0x3d, 0x3e, 0x20, 0x7b, 0x0a, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, 0x28, + 0x74, 0x68, 0x69, 0x73, 0x2e, 0x23, 0x6c, 0x6f, 0x67, 0x29, + 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x72, + 0x65, 0x74, 0x75, 0x72, 0x6e, 0x3b, 0x0a, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, 0x28, 0x65, 0x76, 0x65, + 0x6e, 0x74, 0x2e, 0x6b, 0x65, 0x79, 0x20, 0x3d, 0x3d, 0x3d, + 0x20, 0x22, 0x46, 0x35, 0x22, 0x29, 0x0a, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x65, 0x76, 0x65, 0x6e, 0x74, + 0x2e, 0x70, 0x72, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x44, 0x65, + 0x66, 0x61, 0x75, 0x6c, 0x74, 0x28, 0x29, 0x3b, 0x0a, 0x20, + 0x20, 0x20, 0x20, 0x7d, 0x29, 0x3b, 0x0a, 0x20, 0x20, 0x20, + 0x20, 0x6f, 0x6e, 0x62, 0x65, 0x66, 0x6f, 0x72, 0x65, 0x75, + 0x6e, 0x6c, 0x6f, 0x61, 0x64, 0x20, 0x3d, 0x20, 0x28, 0x29, + 0x20, 0x3d, 0x3e, 0x20, 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x74, 0x68, 0x69, 0x73, 0x2e, 0x23, 0x63, 0x6c, + 0x6f, 0x73, 0x65, 0x28, 0x29, 0x3b, 0x0a, 0x20, 0x20, 0x20, + 0x20, 0x7d, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x73, 0x65, + 0x74, 0x54, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x28, 0x28, + 0x29, 0x20, 0x3d, 0x3e, 0x20, 0x7b, 0x0a, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, 0x28, 0x21, 0x74, 0x68, + 0x69, 0x73, 0x2e, 0x23, 0x77, 0x73, 0x53, 0x74, 0x61, 0x74, + 0x75, 0x73, 0x4f, 0x6e, 0x63, 0x65, 0x29, 0x20, 0x7b, 0x0a, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x74, 0x68, + 0x69, 0x73, 0x2e, 0x23, 0x66, 0x72, 0x65, 0x65, 0x7a, 0x65, + 0x55, 0x69, 0x28, 0x29, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x61, 0x6c, 0x65, 0x72, 0x74, 0x28, + 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x22, 0x53, 0x6f, 0x72, 0x72, 0x79, 0x2e, 0x20, 0x57, + 0x65, 0x62, 0x55, 0x49, 0x20, 0x66, 0x61, 0x69, 0x6c, 0x65, + 0x64, 0x20, 0x74, 0x6f, 0x20, 0x63, 0x6f, 0x6e, 0x6e, 0x65, + 0x63, 0x74, 0x20, 0x74, 0x6f, 0x20, 0x74, 0x68, 0x65, 0x20, + 0x62, 0x61, 0x63, 0x6b, 0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, + 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, + 0x6f, 0x6e, 0x2e, 0x20, 0x50, 0x6c, 0x65, 0x61, 0x73, 0x65, + 0x20, 0x74, 0x72, 0x79, 0x20, 0x61, 0x67, 0x61, 0x69, 0x6e, + 0x2e, 0x22, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x29, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x69, 0x66, 0x20, 0x28, 0x21, 0x74, 0x68, 0x69, + 0x73, 0x2e, 0x23, 0x6c, 0x6f, 0x67, 0x29, 0x0a, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x67, 0x6c, + 0x6f, 0x62, 0x61, 0x6c, 0x54, 0x68, 0x69, 0x73, 0x2e, 0x63, + 0x6c, 0x6f, 0x73, 0x65, 0x28, 0x29, 0x3b, 0x0a, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x7d, 0x0a, 0x20, 0x20, 0x20, 0x20, + 0x7d, 0x2c, 0x20, 0x31, 0x35, 0x30, 0x30, 0x29, 0x3b, 0x0a, + 0x20, 0x20, 0x7d, 0x0a, 0x20, 0x20, 0x23, 0x63, 0x6c, 0x6f, + 0x73, 0x65, 0x28, 0x72, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x20, + 0x3d, 0x20, 0x30, 0x2c, 0x20, 0x76, 0x61, 0x6c, 0x75, 0x65, + 0x20, 0x3d, 0x20, 0x22, 0x22, 0x29, 0x20, 0x7b, 0x0a, 0x20, + 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, 0x28, 0x72, 0x65, 0x61, + 0x73, 0x6f, 0x6e, 0x20, 0x3d, 0x3d, 0x3d, 0x20, 0x74, 0x68, + 0x69, 0x73, 0x2e, 0x23, 0x48, 0x45, 0x41, 0x44, 0x45, 0x52, + 0x5f, 0x53, 0x57, 0x49, 0x54, 0x43, 0x48, 0x29, 0x0a, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x74, 0x68, 0x69, 0x73, 0x2e, + 0x23, 0x73, 0x65, 0x6e, 0x64, 0x45, 0x76, 0x65, 0x6e, 0x74, + 0x4e, 0x61, 0x76, 0x69, 0x67, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x28, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x29, 0x3b, 0x0a, 0x20, + 0x20, 0x20, 0x20, 0x74, 0x68, 0x69, 0x73, 0x2e, 0x23, 0x77, + 0x73, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x20, 0x3d, 0x20, + 0x66, 0x61, 0x6c, 0x73, 0x65, 0x3b, 0x0a, 0x20, 0x20, 0x20, + 0x20, 0x74, 0x68, 0x69, 0x73, 0x2e, 0x23, 0x63, 0x6c, 0x6f, + 0x73, 0x65, 0x52, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x20, 0x3d, + 0x20, 0x72, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x3b, 0x0a, 0x20, + 0x20, 0x20, 0x20, 0x74, 0x68, 0x69, 0x73, 0x2e, 0x23, 0x63, + 0x6c, 0x6f, 0x73, 0x65, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x20, + 0x3d, 0x20, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3b, 0x0a, 0x20, + 0x20, 0x20, 0x20, 0x74, 0x68, 0x69, 0x73, 0x2e, 0x23, 0x77, + 0x73, 0x2e, 0x63, 0x6c, 0x6f, 0x73, 0x65, 0x28, 0x29, 0x3b, + 0x0a, 0x20, 0x20, 0x7d, 0x0a, 0x20, 0x20, 0x23, 0x66, 0x72, + 0x65, 0x65, 0x7a, 0x65, 0x55, 0x69, 0x28, 0x29, 0x20, 0x7b, + 0x0a, 0x20, 0x20, 0x20, 0x20, 0x64, 0x6f, 0x63, 0x75, 0x6d, + 0x65, 0x6e, 0x74, 0x2e, 0x62, 0x6f, 0x64, 0x79, 0x2e, 0x73, + 0x74, 0x79, 0x6c, 0x65, 0x2e, 0x66, 0x69, 0x6c, 0x74, 0x65, + 0x72, 0x20, 0x3d, 0x20, 0x22, 0x63, 0x6f, 0x6e, 0x74, 0x72, + 0x61, 0x73, 0x74, 0x28, 0x31, 0x25, 0x29, 0x22, 0x3b, 0x0a, + 0x20, 0x20, 0x7d, 0x0a, 0x20, 0x20, 0x23, 0x67, 0x65, 0x74, + 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x28, 0x62, 0x75, 0x66, + 0x66, 0x65, 0x72, 0x2c, 0x20, 0x73, 0x74, 0x61, 0x72, 0x74, + 0x49, 0x6e, 0x64, 0x65, 0x78, 0x29, 0x20, 0x7b, 0x0a, 0x20, + 0x20, 0x20, 0x20, 0x6c, 0x65, 0x74, 0x20, 0x73, 0x74, 0x72, + 0x69, 0x6e, 0x67, 0x42, 0x79, 0x74, 0x65, 0x73, 0x20, 0x3d, + 0x20, 0x5b, 0x5d, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x66, + 0x6f, 0x72, 0x20, 0x28, 0x6c, 0x65, 0x74, 0x20, 0x69, 0x20, + 0x3d, 0x20, 0x73, 0x74, 0x61, 0x72, 0x74, 0x49, 0x6e, 0x64, + 0x65, 0x78, 0x3b, 0x20, 0x69, 0x20, 0x3c, 0x20, 0x62, 0x75, + 0x66, 0x66, 0x65, 0x72, 0x2e, 0x6c, 0x65, 0x6e, 0x67, 0x74, + 0x68, 0x3b, 0x20, 0x69, 0x2b, 0x2b, 0x29, 0x20, 0x7b, 0x0a, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, 0x28, + 0x62, 0x75, 0x66, 0x66, 0x65, 0x72, 0x5b, 0x69, 0x5d, 0x20, + 0x3d, 0x3d, 0x3d, 0x20, 0x30, 0x29, 0x20, 0x7b, 0x0a, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x62, 0x72, 0x65, + 0x61, 0x6b, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x7d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x73, 0x74, + 0x72, 0x69, 0x6e, 0x67, 0x42, 0x79, 0x74, 0x65, 0x73, 0x2e, + 0x70, 0x75, 0x73, 0x68, 0x28, 0x62, 0x75, 0x66, 0x66, 0x65, + 0x72, 0x5b, 0x69, 0x5d, 0x29, 0x3b, 0x0a, 0x20, 0x20, 0x20, + 0x20, 0x7d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x65, 0x74, + 0x20, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x54, 0x65, 0x78, + 0x74, 0x20, 0x3d, 0x20, 0x6e, 0x65, 0x77, 0x20, 0x54, 0x65, + 0x78, 0x74, 0x44, 0x65, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x28, + 0x29, 0x2e, 0x64, 0x65, 0x63, 0x6f, 0x64, 0x65, 0x28, 0x6e, + 0x65, 0x77, 0x20, 0x55, 0x69, 0x6e, 0x74, 0x38, 0x41, 0x72, + 0x72, 0x61, 0x79, 0x28, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, + 0x42, 0x79, 0x74, 0x65, 0x73, 0x29, 0x29, 0x3b, 0x0a, 0x20, + 0x20, 0x20, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, + 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x54, 0x65, 0x78, 0x74, + 0x3b, 0x0a, 0x20, 0x20, 0x7d, 0x0a, 0x20, 0x20, 0x23, 0x73, + 0x74, 0x61, 0x72, 0x74, 0x28, 0x29, 0x20, 0x7b, 0x0a, 0x20, + 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, 0x28, 0x74, 0x68, 0x69, + 0x73, 0x2e, 0x23, 0x62, 0x69, 0x6e, 0x64, 0x4c, 0x69, 0x73, + 0x74, 0x2e, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x73, + 0x28, 0x74, 0x68, 0x69, 0x73, 0x2e, 0x23, 0x77, 0x69, 0x6e, + 0x4e, 0x75, 0x6d, 0x20, 0x2b, 0x20, 0x22, 0x2f, 0x22, 0x29, + 0x29, 0x20, 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x74, 0x68, 0x69, 0x73, 0x2e, 0x23, 0x68, 0x61, 0x73, 0x45, + 0x76, 0x65, 0x6e, 0x74, 0x73, 0x20, 0x3d, 0x20, 0x74, 0x72, + 0x75, 0x65, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x7d, 0x0a, + 0x20, 0x20, 0x20, 0x20, 0x74, 0x68, 0x69, 0x73, 0x2e, 0x23, + 0x77, 0x73, 0x20, 0x3d, 0x20, 0x6e, 0x65, 0x77, 0x20, 0x57, + 0x65, 0x62, 0x53, 0x6f, 0x63, 0x6b, 0x65, 0x74, 0x28, 0x0a, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x60, 0x77, 0x73, 0x3a, + 0x2f, 0x2f, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x68, 0x6f, 0x73, + 0x74, 0x3a, 0x24, 0x7b, 0x74, 0x68, 0x69, 0x73, 0x2e, 0x23, + 0x70, 0x6f, 0x72, 0x74, 0x7d, 0x2f, 0x5f, 0x77, 0x65, 0x62, + 0x75, 0x69, 0x5f, 0x77, 0x73, 0x5f, 0x63, 0x6f, 0x6e, 0x6e, + 0x65, 0x63, 0x74, 0x60, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x29, + 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x74, 0x68, 0x69, 0x73, + 0x2e, 0x23, 0x77, 0x73, 0x2e, 0x62, 0x69, 0x6e, 0x61, 0x72, + 0x79, 0x54, 0x79, 0x70, 0x65, 0x20, 0x3d, 0x20, 0x22, 0x61, + 0x72, 0x72, 0x61, 0x79, 0x62, 0x75, 0x66, 0x66, 0x65, 0x72, + 0x22, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x74, 0x68, 0x69, + 0x73, 0x2e, 0x23, 0x77, 0x73, 0x2e, 0x6f, 0x6e, 0x6f, 0x70, + 0x65, 0x6e, 0x20, 0x3d, 0x20, 0x28, 0x29, 0x20, 0x3d, 0x3e, + 0x20, 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x74, + 0x68, 0x69, 0x73, 0x2e, 0x23, 0x77, 0x73, 0x53, 0x74, 0x61, + 0x74, 0x75, 0x73, 0x20, 0x3d, 0x20, 0x74, 0x72, 0x75, 0x65, + 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x74, 0x68, + 0x69, 0x73, 0x2e, 0x23, 0x77, 0x73, 0x53, 0x74, 0x61, 0x74, + 0x75, 0x73, 0x4f, 0x6e, 0x63, 0x65, 0x20, 0x3d, 0x20, 0x74, + 0x72, 0x75, 0x65, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x74, 0x68, 0x69, 0x73, 0x2e, 0x23, 0x66, 0x6e, 0x49, + 0x64, 0x20, 0x3d, 0x20, 0x31, 0x3b, 0x0a, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, 0x28, 0x74, 0x68, 0x69, + 0x73, 0x2e, 0x23, 0x6c, 0x6f, 0x67, 0x29, 0x0a, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x63, 0x6f, 0x6e, 0x73, + 0x6f, 0x6c, 0x65, 0x2e, 0x6c, 0x6f, 0x67, 0x28, 0x22, 0x57, + 0x65, 0x62, 0x55, 0x49, 0x20, 0x2d, 0x3e, 0x20, 0x43, 0x6f, + 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x65, 0x64, 0x22, 0x29, 0x3b, + 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x74, 0x68, 0x69, + 0x73, 0x2e, 0x23, 0x63, 0x6c, 0x69, 0x63, 0x6b, 0x73, 0x4c, + 0x69, 0x73, 0x74, 0x65, 0x6e, 0x65, 0x72, 0x28, 0x29, 0x3b, + 0x0a, 0x20, 0x20, 0x20, 0x20, 0x7d, 0x3b, 0x0a, 0x20, 0x20, + 0x20, 0x20, 0x74, 0x68, 0x69, 0x73, 0x2e, 0x23, 0x77, 0x73, + 0x2e, 0x6f, 0x6e, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x20, 0x3d, + 0x20, 0x28, 0x29, 0x20, 0x3d, 0x3e, 0x20, 0x7b, 0x0a, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, 0x28, 0x74, + 0x68, 0x69, 0x73, 0x2e, 0x23, 0x6c, 0x6f, 0x67, 0x29, 0x0a, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x63, 0x6f, + 0x6e, 0x73, 0x6f, 0x6c, 0x65, 0x2e, 0x6c, 0x6f, 0x67, 0x28, + 0x22, 0x57, 0x65, 0x62, 0x55, 0x49, 0x20, 0x2d, 0x3e, 0x20, + 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, + 0x20, 0x46, 0x61, 0x69, 0x6c, 0x65, 0x64, 0x22, 0x29, 0x3b, + 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x74, 0x68, 0x69, + 0x73, 0x2e, 0x23, 0x66, 0x72, 0x65, 0x65, 0x7a, 0x65, 0x55, + 0x69, 0x28, 0x29, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x7d, + 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x74, 0x68, 0x69, 0x73, + 0x2e, 0x23, 0x77, 0x73, 0x2e, 0x6f, 0x6e, 0x63, 0x6c, 0x6f, + 0x73, 0x65, 0x20, 0x3d, 0x20, 0x28, 0x65, 0x76, 0x65, 0x6e, + 0x74, 0x29, 0x20, 0x3d, 0x3e, 0x20, 0x7b, 0x0a, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x74, 0x68, 0x69, 0x73, 0x2e, 0x23, + 0x77, 0x73, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x20, 0x3d, + 0x20, 0x66, 0x61, 0x6c, 0x73, 0x65, 0x3b, 0x0a, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, 0x28, 0x74, 0x68, + 0x69, 0x73, 0x2e, 0x23, 0x63, 0x6c, 0x6f, 0x73, 0x65, 0x52, + 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x20, 0x3d, 0x3d, 0x3d, 0x20, + 0x74, 0x68, 0x69, 0x73, 0x2e, 0x23, 0x48, 0x45, 0x41, 0x44, + 0x45, 0x52, 0x5f, 0x53, 0x57, 0x49, 0x54, 0x43, 0x48, 0x29, + 0x20, 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x69, 0x66, 0x20, 0x28, 0x74, 0x68, 0x69, 0x73, 0x2e, + 0x23, 0x6c, 0x6f, 0x67, 0x29, 0x20, 0x7b, 0x0a, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x63, 0x6f, + 0x6e, 0x73, 0x6f, 0x6c, 0x65, 0x2e, 0x6c, 0x6f, 0x67, 0x28, + 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x60, 0x57, 0x65, 0x62, 0x55, 0x49, 0x20, + 0x2d, 0x3e, 0x20, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, + 0x69, 0x6f, 0x6e, 0x20, 0x6c, 0x6f, 0x73, 0x74, 0x20, 0x2d, + 0x3e, 0x20, 0x4e, 0x61, 0x76, 0x69, 0x67, 0x61, 0x74, 0x69, + 0x6f, 0x6e, 0x20, 0x74, 0x6f, 0x20, 0x5b, 0x24, 0x7b, 0x74, + 0x68, 0x69, 0x73, 0x2e, 0x23, 0x63, 0x6c, 0x6f, 0x73, 0x65, + 0x56, 0x61, 0x6c, 0x75, 0x65, 0x7d, 0x5d, 0x60, 0x0a, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x29, + 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x7d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x67, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x54, 0x68, 0x69, 0x73, + 0x2e, 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, + 0x72, 0x65, 0x70, 0x6c, 0x61, 0x63, 0x65, 0x28, 0x74, 0x68, + 0x69, 0x73, 0x2e, 0x23, 0x63, 0x6c, 0x6f, 0x73, 0x65, 0x56, + 0x61, 0x6c, 0x75, 0x65, 0x29, 0x3b, 0x0a, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x7d, 0x20, 0x65, 0x6c, 0x73, 0x65, 0x20, + 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x69, 0x66, 0x20, 0x28, 0x74, 0x68, 0x69, 0x73, 0x2e, 0x23, + 0x6c, 0x6f, 0x67, 0x29, 0x20, 0x7b, 0x0a, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x63, 0x6f, 0x6e, + 0x73, 0x6f, 0x6c, 0x65, 0x2e, 0x6c, 0x6f, 0x67, 0x28, 0x60, + 0x57, 0x65, 0x62, 0x55, 0x49, 0x20, 0x2d, 0x3e, 0x20, 0x43, + 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, + 0x6c, 0x6f, 0x73, 0x74, 0x20, 0x28, 0x24, 0x7b, 0x65, 0x76, + 0x65, 0x6e, 0x74, 0x2e, 0x63, 0x6f, 0x64, 0x65, 0x7d, 0x29, + 0x60, 0x29, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x74, 0x68, 0x69, 0x73, 0x2e, 0x23, + 0x66, 0x72, 0x65, 0x65, 0x7a, 0x65, 0x55, 0x69, 0x28, 0x29, + 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x7d, 0x20, 0x65, 0x6c, 0x73, 0x65, 0x20, 0x7b, 0x0a, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x74, + 0x68, 0x69, 0x73, 0x2e, 0x23, 0x63, 0x6c, 0x6f, 0x73, 0x65, + 0x57, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x54, 0x69, 0x6d, 0x65, + 0x72, 0x28, 0x29, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x7d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x7d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x7d, 0x3b, 0x0a, + 0x20, 0x20, 0x20, 0x20, 0x74, 0x68, 0x69, 0x73, 0x2e, 0x23, + 0x77, 0x73, 0x2e, 0x6f, 0x6e, 0x6d, 0x65, 0x73, 0x73, 0x61, + 0x67, 0x65, 0x20, 0x3d, 0x20, 0x61, 0x73, 0x79, 0x6e, 0x63, + 0x20, 0x28, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x29, 0x20, 0x3d, + 0x3e, 0x20, 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x76, 0x61, 0x72, 0x20, 0x5f, 0x61, 0x2c, 0x20, 0x5f, 0x62, + 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x63, 0x6f, + 0x6e, 0x73, 0x74, 0x20, 0x62, 0x75, 0x66, 0x66, 0x65, 0x72, + 0x38, 0x20, 0x3d, 0x20, 0x6e, 0x65, 0x77, 0x20, 0x55, 0x69, + 0x6e, 0x74, 0x38, 0x41, 0x72, 0x72, 0x61, 0x79, 0x28, 0x65, + 0x76, 0x65, 0x6e, 0x74, 0x2e, 0x64, 0x61, 0x74, 0x61, 0x29, + 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, + 0x20, 0x28, 0x62, 0x75, 0x66, 0x66, 0x65, 0x72, 0x38, 0x2e, + 0x6c, 0x65, 0x6e, 0x67, 0x74, 0x68, 0x20, 0x3c, 0x20, 0x34, + 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x3b, 0x0a, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, 0x28, 0x62, 0x75, + 0x66, 0x66, 0x65, 0x72, 0x38, 0x5b, 0x30, 0x5d, 0x20, 0x21, + 0x3d, 0x3d, 0x20, 0x74, 0x68, 0x69, 0x73, 0x2e, 0x23, 0x48, + 0x45, 0x41, 0x44, 0x45, 0x52, 0x5f, 0x53, 0x49, 0x47, 0x4e, + 0x41, 0x54, 0x55, 0x52, 0x45, 0x29, 0x0a, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, + 0x6e, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x69, + 0x66, 0x20, 0x28, 0x62, 0x75, 0x66, 0x66, 0x65, 0x72, 0x38, + 0x5b, 0x31, 0x5d, 0x20, 0x21, 0x3d, 0x3d, 0x20, 0x74, 0x68, + 0x69, 0x73, 0x2e, 0x23, 0x48, 0x45, 0x41, 0x44, 0x45, 0x52, + 0x5f, 0x53, 0x45, 0x4e, 0x44, 0x5f, 0x52, 0x41, 0x57, 0x29, + 0x20, 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x63, 0x6f, 0x6e, 0x73, 0x74, 0x20, 0x64, 0x61, 0x74, + 0x61, 0x38, 0x20, 0x3d, 0x20, 0x62, 0x75, 0x66, 0x66, 0x65, + 0x72, 0x38, 0x5b, 0x62, 0x75, 0x66, 0x66, 0x65, 0x72, 0x38, + 0x2e, 0x6c, 0x65, 0x6e, 0x67, 0x74, 0x68, 0x20, 0x2d, 0x20, + 0x31, 0x5d, 0x20, 0x3d, 0x3d, 0x3d, 0x20, 0x30, 0x20, 0x3f, + 0x20, 0x62, 0x75, 0x66, 0x66, 0x65, 0x72, 0x38, 0x2e, 0x73, + 0x6c, 0x69, 0x63, 0x65, 0x28, 0x33, 0x2c, 0x20, 0x2d, 0x31, + 0x29, 0x20, 0x3a, 0x20, 0x62, 0x75, 0x66, 0x66, 0x65, 0x72, + 0x38, 0x2e, 0x73, 0x6c, 0x69, 0x63, 0x65, 0x28, 0x33, 0x29, + 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x63, 0x6f, 0x6e, 0x73, 0x74, 0x20, 0x64, 0x61, 0x74, 0x61, + 0x38, 0x75, 0x74, 0x66, 0x38, 0x20, 0x3d, 0x20, 0x6e, 0x65, + 0x77, 0x20, 0x54, 0x65, 0x78, 0x74, 0x44, 0x65, 0x63, 0x6f, + 0x64, 0x65, 0x72, 0x28, 0x29, 0x2e, 0x64, 0x65, 0x63, 0x6f, + 0x64, 0x65, 0x28, 0x64, 0x61, 0x74, 0x61, 0x38, 0x29, 0x3b, + 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x73, + 0x77, 0x69, 0x74, 0x63, 0x68, 0x20, 0x28, 0x62, 0x75, 0x66, + 0x66, 0x65, 0x72, 0x38, 0x5b, 0x31, 0x5d, 0x29, 0x20, 0x7b, + 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x63, 0x61, 0x73, 0x65, 0x20, 0x74, 0x68, 0x69, 0x73, + 0x2e, 0x23, 0x48, 0x45, 0x41, 0x44, 0x45, 0x52, 0x5f, 0x43, + 0x41, 0x4c, 0x4c, 0x5f, 0x46, 0x55, 0x4e, 0x43, 0x3a, 0x0a, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x63, 0x6f, + 0x6e, 0x73, 0x74, 0x20, 0x63, 0x61, 0x6c, 0x6c, 0x49, 0x64, + 0x20, 0x3d, 0x20, 0x62, 0x75, 0x66, 0x66, 0x65, 0x72, 0x38, + 0x5b, 0x32, 0x5d, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x69, + 0x66, 0x20, 0x28, 0x74, 0x68, 0x69, 0x73, 0x2e, 0x23, 0x6c, + 0x6f, 0x67, 0x29, 0x20, 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x63, 0x6f, 0x6e, 0x73, 0x6f, 0x6c, 0x65, 0x2e, + 0x6c, 0x6f, 0x67, 0x28, 0x60, 0x57, 0x65, 0x62, 0x55, 0x49, + 0x20, 0x2d, 0x3e, 0x20, 0x46, 0x75, 0x6e, 0x63, 0x20, 0x52, + 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x20, 0x5b, 0x24, + 0x7b, 0x64, 0x61, 0x74, 0x61, 0x38, 0x75, 0x74, 0x66, 0x38, + 0x7d, 0x5d, 0x60, 0x29, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x7d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, 0x28, + 0x74, 0x68, 0x69, 0x73, 0x2e, 0x23, 0x66, 0x6e, 0x50, 0x72, + 0x6f, 0x6d, 0x69, 0x73, 0x65, 0x52, 0x65, 0x73, 0x6f, 0x6c, + 0x76, 0x65, 0x5b, 0x63, 0x61, 0x6c, 0x6c, 0x49, 0x64, 0x5d, + 0x29, 0x20, 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x69, 0x66, 0x20, 0x28, 0x74, 0x68, 0x69, 0x73, 0x2e, 0x23, + 0x6c, 0x6f, 0x67, 0x29, 0x20, 0x7b, 0x0a, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x63, 0x6f, 0x6e, 0x73, 0x6f, + 0x6c, 0x65, 0x2e, 0x6c, 0x6f, 0x67, 0x28, 0x0a, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x60, 0x57, + 0x65, 0x62, 0x55, 0x49, 0x20, 0x2d, 0x3e, 0x20, 0x52, 0x65, + 0x73, 0x6f, 0x6c, 0x76, 0x69, 0x6e, 0x67, 0x20, 0x52, 0x65, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x20, 0x23, 0x24, 0x7b, + 0x63, 0x61, 0x6c, 0x6c, 0x49, 0x64, 0x7d, 0x2e, 0x2e, 0x2e, + 0x60, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x29, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7d, + 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x28, 0x5f, 0x62, + 0x20, 0x3d, 0x20, 0x28, 0x5f, 0x61, 0x20, 0x3d, 0x20, 0x74, + 0x68, 0x69, 0x73, 0x2e, 0x23, 0x66, 0x6e, 0x50, 0x72, 0x6f, + 0x6d, 0x69, 0x73, 0x65, 0x52, 0x65, 0x73, 0x6f, 0x6c, 0x76, + 0x65, 0x29, 0x5b, 0x63, 0x61, 0x6c, 0x6c, 0x49, 0x64, 0x5d, + 0x29, 0x20, 0x3d, 0x3d, 0x20, 0x6e, 0x75, 0x6c, 0x6c, 0x20, + 0x3f, 0x20, 0x76, 0x6f, 0x69, 0x64, 0x20, 0x30, 0x20, 0x3a, + 0x20, 0x5f, 0x62, 0x2e, 0x63, 0x61, 0x6c, 0x6c, 0x28, 0x5f, + 0x61, 0x2c, 0x20, 0x64, 0x61, 0x74, 0x61, 0x38, 0x75, 0x74, + 0x66, 0x38, 0x29, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x74, 0x68, 0x69, 0x73, 0x2e, 0x23, 0x66, 0x6e, 0x50, + 0x72, 0x6f, 0x6d, 0x69, 0x73, 0x65, 0x52, 0x65, 0x73, 0x6f, + 0x6c, 0x76, 0x65, 0x5b, 0x63, 0x61, 0x6c, 0x6c, 0x49, 0x64, + 0x5d, 0x20, 0x3d, 0x20, 0x76, 0x6f, 0x69, 0x64, 0x20, 0x30, + 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7d, 0x0a, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x7d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x62, 0x72, 0x65, 0x61, 0x6b, 0x3b, + 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x63, 0x61, 0x73, 0x65, 0x20, 0x74, 0x68, 0x69, 0x73, + 0x2e, 0x23, 0x48, 0x45, 0x41, 0x44, 0x45, 0x52, 0x5f, 0x53, + 0x57, 0x49, 0x54, 0x43, 0x48, 0x3a, 0x0a, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x74, + 0x68, 0x69, 0x73, 0x2e, 0x23, 0x63, 0x6c, 0x6f, 0x73, 0x65, + 0x28, 0x74, 0x68, 0x69, 0x73, 0x2e, 0x23, 0x48, 0x45, 0x41, + 0x44, 0x45, 0x52, 0x5f, 0x53, 0x57, 0x49, 0x54, 0x43, 0x48, + 0x2c, 0x20, 0x64, 0x61, 0x74, 0x61, 0x38, 0x75, 0x74, 0x66, + 0x38, 0x29, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x62, 0x72, 0x65, 0x61, + 0x6b, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x63, 0x61, 0x73, 0x65, 0x20, 0x74, 0x68, + 0x69, 0x73, 0x2e, 0x23, 0x48, 0x45, 0x41, 0x44, 0x45, 0x52, + 0x5f, 0x43, 0x4c, 0x4f, 0x53, 0x45, 0x3a, 0x0a, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x67, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x54, 0x68, 0x69, 0x73, + 0x2e, 0x63, 0x6c, 0x6f, 0x73, 0x65, 0x28, 0x29, 0x3b, 0x0a, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x62, 0x72, 0x65, 0x61, 0x6b, 0x3b, 0x0a, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x63, + 0x61, 0x73, 0x65, 0x20, 0x74, 0x68, 0x69, 0x73, 0x2e, 0x23, + 0x48, 0x45, 0x41, 0x44, 0x45, 0x52, 0x5f, 0x4a, 0x53, 0x5f, + 0x51, 0x55, 0x49, 0x43, 0x4b, 0x3a, 0x0a, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x63, 0x61, 0x73, + 0x65, 0x20, 0x74, 0x68, 0x69, 0x73, 0x2e, 0x23, 0x48, 0x45, + 0x41, 0x44, 0x45, 0x52, 0x5f, 0x4a, 0x53, 0x3a, 0x0a, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x63, 0x6f, 0x6e, + 0x73, 0x74, 0x20, 0x64, 0x61, 0x74, 0x61, 0x38, 0x75, 0x74, + 0x66, 0x38, 0x73, 0x61, 0x6e, 0x69, 0x74, 0x69, 0x7a, 0x65, + 0x20, 0x3d, 0x20, 0x64, 0x61, 0x74, 0x61, 0x38, 0x75, 0x74, + 0x66, 0x38, 0x2e, 0x72, 0x65, 0x70, 0x6c, 0x61, 0x63, 0x65, + 0x28, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x2f, 0x28, + 0x3f, 0x3a, 0x5c, 0x72, 0x5c, 0x6e, 0x7c, 0x5c, 0x72, 0x7c, + 0x5c, 0x6e, 0x29, 0x2f, 0x67, 0x2c, 0x0a, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x22, 0x5c, 0x6e, 0x22, 0x0a, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x29, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x69, + 0x66, 0x20, 0x28, 0x74, 0x68, 0x69, 0x73, 0x2e, 0x23, 0x6c, + 0x6f, 0x67, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x63, 0x6f, 0x6e, 0x73, 0x6f, 0x6c, 0x65, 0x2e, 0x6c, 0x6f, + 0x67, 0x28, 0x60, 0x57, 0x65, 0x62, 0x55, 0x49, 0x20, 0x2d, + 0x3e, 0x20, 0x4a, 0x53, 0x20, 0x5b, 0x24, 0x7b, 0x64, 0x61, + 0x74, 0x61, 0x38, 0x75, 0x74, 0x66, 0x38, 0x73, 0x61, 0x6e, + 0x69, 0x74, 0x69, 0x7a, 0x65, 0x7d, 0x5d, 0x60, 0x29, 0x3b, + 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x65, 0x74, 0x20, 0x46, + 0x75, 0x6e, 0x52, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x3d, + 0x20, 0x22, 0x75, 0x6e, 0x64, 0x65, 0x66, 0x69, 0x6e, 0x65, + 0x64, 0x22, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x65, + 0x74, 0x20, 0x46, 0x75, 0x6e, 0x45, 0x72, 0x72, 0x6f, 0x72, + 0x20, 0x3d, 0x20, 0x66, 0x61, 0x6c, 0x73, 0x65, 0x3b, 0x0a, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x74, 0x72, 0x79, 0x20, 0x7b, 0x0a, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x46, 0x75, 0x6e, 0x52, + 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x3d, 0x20, 0x61, 0x77, + 0x61, 0x69, 0x74, 0x20, 0x41, 0x73, 0x79, 0x6e, 0x63, 0x46, + 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x64, 0x61, + 0x74, 0x61, 0x38, 0x75, 0x74, 0x66, 0x38, 0x73, 0x61, 0x6e, + 0x69, 0x74, 0x69, 0x7a, 0x65, 0x29, 0x28, 0x29, 0x3b, 0x0a, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x7d, 0x20, 0x63, 0x61, 0x74, 0x63, + 0x68, 0x20, 0x28, 0x65, 0x29, 0x20, 0x7b, 0x0a, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x46, 0x75, 0x6e, 0x45, 0x72, 0x72, + 0x6f, 0x72, 0x20, 0x3d, 0x20, 0x74, 0x72, 0x75, 0x65, 0x3b, + 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x46, 0x75, 0x6e, + 0x52, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x3d, 0x20, 0x65, + 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x3b, 0x0a, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x7d, 0x0a, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x69, 0x66, 0x20, 0x28, 0x62, 0x75, 0x66, 0x66, 0x65, 0x72, + 0x38, 0x5b, 0x31, 0x5d, 0x20, 0x3d, 0x3d, 0x3d, 0x20, 0x74, + 0x68, 0x69, 0x73, 0x2e, 0x23, 0x48, 0x45, 0x41, 0x44, 0x45, + 0x52, 0x5f, 0x4a, 0x53, 0x5f, 0x51, 0x55, 0x49, 0x43, 0x4b, + 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, + 0x74, 0x75, 0x72, 0x6e, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x69, 0x66, 0x20, 0x28, 0x46, 0x75, 0x6e, 0x52, 0x65, 0x74, + 0x75, 0x72, 0x6e, 0x20, 0x3d, 0x3d, 0x3d, 0x20, 0x76, 0x6f, + 0x69, 0x64, 0x20, 0x30, 0x29, 0x20, 0x7b, 0x0a, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x46, 0x75, 0x6e, 0x52, 0x65, 0x74, + 0x75, 0x72, 0x6e, 0x20, 0x3d, 0x20, 0x22, 0x75, 0x6e, 0x64, + 0x65, 0x66, 0x69, 0x6e, 0x65, 0x64, 0x22, 0x3b, 0x0a, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x7d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x69, + 0x66, 0x20, 0x28, 0x74, 0x68, 0x69, 0x73, 0x2e, 0x23, 0x6c, + 0x6f, 0x67, 0x20, 0x26, 0x26, 0x20, 0x21, 0x46, 0x75, 0x6e, + 0x45, 0x72, 0x72, 0x6f, 0x72, 0x29, 0x0a, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x63, 0x6f, 0x6e, 0x73, 0x6f, 0x6c, 0x65, + 0x2e, 0x6c, 0x6f, 0x67, 0x28, 0x60, 0x57, 0x65, 0x62, 0x55, + 0x49, 0x20, 0x2d, 0x3e, 0x20, 0x4a, 0x53, 0x20, 0x2d, 0x3e, + 0x20, 0x52, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x5b, 0x24, + 0x7b, 0x46, 0x75, 0x6e, 0x52, 0x65, 0x74, 0x75, 0x72, 0x6e, + 0x7d, 0x5d, 0x60, 0x29, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x69, 0x66, 0x20, 0x28, 0x74, 0x68, 0x69, 0x73, 0x2e, 0x23, + 0x6c, 0x6f, 0x67, 0x20, 0x26, 0x26, 0x20, 0x46, 0x75, 0x6e, + 0x45, 0x72, 0x72, 0x6f, 0x72, 0x29, 0x0a, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x63, 0x6f, 0x6e, 0x73, 0x6f, 0x6c, 0x65, + 0x2e, 0x6c, 0x6f, 0x67, 0x28, 0x60, 0x57, 0x65, 0x62, 0x55, + 0x49, 0x20, 0x2d, 0x3e, 0x20, 0x4a, 0x53, 0x20, 0x2d, 0x3e, + 0x20, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x20, 0x5b, 0x24, 0x7b, + 0x46, 0x75, 0x6e, 0x52, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x7d, + 0x5d, 0x60, 0x29, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x63, + 0x6f, 0x6e, 0x73, 0x74, 0x20, 0x52, 0x65, 0x74, 0x75, 0x72, + 0x6e, 0x38, 0x20, 0x3d, 0x20, 0x55, 0x69, 0x6e, 0x74, 0x38, + 0x41, 0x72, 0x72, 0x61, 0x79, 0x2e, 0x6f, 0x66, 0x28, 0x0a, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x74, 0x68, 0x69, 0x73, + 0x2e, 0x23, 0x48, 0x45, 0x41, 0x44, 0x45, 0x52, 0x5f, 0x53, + 0x49, 0x47, 0x4e, 0x41, 0x54, 0x55, 0x52, 0x45, 0x2c, 0x0a, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x74, 0x68, 0x69, 0x73, + 0x2e, 0x23, 0x48, 0x45, 0x41, 0x44, 0x45, 0x52, 0x5f, 0x4a, + 0x53, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x62, + 0x75, 0x66, 0x66, 0x65, 0x72, 0x38, 0x5b, 0x32, 0x5d, 0x2c, + 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x46, 0x75, 0x6e, + 0x45, 0x72, 0x72, 0x6f, 0x72, 0x20, 0x3f, 0x20, 0x30, 0x20, + 0x3a, 0x20, 0x31, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x2e, 0x2e, 0x2e, 0x6e, 0x65, 0x77, 0x20, 0x54, 0x65, + 0x78, 0x74, 0x45, 0x6e, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x28, + 0x29, 0x2e, 0x65, 0x6e, 0x63, 0x6f, 0x64, 0x65, 0x28, 0x46, + 0x75, 0x6e, 0x52, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x29, 0x0a, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x29, 0x3b, 0x0a, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x69, 0x66, 0x20, 0x28, 0x74, 0x68, 0x69, 0x73, 0x2e, + 0x23, 0x77, 0x73, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x29, + 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x74, 0x68, 0x69, + 0x73, 0x2e, 0x23, 0x77, 0x73, 0x2e, 0x73, 0x65, 0x6e, 0x64, + 0x28, 0x52, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x38, 0x2e, 0x62, + 0x75, 0x66, 0x66, 0x65, 0x72, 0x29, 0x3b, 0x0a, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x7d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x62, 0x72, 0x65, 0x61, 0x6b, 0x3b, + 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7d, + 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7d, 0x20, 0x65, + 0x6c, 0x73, 0x65, 0x20, 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x73, 0x77, 0x69, 0x74, 0x63, 0x68, + 0x20, 0x28, 0x62, 0x75, 0x66, 0x66, 0x65, 0x72, 0x38, 0x5b, + 0x31, 0x5d, 0x29, 0x20, 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x63, 0x61, 0x73, 0x65, + 0x20, 0x74, 0x68, 0x69, 0x73, 0x2e, 0x23, 0x48, 0x45, 0x41, + 0x44, 0x45, 0x52, 0x5f, 0x53, 0x45, 0x4e, 0x44, 0x5f, 0x52, + 0x41, 0x57, 0x3a, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7b, 0x0a, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x63, 0x6f, 0x6e, 0x73, 0x74, 0x20, 0x66, 0x75, + 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x4e, 0x61, 0x6d, 0x65, + 0x20, 0x3d, 0x20, 0x74, 0x68, 0x69, 0x73, 0x2e, 0x23, 0x67, + 0x65, 0x74, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x28, 0x62, + 0x75, 0x66, 0x66, 0x65, 0x72, 0x38, 0x2c, 0x20, 0x33, 0x29, + 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x63, 0x6f, 0x6e, 0x73, + 0x74, 0x20, 0x72, 0x61, 0x77, 0x44, 0x61, 0x74, 0x61, 0x49, + 0x6e, 0x64, 0x65, 0x78, 0x20, 0x3d, 0x20, 0x33, 0x20, 0x2b, + 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x4e, + 0x61, 0x6d, 0x65, 0x2e, 0x6c, 0x65, 0x6e, 0x67, 0x74, 0x68, + 0x20, 0x2b, 0x20, 0x31, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x63, 0x6f, 0x6e, 0x73, 0x74, 0x20, 0x75, 0x73, 0x65, 0x72, + 0x52, 0x61, 0x77, 0x44, 0x61, 0x74, 0x61, 0x20, 0x3d, 0x20, + 0x62, 0x75, 0x66, 0x66, 0x65, 0x72, 0x38, 0x2e, 0x73, 0x75, + 0x62, 0x61, 0x72, 0x72, 0x61, 0x79, 0x28, 0x72, 0x61, 0x77, + 0x44, 0x61, 0x74, 0x61, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x29, + 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, 0x28, + 0x74, 0x79, 0x70, 0x65, 0x6f, 0x66, 0x20, 0x77, 0x69, 0x6e, + 0x64, 0x6f, 0x77, 0x5b, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, + 0x6f, 0x6e, 0x4e, 0x61, 0x6d, 0x65, 0x5d, 0x20, 0x3d, 0x3d, + 0x3d, 0x20, 0x22, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, + 0x6e, 0x22, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x77, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x5b, 0x66, 0x75, 0x6e, + 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x4e, 0x61, 0x6d, 0x65, 0x5d, + 0x28, 0x75, 0x73, 0x65, 0x72, 0x52, 0x61, 0x77, 0x44, 0x61, + 0x74, 0x61, 0x29, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x65, + 0x6c, 0x73, 0x65, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x61, 0x77, 0x61, 0x69, 0x74, 0x20, 0x41, 0x73, 0x79, 0x6e, + 0x63, 0x46, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, + 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x4e, 0x61, + 0x6d, 0x65, 0x20, 0x2b, 0x20, 0x22, 0x28, 0x75, 0x73, 0x65, + 0x72, 0x52, 0x61, 0x77, 0x44, 0x61, 0x74, 0x61, 0x29, 0x3b, + 0x22, 0x29, 0x28, 0x29, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7d, 0x0a, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x62, 0x72, 0x65, 0x61, 0x6b, 0x3b, 0x0a, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7d, 0x0a, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x7d, 0x0a, 0x20, 0x20, 0x20, + 0x20, 0x7d, 0x3b, 0x0a, 0x20, 0x20, 0x7d, 0x0a, 0x20, 0x20, + 0x23, 0x63, 0x6c, 0x69, 0x63, 0x6b, 0x73, 0x4c, 0x69, 0x73, + 0x74, 0x65, 0x6e, 0x65, 0x72, 0x28, 0x29, 0x20, 0x7b, 0x0a, + 0x20, 0x20, 0x20, 0x20, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, + 0x2e, 0x6b, 0x65, 0x79, 0x73, 0x28, 0x77, 0x69, 0x6e, 0x64, + 0x6f, 0x77, 0x29, 0x2e, 0x66, 0x6f, 0x72, 0x45, 0x61, 0x63, + 0x68, 0x28, 0x28, 0x6b, 0x65, 0x79, 0x29, 0x20, 0x3d, 0x3e, + 0x20, 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x69, + 0x66, 0x20, 0x28, 0x2f, 0x5e, 0x6f, 0x6e, 0x28, 0x63, 0x6c, + 0x69, 0x63, 0x6b, 0x29, 0x2f, 0x2e, 0x74, 0x65, 0x73, 0x74, + 0x28, 0x6b, 0x65, 0x79, 0x29, 0x29, 0x20, 0x7b, 0x0a, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x67, 0x6c, 0x6f, + 0x62, 0x61, 0x6c, 0x54, 0x68, 0x69, 0x73, 0x2e, 0x61, 0x64, + 0x64, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x4c, 0x69, 0x73, 0x74, + 0x65, 0x6e, 0x65, 0x72, 0x28, 0x6b, 0x65, 0x79, 0x2e, 0x73, + 0x6c, 0x69, 0x63, 0x65, 0x28, 0x32, 0x29, 0x2c, 0x20, 0x28, + 0x65, 0x76, 0x65, 0x6e, 0x74, 0x29, 0x20, 0x3d, 0x3e, 0x20, + 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x76, 0x61, 0x72, 0x20, 0x5f, 0x61, 0x3b, 0x0a, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x69, 0x66, 0x20, 0x28, 0x21, 0x28, 0x65, 0x76, 0x65, 0x6e, + 0x74, 0x2e, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x20, 0x69, + 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x6f, 0x66, 0x20, + 0x48, 0x54, 0x4d, 0x4c, 0x45, 0x6c, 0x65, 0x6d, 0x65, 0x6e, + 0x74, 0x29, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x74, 0x75, + 0x72, 0x6e, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, 0x28, 0x74, 0x68, + 0x69, 0x73, 0x2e, 0x23, 0x68, 0x61, 0x73, 0x45, 0x76, 0x65, + 0x6e, 0x74, 0x73, 0x20, 0x7c, 0x7c, 0x20, 0x65, 0x76, 0x65, + 0x6e, 0x74, 0x2e, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x2e, + 0x69, 0x64, 0x20, 0x21, 0x3d, 0x3d, 0x20, 0x22, 0x22, 0x20, + 0x26, 0x26, 0x20, 0x74, 0x68, 0x69, 0x73, 0x2e, 0x23, 0x62, + 0x69, 0x6e, 0x64, 0x4c, 0x69, 0x73, 0x74, 0x2e, 0x69, 0x6e, + 0x63, 0x6c, 0x75, 0x64, 0x65, 0x73, 0x28, 0x0a, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x74, 0x68, 0x69, 0x73, 0x2e, 0x23, 0x77, 0x69, 0x6e, 0x4e, + 0x75, 0x6d, 0x20, 0x2b, 0x20, 0x22, 0x2f, 0x22, 0x20, 0x2b, + 0x20, 0x28, 0x28, 0x5f, 0x61, 0x20, 0x3d, 0x20, 0x65, 0x76, + 0x65, 0x6e, 0x74, 0x2e, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, + 0x29, 0x20, 0x3d, 0x3d, 0x20, 0x6e, 0x75, 0x6c, 0x6c, 0x20, + 0x3f, 0x20, 0x76, 0x6f, 0x69, 0x64, 0x20, 0x30, 0x20, 0x3a, + 0x20, 0x5f, 0x61, 0x2e, 0x69, 0x64, 0x29, 0x0a, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x29, 0x29, + 0x20, 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x74, 0x68, 0x69, 0x73, 0x2e, + 0x23, 0x73, 0x65, 0x6e, 0x64, 0x43, 0x6c, 0x69, 0x63, 0x6b, + 0x28, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x2e, 0x74, 0x61, 0x72, + 0x67, 0x65, 0x74, 0x2e, 0x69, 0x64, 0x29, 0x3b, 0x0a, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7d, + 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7d, + 0x29, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7d, + 0x0a, 0x20, 0x20, 0x20, 0x20, 0x7d, 0x29, 0x3b, 0x0a, 0x20, + 0x20, 0x7d, 0x0a, 0x20, 0x20, 0x23, 0x73, 0x65, 0x6e, 0x64, + 0x43, 0x6c, 0x69, 0x63, 0x6b, 0x28, 0x65, 0x6c, 0x65, 0x6d, + 0x29, 0x20, 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, + 0x20, 0x28, 0x74, 0x68, 0x69, 0x73, 0x2e, 0x23, 0x77, 0x73, + 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x29, 0x20, 0x7b, 0x0a, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x63, 0x6f, 0x6e, 0x73, + 0x74, 0x20, 0x70, 0x61, 0x63, 0x6b, 0x65, 0x74, 0x20, 0x3d, + 0x20, 0x65, 0x6c, 0x65, 0x6d, 0x20, 0x21, 0x3d, 0x3d, 0x20, + 0x22, 0x22, 0x20, 0x3f, 0x20, 0x55, 0x69, 0x6e, 0x74, 0x38, + 0x41, 0x72, 0x72, 0x61, 0x79, 0x2e, 0x6f, 0x66, 0x28, 0x0a, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x74, 0x68, + 0x69, 0x73, 0x2e, 0x23, 0x48, 0x45, 0x41, 0x44, 0x45, 0x52, + 0x5f, 0x53, 0x49, 0x47, 0x4e, 0x41, 0x54, 0x55, 0x52, 0x45, + 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x74, 0x68, 0x69, 0x73, 0x2e, 0x23, 0x48, 0x45, 0x41, 0x44, + 0x45, 0x52, 0x5f, 0x43, 0x4c, 0x49, 0x43, 0x4b, 0x2c, 0x0a, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x30, 0x2c, + 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x2e, + 0x2e, 0x2e, 0x6e, 0x65, 0x77, 0x20, 0x54, 0x65, 0x78, 0x74, + 0x45, 0x6e, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x28, 0x29, 0x2e, + 0x65, 0x6e, 0x63, 0x6f, 0x64, 0x65, 0x28, 0x65, 0x6c, 0x65, + 0x6d, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x29, + 0x20, 0x3a, 0x20, 0x55, 0x69, 0x6e, 0x74, 0x38, 0x41, 0x72, + 0x72, 0x61, 0x79, 0x2e, 0x6f, 0x66, 0x28, 0x0a, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x74, 0x68, 0x69, 0x73, + 0x2e, 0x23, 0x48, 0x45, 0x41, 0x44, 0x45, 0x52, 0x5f, 0x53, + 0x49, 0x47, 0x4e, 0x41, 0x54, 0x55, 0x52, 0x45, 0x2c, 0x0a, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x74, 0x68, + 0x69, 0x73, 0x2e, 0x23, 0x48, 0x45, 0x41, 0x44, 0x45, 0x52, + 0x5f, 0x43, 0x4c, 0x49, 0x43, 0x4b, 0x2c, 0x0a, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x30, 0x2c, 0x0a, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x30, 0x0a, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x29, 0x3b, 0x0a, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x74, 0x68, 0x69, 0x73, 0x2e, 0x23, + 0x77, 0x73, 0x2e, 0x73, 0x65, 0x6e, 0x64, 0x28, 0x70, 0x61, + 0x63, 0x6b, 0x65, 0x74, 0x2e, 0x62, 0x75, 0x66, 0x66, 0x65, + 0x72, 0x29, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x69, 0x66, 0x20, 0x28, 0x74, 0x68, 0x69, 0x73, 0x2e, 0x23, + 0x6c, 0x6f, 0x67, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x63, 0x6f, 0x6e, 0x73, 0x6f, 0x6c, 0x65, + 0x2e, 0x6c, 0x6f, 0x67, 0x28, 0x60, 0x57, 0x65, 0x62, 0x55, + 0x49, 0x20, 0x2d, 0x3e, 0x20, 0x43, 0x6c, 0x69, 0x63, 0x6b, + 0x20, 0x5b, 0x24, 0x7b, 0x65, 0x6c, 0x65, 0x6d, 0x7d, 0x5d, + 0x60, 0x29, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x7d, 0x0a, + 0x20, 0x20, 0x7d, 0x0a, 0x20, 0x20, 0x23, 0x73, 0x65, 0x6e, + 0x64, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x4e, 0x61, 0x76, 0x69, + 0x67, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x75, 0x72, 0x6c, + 0x29, 0x20, 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, + 0x20, 0x28, 0x74, 0x68, 0x69, 0x73, 0x2e, 0x23, 0x68, 0x61, + 0x73, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x20, 0x26, 0x26, + 0x20, 0x74, 0x68, 0x69, 0x73, 0x2e, 0x23, 0x77, 0x73, 0x53, + 0x74, 0x61, 0x74, 0x75, 0x73, 0x20, 0x26, 0x26, 0x20, 0x75, + 0x72, 0x6c, 0x20, 0x21, 0x3d, 0x3d, 0x20, 0x22, 0x22, 0x29, + 0x20, 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x63, + 0x6f, 0x6e, 0x73, 0x74, 0x20, 0x70, 0x61, 0x63, 0x6b, 0x65, + 0x74, 0x20, 0x3d, 0x20, 0x55, 0x69, 0x6e, 0x74, 0x38, 0x41, + 0x72, 0x72, 0x61, 0x79, 0x2e, 0x6f, 0x66, 0x28, 0x0a, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x74, 0x68, 0x69, + 0x73, 0x2e, 0x23, 0x48, 0x45, 0x41, 0x44, 0x45, 0x52, 0x5f, + 0x53, 0x49, 0x47, 0x4e, 0x41, 0x54, 0x55, 0x52, 0x45, 0x2c, + 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x74, + 0x68, 0x69, 0x73, 0x2e, 0x23, 0x48, 0x45, 0x41, 0x44, 0x45, + 0x52, 0x5f, 0x53, 0x57, 0x49, 0x54, 0x43, 0x48, 0x2c, 0x0a, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x2e, 0x2e, + 0x2e, 0x6e, 0x65, 0x77, 0x20, 0x54, 0x65, 0x78, 0x74, 0x45, + 0x6e, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x28, 0x29, 0x2e, 0x65, + 0x6e, 0x63, 0x6f, 0x64, 0x65, 0x28, 0x75, 0x72, 0x6c, 0x29, + 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x29, 0x3b, 0x0a, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x74, 0x68, 0x69, 0x73, + 0x2e, 0x23, 0x77, 0x73, 0x2e, 0x73, 0x65, 0x6e, 0x64, 0x28, + 0x70, 0x61, 0x63, 0x6b, 0x65, 0x74, 0x2e, 0x62, 0x75, 0x66, + 0x66, 0x65, 0x72, 0x29, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x69, 0x66, 0x20, 0x28, 0x74, 0x68, 0x69, 0x73, + 0x2e, 0x23, 0x6c, 0x6f, 0x67, 0x29, 0x0a, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x63, 0x6f, 0x6e, 0x73, 0x6f, + 0x6c, 0x65, 0x2e, 0x6c, 0x6f, 0x67, 0x28, 0x60, 0x57, 0x65, + 0x62, 0x55, 0x49, 0x20, 0x2d, 0x3e, 0x20, 0x4e, 0x61, 0x76, + 0x69, 0x67, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x5b, 0x24, + 0x7b, 0x75, 0x72, 0x6c, 0x7d, 0x5d, 0x60, 0x29, 0x3b, 0x0a, + 0x20, 0x20, 0x20, 0x20, 0x7d, 0x0a, 0x20, 0x20, 0x7d, 0x0a, + 0x20, 0x20, 0x23, 0x69, 0x73, 0x45, 0x78, 0x74, 0x65, 0x72, + 0x6e, 0x61, 0x6c, 0x4c, 0x69, 0x6e, 0x6b, 0x28, 0x75, 0x72, + 0x6c, 0x29, 0x20, 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x72, + 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x6e, 0x65, 0x77, 0x20, + 0x55, 0x52, 0x4c, 0x28, 0x75, 0x72, 0x6c, 0x29, 0x2e, 0x68, + 0x6f, 0x73, 0x74, 0x20, 0x3d, 0x3d, 0x3d, 0x20, 0x67, 0x6c, + 0x6f, 0x62, 0x61, 0x6c, 0x54, 0x68, 0x69, 0x73, 0x2e, 0x6c, + 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x68, 0x6f, + 0x73, 0x74, 0x3b, 0x0a, 0x20, 0x20, 0x7d, 0x0a, 0x20, 0x20, + 0x23, 0x63, 0x6c, 0x6f, 0x73, 0x65, 0x57, 0x69, 0x6e, 0x64, + 0x6f, 0x77, 0x54, 0x69, 0x6d, 0x65, 0x72, 0x28, 0x29, 0x20, + 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x73, 0x65, 0x74, 0x54, + 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x28, 0x66, 0x75, 0x6e, + 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x29, 0x20, 0x7b, 0x0a, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x67, 0x6c, 0x6f, 0x62, + 0x61, 0x6c, 0x54, 0x68, 0x69, 0x73, 0x2e, 0x63, 0x6c, 0x6f, + 0x73, 0x65, 0x28, 0x29, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, + 0x7d, 0x2c, 0x20, 0x31, 0x65, 0x33, 0x29, 0x3b, 0x0a, 0x20, + 0x20, 0x7d, 0x0a, 0x20, 0x20, 0x23, 0x66, 0x6e, 0x50, 0x72, + 0x6f, 0x6d, 0x69, 0x73, 0x65, 0x28, 0x66, 0x6e, 0x2c, 0x20, + 0x76, 0x61, 0x6c, 0x75, 0x65, 0x29, 0x20, 0x7b, 0x0a, 0x20, + 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, 0x28, 0x74, 0x68, 0x69, + 0x73, 0x2e, 0x23, 0x6c, 0x6f, 0x67, 0x29, 0x0a, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x63, 0x6f, 0x6e, 0x73, 0x6f, 0x6c, + 0x65, 0x2e, 0x6c, 0x6f, 0x67, 0x28, 0x60, 0x57, 0x65, 0x62, + 0x55, 0x49, 0x20, 0x2d, 0x3e, 0x20, 0x46, 0x75, 0x6e, 0x63, + 0x20, 0x5b, 0x24, 0x7b, 0x66, 0x6e, 0x7d, 0x5d, 0x28, 0x24, + 0x7b, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x7d, 0x29, 0x60, 0x29, + 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x63, 0x6f, 0x6e, 0x73, + 0x74, 0x20, 0x63, 0x61, 0x6c, 0x6c, 0x49, 0x64, 0x20, 0x3d, + 0x20, 0x74, 0x68, 0x69, 0x73, 0x2e, 0x23, 0x66, 0x6e, 0x49, + 0x64, 0x2b, 0x2b, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x63, + 0x6f, 0x6e, 0x73, 0x74, 0x20, 0x70, 0x61, 0x63, 0x6b, 0x65, + 0x74, 0x20, 0x3d, 0x20, 0x55, 0x69, 0x6e, 0x74, 0x38, 0x41, + 0x72, 0x72, 0x61, 0x79, 0x2e, 0x6f, 0x66, 0x28, 0x0a, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x74, 0x68, 0x69, 0x73, 0x2e, + 0x23, 0x48, 0x45, 0x41, 0x44, 0x45, 0x52, 0x5f, 0x53, 0x49, + 0x47, 0x4e, 0x41, 0x54, 0x55, 0x52, 0x45, 0x2c, 0x0a, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x74, 0x68, 0x69, 0x73, 0x2e, + 0x23, 0x48, 0x45, 0x41, 0x44, 0x45, 0x52, 0x5f, 0x43, 0x41, + 0x4c, 0x4c, 0x5f, 0x46, 0x55, 0x4e, 0x43, 0x2c, 0x0a, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x63, 0x61, 0x6c, 0x6c, 0x49, + 0x64, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x2e, + 0x2e, 0x2e, 0x6e, 0x65, 0x77, 0x20, 0x54, 0x65, 0x78, 0x74, + 0x45, 0x6e, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x28, 0x29, 0x2e, + 0x65, 0x6e, 0x63, 0x6f, 0x64, 0x65, 0x28, 0x66, 0x6e, 0x29, + 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x30, 0x2c, + 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x2e, 0x2e, 0x2e, + 0x6e, 0x65, 0x77, 0x20, 0x54, 0x65, 0x78, 0x74, 0x45, 0x6e, + 0x63, 0x6f, 0x64, 0x65, 0x72, 0x28, 0x29, 0x2e, 0x65, 0x6e, + 0x63, 0x6f, 0x64, 0x65, 0x28, 0x76, 0x61, 0x6c, 0x75, 0x65, + 0x29, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x30, + 0x0a, 0x20, 0x20, 0x20, 0x20, 0x29, 0x3b, 0x0a, 0x20, 0x20, + 0x20, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x6e, + 0x65, 0x77, 0x20, 0x50, 0x72, 0x6f, 0x6d, 0x69, 0x73, 0x65, + 0x28, 0x28, 0x72, 0x65, 0x73, 0x6f, 0x6c, 0x76, 0x65, 0x29, + 0x20, 0x3d, 0x3e, 0x20, 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x74, 0x68, 0x69, 0x73, 0x2e, 0x23, 0x66, 0x6e, + 0x50, 0x72, 0x6f, 0x6d, 0x69, 0x73, 0x65, 0x52, 0x65, 0x73, + 0x6f, 0x6c, 0x76, 0x65, 0x5b, 0x63, 0x61, 0x6c, 0x6c, 0x49, + 0x64, 0x5d, 0x20, 0x3d, 0x20, 0x72, 0x65, 0x73, 0x6f, 0x6c, + 0x76, 0x65, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x74, 0x68, 0x69, 0x73, 0x2e, 0x23, 0x77, 0x73, 0x2e, 0x73, + 0x65, 0x6e, 0x64, 0x28, 0x70, 0x61, 0x63, 0x6b, 0x65, 0x74, + 0x2e, 0x62, 0x75, 0x66, 0x66, 0x65, 0x72, 0x29, 0x3b, 0x0a, + 0x20, 0x20, 0x20, 0x20, 0x7d, 0x29, 0x3b, 0x0a, 0x20, 0x20, + 0x7d, 0x0a, 0x20, 0x20, 0x2f, 0x2f, 0x20, 0x2d, 0x2d, 0x20, + 0x41, 0x50, 0x49, 0x73, 0x20, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, + 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, + 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, + 0x2d, 0x0a, 0x20, 0x20, 0x2f, 0x2a, 0x2a, 0x0a, 0x20, 0x20, + 0x20, 0x2a, 0x20, 0x43, 0x61, 0x6c, 0x6c, 0x20, 0x61, 0x20, + 0x62, 0x61, 0x63, 0x6b, 0x65, 0x6e, 0x64, 0x20, 0x62, 0x69, + 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x20, 0x66, 0x72, 0x6f, 0x6d, + 0x20, 0x74, 0x68, 0x65, 0x20, 0x66, 0x72, 0x6f, 0x6e, 0x74, + 0x65, 0x6e, 0x64, 0x2e, 0x0a, 0x20, 0x20, 0x20, 0x2a, 0x20, + 0x40, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x20, 0x62, 0x69, 0x6e, + 0x64, 0x69, 0x6e, 0x67, 0x4e, 0x61, 0x6d, 0x65, 0x20, 0x2d, + 0x20, 0x42, 0x61, 0x63, 0x6b, 0x65, 0x6e, 0x64, 0x20, 0x62, + 0x69, 0x6e, 0x64, 0x20, 0x6e, 0x61, 0x6d, 0x65, 0x2e, 0x0a, + 0x20, 0x20, 0x20, 0x2a, 0x20, 0x40, 0x70, 0x61, 0x72, 0x61, + 0x6d, 0x20, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x20, + 0x2d, 0x20, 0x50, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x20, + 0x74, 0x6f, 0x20, 0x73, 0x65, 0x6e, 0x64, 0x20, 0x74, 0x6f, + 0x20, 0x74, 0x68, 0x65, 0x20, 0x62, 0x69, 0x6e, 0x64, 0x69, + 0x6e, 0x67, 0x2c, 0x20, 0x61, 0x63, 0x63, 0x65, 0x70, 0x74, + 0x20, 0x61, 0x6e, 0x79, 0x20, 0x4a, 0x53, 0x4f, 0x4e, 0x20, + 0x76, 0x61, 0x6c, 0x69, 0x64, 0x20, 0x64, 0x61, 0x74, 0x61, + 0x0a, 0x20, 0x20, 0x20, 0x2a, 0x20, 0x28, 0x73, 0x74, 0x72, + 0x69, 0x6e, 0x67, 0x2c, 0x20, 0x6e, 0x75, 0x6d, 0x62, 0x65, + 0x72, 0x2c, 0x20, 0x61, 0x72, 0x72, 0x61, 0x79, 0x2c, 0x20, + 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x2c, 0x20, 0x62, 0x6f, + 0x6f, 0x6c, 0x65, 0x61, 0x6e, 0x2c, 0x20, 0x75, 0x6e, 0x64, + 0x65, 0x66, 0x69, 0x6e, 0x65, 0x64, 0x29, 0x2e, 0x0a, 0x20, + 0x20, 0x20, 0x2a, 0x20, 0x40, 0x72, 0x65, 0x74, 0x75, 0x72, + 0x6e, 0x20, 0x2d, 0x20, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, + 0x73, 0x65, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, + 0x62, 0x61, 0x63, 0x6b, 0x65, 0x6e, 0x64, 0x20, 0x63, 0x61, + 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x20, 0x61, 0x73, 0x20, + 0x4a, 0x53, 0x4f, 0x4e, 0x20, 0x63, 0x6f, 0x6d, 0x70, 0x61, + 0x74, 0x69, 0x62, 0x6c, 0x65, 0x20, 0x76, 0x61, 0x6c, 0x75, + 0x65, 0x2e, 0x0a, 0x20, 0x20, 0x20, 0x2a, 0x20, 0x40, 0x65, + 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x0a, 0x20, 0x20, 0x20, + 0x2a, 0x20, 0x5f, 0x5f, 0x42, 0x61, 0x63, 0x6b, 0x65, 0x6e, + 0x64, 0x20, 0x28, 0x43, 0x29, 0x5f, 0x5f, 0x0a, 0x20, 0x20, + 0x20, 0x2a, 0x20, 0x60, 0x60, 0x60, 0x63, 0x0a, 0x20, 0x20, + 0x20, 0x2a, 0x20, 0x77, 0x65, 0x62, 0x75, 0x69, 0x5f, 0x62, + 0x69, 0x6e, 0x64, 0x28, 0x77, 0x69, 0x6e, 0x64, 0x6f, 0x77, + 0x2c, 0x20, 0x22, 0x67, 0x65, 0x74, 0x5f, 0x63, 0x77, 0x64, + 0x22, 0x2c, 0x20, 0x67, 0x65, 0x74, 0x5f, 0x63, 0x75, 0x72, + 0x72, 0x65, 0x6e, 0x74, 0x5f, 0x77, 0x6f, 0x72, 0x6b, 0x69, + 0x6e, 0x67, 0x5f, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, 0x6f, + 0x72, 0x79, 0x29, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x2a, 0x20, + 0x60, 0x60, 0x60, 0x0a, 0x20, 0x20, 0x20, 0x2a, 0x20, 0x5f, + 0x5f, 0x46, 0x72, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x64, 0x20, + 0x28, 0x4a, 0x53, 0x29, 0x5f, 0x5f, 0x0a, 0x20, 0x20, 0x20, + 0x2a, 0x20, 0x60, 0x60, 0x60, 0x6a, 0x73, 0x0a, 0x20, 0x20, + 0x20, 0x2a, 0x20, 0x63, 0x6f, 0x6e, 0x73, 0x74, 0x20, 0x63, + 0x77, 0x64, 0x20, 0x3d, 0x20, 0x61, 0x77, 0x61, 0x69, 0x74, + 0x20, 0x77, 0x65, 0x62, 0x75, 0x69, 0x2e, 0x63, 0x61, 0x6c, + 0x6c, 0x28, 0x22, 0x67, 0x65, 0x74, 0x5f, 0x63, 0x77, 0x64, + 0x22, 0x29, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x2a, 0x20, 0x60, + 0x60, 0x60, 0x0a, 0x20, 0x20, 0x20, 0x2a, 0x20, 0x40, 0x65, + 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x0a, 0x20, 0x20, 0x20, + 0x2a, 0x20, 0x5f, 0x5f, 0x42, 0x61, 0x63, 0x6b, 0x65, 0x6e, + 0x64, 0x20, 0x28, 0x43, 0x29, 0x5f, 0x5f, 0x0a, 0x20, 0x20, + 0x20, 0x2a, 0x20, 0x60, 0x60, 0x60, 0x63, 0x0a, 0x20, 0x20, + 0x20, 0x2a, 0x20, 0x77, 0x65, 0x62, 0x75, 0x69, 0x5f, 0x62, + 0x69, 0x6e, 0x64, 0x28, 0x77, 0x69, 0x6e, 0x64, 0x6f, 0x77, + 0x2c, 0x20, 0x22, 0x77, 0x72, 0x69, 0x74, 0x65, 0x5f, 0x66, + 0x69, 0x6c, 0x65, 0x22, 0x2c, 0x20, 0x77, 0x72, 0x69, 0x74, + 0x65, 0x5f, 0x66, 0x69, 0x6c, 0x65, 0x29, 0x3b, 0x0a, 0x20, + 0x20, 0x20, 0x2a, 0x20, 0x60, 0x60, 0x60, 0x0a, 0x20, 0x20, + 0x20, 0x2a, 0x20, 0x5f, 0x5f, 0x46, 0x72, 0x6f, 0x6e, 0x74, + 0x65, 0x6e, 0x64, 0x20, 0x28, 0x4a, 0x53, 0x29, 0x5f, 0x5f, + 0x0a, 0x20, 0x20, 0x20, 0x2a, 0x20, 0x60, 0x60, 0x60, 0x6a, + 0x73, 0x0a, 0x20, 0x20, 0x20, 0x2a, 0x20, 0x77, 0x65, 0x62, + 0x75, 0x69, 0x2e, 0x63, 0x61, 0x6c, 0x6c, 0x28, 0x22, 0x77, + 0x72, 0x69, 0x74, 0x65, 0x5f, 0x66, 0x69, 0x6c, 0x65, 0x22, + 0x2c, 0x20, 0x22, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, + 0x20, 0x74, 0x6f, 0x20, 0x77, 0x72, 0x69, 0x74, 0x65, 0x22, + 0x29, 0x0a, 0x20, 0x20, 0x20, 0x2a, 0x20, 0x20, 0x2e, 0x74, + 0x68, 0x65, 0x6e, 0x28, 0x28, 0x29, 0x20, 0x3d, 0x3e, 0x20, + 0x63, 0x6f, 0x6e, 0x73, 0x6f, 0x6c, 0x65, 0x2e, 0x6c, 0x6f, + 0x67, 0x28, 0x22, 0x53, 0x75, 0x63, 0x63, 0x65, 0x73, 0x73, + 0x22, 0x29, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x2a, 0x20, 0x20, + 0x2e, 0x63, 0x61, 0x74, 0x63, 0x68, 0x28, 0x28, 0x29, 0x20, + 0x3d, 0x3e, 0x20, 0x63, 0x6f, 0x6e, 0x73, 0x6f, 0x6c, 0x65, + 0x2e, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x28, 0x22, 0x43, 0x61, + 0x6e, 0x27, 0x74, 0x20, 0x77, 0x72, 0x69, 0x74, 0x65, 0x20, + 0x74, 0x68, 0x65, 0x20, 0x66, 0x69, 0x6c, 0x65, 0x22, 0x29, + 0x29, 0x0a, 0x20, 0x20, 0x20, 0x2a, 0x20, 0x60, 0x60, 0x60, + 0x0a, 0x20, 0x20, 0x20, 0x2a, 0x20, 0x40, 0x65, 0x78, 0x61, + 0x6d, 0x70, 0x6c, 0x65, 0x0a, 0x20, 0x20, 0x20, 0x2a, 0x20, + 0x5f, 0x5f, 0x42, 0x61, 0x63, 0x6b, 0x65, 0x6e, 0x64, 0x20, + 0x28, 0x43, 0x29, 0x5f, 0x5f, 0x0a, 0x20, 0x20, 0x20, 0x2a, + 0x20, 0x60, 0x60, 0x60, 0x63, 0x0a, 0x20, 0x20, 0x20, 0x2a, + 0x20, 0x2f, 0x2f, 0x63, 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x78, + 0x5f, 0x64, 0x61, 0x74, 0x61, 0x73, 0x28, 0x29, 0x20, 0x72, + 0x65, 0x74, 0x75, 0x72, 0x6e, 0x73, 0x20, 0x74, 0x68, 0x65, + 0x20, 0x66, 0x6f, 0x6c, 0x6c, 0x6f, 0x77, 0x69, 0x6e, 0x67, + 0x20, 0x4a, 0x53, 0x4f, 0x4e, 0x20, 0x73, 0x74, 0x72, 0x69, + 0x6e, 0x67, 0x0a, 0x20, 0x20, 0x20, 0x2a, 0x20, 0x2f, 0x2f, + 0x27, 0x7b, 0x20, 0x22, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x22, + 0x3a, 0x20, 0x31, 0x2c, 0x20, 0x22, 0x6c, 0x69, 0x73, 0x74, + 0x22, 0x3a, 0x20, 0x5b, 0x20, 0x31, 0x2c, 0x20, 0x32, 0x2c, + 0x20, 0x33, 0x20, 0x5d, 0x2c, 0x20, 0x22, 0x69, 0x73, 0x47, + 0x6f, 0x6f, 0x64, 0x22, 0x3a, 0x20, 0x74, 0x72, 0x75, 0x65, + 0x20, 0x7d, 0x27, 0x0a, 0x20, 0x20, 0x20, 0x2a, 0x20, 0x77, + 0x65, 0x62, 0x75, 0x69, 0x5f, 0x62, 0x69, 0x6e, 0x64, 0x28, + 0x77, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x2c, 0x20, 0x22, 0x63, + 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x78, 0x5f, 0x64, 0x61, 0x74, + 0x61, 0x73, 0x22, 0x2c, 0x20, 0x63, 0x6f, 0x6d, 0x70, 0x6c, + 0x65, 0x78, 0x5f, 0x64, 0x61, 0x74, 0x61, 0x73, 0x29, 0x3b, + 0x0a, 0x20, 0x20, 0x20, 0x2a, 0x20, 0x60, 0x60, 0x60, 0x0a, + 0x20, 0x20, 0x20, 0x2a, 0x20, 0x5f, 0x5f, 0x46, 0x72, 0x6f, + 0x6e, 0x74, 0x65, 0x6e, 0x64, 0x20, 0x28, 0x4a, 0x53, 0x29, + 0x5f, 0x5f, 0x0a, 0x20, 0x20, 0x20, 0x2a, 0x20, 0x60, 0x60, + 0x60, 0x6a, 0x73, 0x0a, 0x20, 0x20, 0x20, 0x2a, 0x20, 0x74, + 0x79, 0x70, 0x65, 0x20, 0x43, 0x6f, 0x6d, 0x70, 0x6c, 0x65, + 0x78, 0x44, 0x61, 0x74, 0x61, 0x73, 0x20, 0x3d, 0x20, 0x7b, + 0x0a, 0x20, 0x20, 0x20, 0x2a, 0x20, 0x20, 0x63, 0x6f, 0x75, + 0x6e, 0x74, 0x3a, 0x20, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, + 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x2a, 0x20, 0x20, 0x6c, 0x69, + 0x73, 0x74, 0x3a, 0x20, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, + 0x5b, 0x5d, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x2a, 0x20, 0x20, + 0x69, 0x73, 0x47, 0x6f, 0x6f, 0x64, 0x3a, 0x20, 0x62, 0x6f, + 0x6f, 0x6c, 0x65, 0x61, 0x6e, 0x3b, 0x0a, 0x20, 0x20, 0x20, + 0x2a, 0x20, 0x7d, 0x0a, 0x20, 0x20, 0x20, 0x2a, 0x0a, 0x20, + 0x20, 0x20, 0x2a, 0x20, 0x63, 0x6f, 0x6e, 0x73, 0x74, 0x20, + 0x7b, 0x20, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x2c, 0x20, 0x6c, + 0x69, 0x73, 0x74, 0x2c, 0x20, 0x69, 0x73, 0x47, 0x6f, 0x6f, + 0x64, 0x20, 0x7d, 0x20, 0x3d, 0x20, 0x61, 0x77, 0x61, 0x69, + 0x74, 0x20, 0x77, 0x65, 0x62, 0x75, 0x69, 0x0a, 0x20, 0x20, + 0x20, 0x2a, 0x20, 0x20, 0x2e, 0x63, 0x61, 0x6c, 0x6c, 0x3c, + 0x43, 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x78, 0x44, 0x61, 0x74, + 0x61, 0x73, 0x3e, 0x28, 0x22, 0x63, 0x6f, 0x6d, 0x70, 0x6c, + 0x65, 0x78, 0x5f, 0x64, 0x61, 0x74, 0x61, 0x73, 0x22, 0x29, + 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x2a, 0x0a, 0x20, 0x20, 0x20, + 0x2a, 0x20, 0x2f, 0x2f, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x20, + 0x3d, 0x20, 0x31, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x2a, 0x20, + 0x2f, 0x2f, 0x6c, 0x69, 0x73, 0x74, 0x20, 0x3d, 0x20, 0x5b, + 0x20, 0x31, 0x2c, 0x20, 0x32, 0x2c, 0x20, 0x33, 0x20, 0x5d, + 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x2a, 0x20, 0x2f, 0x2f, 0x69, + 0x73, 0x47, 0x6f, 0x6f, 0x64, 0x20, 0x3d, 0x20, 0x74, 0x72, + 0x75, 0x65, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x2a, 0x20, 0x60, + 0x60, 0x60, 0x0a, 0x20, 0x20, 0x20, 0x2a, 0x2f, 0x0a, 0x20, + 0x20, 0x61, 0x73, 0x79, 0x6e, 0x63, 0x20, 0x63, 0x61, 0x6c, + 0x6c, 0x28, 0x62, 0x69, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x4e, + 0x61, 0x6d, 0x65, 0x2c, 0x20, 0x70, 0x61, 0x79, 0x6c, 0x6f, + 0x61, 0x64, 0x29, 0x20, 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, + 0x69, 0x66, 0x20, 0x28, 0x21, 0x62, 0x69, 0x6e, 0x64, 0x69, + 0x6e, 0x67, 0x4e, 0x61, 0x6d, 0x65, 0x29, 0x0a, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, + 0x20, 0x50, 0x72, 0x6f, 0x6d, 0x69, 0x73, 0x65, 0x2e, 0x72, + 0x65, 0x6a, 0x65, 0x63, 0x74, 0x28, 0x6e, 0x65, 0x77, 0x20, + 0x53, 0x79, 0x6e, 0x74, 0x61, 0x78, 0x45, 0x72, 0x72, 0x6f, + 0x72, 0x28, 0x22, 0x6e, 0x6f, 0x20, 0x62, 0x69, 0x6e, 0x64, + 0x69, 0x6e, 0x67, 0x20, 0x6e, 0x61, 0x6d, 0x65, 0x20, 0x70, + 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x64, 0x22, 0x29, 0x29, + 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, 0x28, + 0x21, 0x74, 0x68, 0x69, 0x73, 0x2e, 0x23, 0x77, 0x73, 0x53, + 0x74, 0x61, 0x74, 0x75, 0x73, 0x29, 0x0a, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, + 0x50, 0x72, 0x6f, 0x6d, 0x69, 0x73, 0x65, 0x2e, 0x72, 0x65, + 0x6a, 0x65, 0x63, 0x74, 0x28, 0x6e, 0x65, 0x77, 0x20, 0x45, + 0x72, 0x72, 0x6f, 0x72, 0x28, 0x22, 0x77, 0x65, 0x62, 0x73, + 0x6f, 0x63, 0x6b, 0x65, 0x74, 0x20, 0x69, 0x73, 0x20, 0x6e, + 0x6f, 0x74, 0x20, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, + 0x65, 0x64, 0x22, 0x29, 0x29, 0x3b, 0x0a, 0x20, 0x20, 0x20, + 0x20, 0x69, 0x66, 0x20, 0x28, 0x21, 0x74, 0x68, 0x69, 0x73, + 0x2e, 0x23, 0x68, 0x61, 0x73, 0x45, 0x76, 0x65, 0x6e, 0x74, + 0x73, 0x20, 0x26, 0x26, 0x20, 0x21, 0x74, 0x68, 0x69, 0x73, + 0x2e, 0x23, 0x62, 0x69, 0x6e, 0x64, 0x4c, 0x69, 0x73, 0x74, + 0x2e, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x73, 0x28, + 0x60, 0x24, 0x7b, 0x74, 0x68, 0x69, 0x73, 0x2e, 0x23, 0x77, + 0x69, 0x6e, 0x4e, 0x75, 0x6d, 0x7d, 0x2f, 0x24, 0x7b, 0x62, + 0x69, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x4e, 0x61, 0x6d, 0x65, + 0x7d, 0x60, 0x29, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x50, 0x72, + 0x6f, 0x6d, 0x69, 0x73, 0x65, 0x2e, 0x72, 0x65, 0x6a, 0x65, + 0x63, 0x74, 0x28, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x6e, 0x65, 0x77, 0x20, 0x52, 0x65, 0x66, 0x65, + 0x72, 0x65, 0x6e, 0x63, 0x65, 0x45, 0x72, 0x72, 0x6f, 0x72, + 0x28, 0x60, 0x6e, 0x6f, 0x20, 0x62, 0x69, 0x6e, 0x64, 0x69, + 0x6e, 0x67, 0x20, 0x77, 0x61, 0x73, 0x20, 0x66, 0x6f, 0x75, + 0x6e, 0x64, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x22, 0x24, 0x7b, + 0x62, 0x69, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x4e, 0x61, 0x6d, + 0x65, 0x7d, 0x22, 0x60, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x29, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x63, + 0x6f, 0x6e, 0x73, 0x74, 0x20, 0x72, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x20, 0x3d, 0x20, 0x61, 0x77, 0x61, 0x69, + 0x74, 0x20, 0x74, 0x68, 0x69, 0x73, 0x2e, 0x23, 0x66, 0x6e, + 0x50, 0x72, 0x6f, 0x6d, 0x69, 0x73, 0x65, 0x28, 0x0a, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x62, 0x69, 0x6e, 0x64, 0x69, + 0x6e, 0x67, 0x4e, 0x61, 0x6d, 0x65, 0x2c, 0x0a, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, + 0x64, 0x20, 0x3d, 0x3d, 0x3d, 0x20, 0x76, 0x6f, 0x69, 0x64, + 0x20, 0x30, 0x20, 0x3f, 0x20, 0x22, 0x22, 0x20, 0x3a, 0x20, + 0x74, 0x79, 0x70, 0x65, 0x6f, 0x66, 0x20, 0x70, 0x61, 0x79, + 0x6c, 0x6f, 0x61, 0x64, 0x20, 0x3d, 0x3d, 0x3d, 0x20, 0x22, + 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x22, 0x20, 0x3f, 0x20, + 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x20, 0x3a, 0x20, + 0x4a, 0x53, 0x4f, 0x4e, 0x2e, 0x73, 0x74, 0x72, 0x69, 0x6e, + 0x67, 0x69, 0x66, 0x79, 0x28, 0x70, 0x61, 0x79, 0x6c, 0x6f, + 0x61, 0x64, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x29, 0x3b, + 0x0a, 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, 0x28, 0x72, + 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x20, 0x3d, 0x3d, + 0x3d, 0x20, 0x76, 0x6f, 0x69, 0x64, 0x20, 0x30, 0x29, 0x0a, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x74, 0x75, + 0x72, 0x6e, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x74, 0x72, + 0x79, 0x20, 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x4a, 0x53, 0x4f, + 0x4e, 0x2e, 0x70, 0x61, 0x72, 0x73, 0x65, 0x28, 0x72, 0x65, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x29, 0x3b, 0x0a, 0x20, + 0x20, 0x20, 0x20, 0x7d, 0x20, 0x63, 0x61, 0x74, 0x63, 0x68, + 0x20, 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x72, + 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x72, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, + 0x7d, 0x0a, 0x20, 0x20, 0x7d, 0x0a, 0x20, 0x20, 0x2f, 0x2a, + 0x2a, 0x0a, 0x20, 0x20, 0x20, 0x2a, 0x20, 0x41, 0x63, 0x74, + 0x69, 0x76, 0x65, 0x20, 0x6f, 0x72, 0x20, 0x64, 0x65, 0x61, + 0x63, 0x74, 0x69, 0x76, 0x61, 0x74, 0x65, 0x20, 0x77, 0x65, + 0x62, 0x75, 0x69, 0x20, 0x64, 0x65, 0x62, 0x75, 0x67, 0x20, + 0x6c, 0x6f, 0x67, 0x67, 0x69, 0x6e, 0x67, 0x2e, 0x0a, 0x20, + 0x20, 0x20, 0x2a, 0x20, 0x40, 0x70, 0x61, 0x72, 0x61, 0x6d, + 0x20, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x20, 0x2d, 0x20, + 0x6c, 0x6f, 0x67, 0x20, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, + 0x20, 0x74, 0x6f, 0x20, 0x73, 0x65, 0x74, 0x2e, 0x0a, 0x20, + 0x20, 0x20, 0x2a, 0x2f, 0x0a, 0x20, 0x20, 0x73, 0x65, 0x74, + 0x4c, 0x6f, 0x67, 0x67, 0x69, 0x6e, 0x67, 0x28, 0x73, 0x74, + 0x61, 0x74, 0x75, 0x73, 0x29, 0x20, 0x7b, 0x0a, 0x20, 0x20, + 0x20, 0x20, 0x69, 0x66, 0x20, 0x28, 0x73, 0x74, 0x61, 0x74, + 0x75, 0x73, 0x29, 0x20, 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x63, 0x6f, 0x6e, 0x73, 0x6f, 0x6c, 0x65, 0x2e, + 0x6c, 0x6f, 0x67, 0x28, 0x22, 0x57, 0x65, 0x62, 0x55, 0x49, + 0x20, 0x2d, 0x3e, 0x20, 0x4c, 0x6f, 0x67, 0x20, 0x45, 0x6e, + 0x61, 0x62, 0x6c, 0x65, 0x64, 0x2e, 0x22, 0x29, 0x3b, 0x0a, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x74, 0x68, 0x69, 0x73, + 0x2e, 0x23, 0x6c, 0x6f, 0x67, 0x20, 0x3d, 0x20, 0x74, 0x72, + 0x75, 0x65, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x7d, 0x20, + 0x65, 0x6c, 0x73, 0x65, 0x20, 0x7b, 0x0a, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x63, 0x6f, 0x6e, 0x73, 0x6f, 0x6c, 0x65, + 0x2e, 0x6c, 0x6f, 0x67, 0x28, 0x22, 0x57, 0x65, 0x62, 0x55, + 0x49, 0x20, 0x2d, 0x3e, 0x20, 0x4c, 0x6f, 0x67, 0x20, 0x44, + 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x2e, 0x22, 0x29, + 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x74, 0x68, + 0x69, 0x73, 0x2e, 0x23, 0x6c, 0x6f, 0x67, 0x20, 0x3d, 0x20, + 0x66, 0x61, 0x6c, 0x73, 0x65, 0x3b, 0x0a, 0x20, 0x20, 0x20, + 0x20, 0x7d, 0x0a, 0x20, 0x20, 0x7d, 0x0a, 0x20, 0x20, 0x2f, + 0x2a, 0x2a, 0x0a, 0x20, 0x20, 0x20, 0x2a, 0x20, 0x45, 0x6e, + 0x63, 0x6f, 0x64, 0x65, 0x20, 0x64, 0x61, 0x74, 0x61, 0x73, + 0x20, 0x69, 0x6e, 0x74, 0x6f, 0x20, 0x62, 0x61, 0x73, 0x65, + 0x36, 0x34, 0x20, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x2e, + 0x0a, 0x20, 0x20, 0x20, 0x2a, 0x20, 0x40, 0x70, 0x61, 0x72, + 0x61, 0x6d, 0x20, 0x64, 0x61, 0x74, 0x61, 0x73, 0x20, 0x2d, + 0x20, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x20, 0x6f, 0x72, + 0x20, 0x4a, 0x53, 0x4f, 0x4e, 0x20, 0x76, 0x61, 0x6c, 0x75, + 0x65, 0x2e, 0x0a, 0x20, 0x20, 0x20, 0x2a, 0x2f, 0x0a, 0x20, + 0x20, 0x65, 0x6e, 0x63, 0x6f, 0x64, 0x65, 0x28, 0x64, 0x61, + 0x74, 0x61, 0x73, 0x29, 0x20, 0x7b, 0x0a, 0x20, 0x20, 0x20, + 0x20, 0x69, 0x66, 0x20, 0x28, 0x74, 0x79, 0x70, 0x65, 0x6f, + 0x66, 0x20, 0x64, 0x61, 0x74, 0x61, 0x73, 0x20, 0x3d, 0x3d, + 0x3d, 0x20, 0x22, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x22, + 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, + 0x74, 0x75, 0x72, 0x6e, 0x20, 0x62, 0x74, 0x6f, 0x61, 0x28, + 0x64, 0x61, 0x74, 0x61, 0x73, 0x29, 0x3b, 0x0a, 0x20, 0x20, + 0x20, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x62, + 0x74, 0x6f, 0x61, 0x28, 0x4a, 0x53, 0x4f, 0x4e, 0x2e, 0x73, + 0x74, 0x72, 0x69, 0x6e, 0x67, 0x69, 0x66, 0x79, 0x28, 0x64, + 0x61, 0x74, 0x61, 0x73, 0x29, 0x29, 0x3b, 0x0a, 0x20, 0x20, + 0x7d, 0x0a, 0x20, 0x20, 0x2f, 0x2a, 0x2a, 0x0a, 0x20, 0x20, + 0x20, 0x2a, 0x20, 0x44, 0x65, 0x63, 0x6f, 0x64, 0x65, 0x20, + 0x61, 0x20, 0x62, 0x61, 0x73, 0x65, 0x36, 0x34, 0x20, 0x73, + 0x74, 0x72, 0x69, 0x6e, 0x67, 0x20, 0x69, 0x6e, 0x74, 0x6f, + 0x20, 0x61, 0x6e, 0x79, 0x20, 0x4a, 0x53, 0x4f, 0x4e, 0x20, + 0x76, 0x61, 0x6c, 0x69, 0x64, 0x20, 0x66, 0x6f, 0x72, 0x6d, + 0x61, 0x74, 0x0a, 0x20, 0x20, 0x20, 0x2a, 0x20, 0x28, 0x73, + 0x74, 0x72, 0x69, 0x6e, 0x67, 0x2c, 0x20, 0x6e, 0x75, 0x6d, + 0x62, 0x65, 0x72, 0x2c, 0x20, 0x61, 0x72, 0x72, 0x61, 0x79, + 0x2c, 0x20, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x2c, 0x20, + 0x62, 0x6f, 0x6f, 0x6c, 0x65, 0x61, 0x6e, 0x29, 0x2e, 0x0a, + 0x20, 0x20, 0x20, 0x2a, 0x20, 0x40, 0x70, 0x61, 0x72, 0x61, + 0x6d, 0x20, 0x62, 0x36, 0x34, 0x20, 0x2d, 0x20, 0x62, 0x61, + 0x73, 0x65, 0x36, 0x34, 0x20, 0x73, 0x74, 0x72, 0x69, 0x6e, + 0x67, 0x20, 0x74, 0x6f, 0x20, 0x64, 0x65, 0x63, 0x6f, 0x64, + 0x65, 0x2e, 0x0a, 0x20, 0x20, 0x20, 0x2a, 0x2f, 0x0a, 0x20, + 0x20, 0x64, 0x65, 0x63, 0x6f, 0x64, 0x65, 0x28, 0x62, 0x36, + 0x34, 0x29, 0x20, 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x74, + 0x72, 0x79, 0x20, 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x4a, 0x53, + 0x4f, 0x4e, 0x2e, 0x70, 0x61, 0x72, 0x73, 0x65, 0x28, 0x61, + 0x74, 0x6f, 0x62, 0x28, 0x62, 0x36, 0x34, 0x29, 0x29, 0x3b, + 0x0a, 0x20, 0x20, 0x20, 0x20, 0x7d, 0x20, 0x63, 0x61, 0x74, + 0x63, 0x68, 0x20, 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x61, 0x74, + 0x6f, 0x62, 0x28, 0x62, 0x36, 0x34, 0x29, 0x3b, 0x0a, 0x20, + 0x20, 0x20, 0x20, 0x7d, 0x0a, 0x20, 0x20, 0x7d, 0x0a, 0x7d, + 0x3b, 0x0a, 0x61, 0x64, 0x64, 0x45, 0x76, 0x65, 0x6e, 0x74, + 0x4c, 0x69, 0x73, 0x74, 0x65, 0x6e, 0x65, 0x72, 0x28, 0x22, + 0x6c, 0x6f, 0x61, 0x64, 0x22, 0x2c, 0x20, 0x28, 0x29, 0x20, + 0x3d, 0x3e, 0x20, 0x7b, 0x0a, 0x20, 0x20, 0x64, 0x6f, 0x63, + 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x62, 0x6f, 0x64, 0x79, + 0x2e, 0x61, 0x64, 0x64, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x4c, + 0x69, 0x73, 0x74, 0x65, 0x6e, 0x65, 0x72, 0x28, 0x0a, 0x20, + 0x20, 0x20, 0x20, 0x22, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x78, + 0x74, 0x6d, 0x65, 0x6e, 0x75, 0x22, 0x2c, 0x0a, 0x20, 0x20, + 0x20, 0x20, 0x28, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x29, 0x20, + 0x3d, 0x3e, 0x20, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x2e, 0x70, + 0x72, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x44, 0x65, 0x66, 0x61, + 0x75, 0x6c, 0x74, 0x28, 0x29, 0x0a, 0x20, 0x20, 0x29, 0x3b, + 0x0a, 0x20, 0x20, 0x61, 0x64, 0x64, 0x52, 0x65, 0x66, 0x72, + 0x65, 0x73, 0x68, 0x61, 0x62, 0x6c, 0x65, 0x45, 0x76, 0x65, + 0x6e, 0x74, 0x4c, 0x69, 0x73, 0x74, 0x65, 0x6e, 0x65, 0x72, + 0x28, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x64, 0x6f, 0x63, 0x75, + 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x62, 0x6f, 0x64, 0x79, 0x2c, + 0x0a, 0x20, 0x20, 0x20, 0x20, 0x22, 0x69, 0x6e, 0x70, 0x75, + 0x74, 0x22, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x22, 0x63, + 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x6d, 0x65, 0x6e, 0x75, + 0x22, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x28, 0x65, 0x76, + 0x65, 0x6e, 0x74, 0x29, 0x20, 0x3d, 0x3e, 0x20, 0x65, 0x76, + 0x65, 0x6e, 0x74, 0x2e, 0x73, 0x74, 0x6f, 0x70, 0x50, 0x72, + 0x6f, 0x70, 0x61, 0x67, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x28, + 0x29, 0x0a, 0x20, 0x20, 0x29, 0x3b, 0x0a, 0x7d, 0x29, 0x3b, + 0x0a, +}; + +#endif // WEBUI_BRIDGE_H \ No newline at end of file diff --git a/bridge/webui_bridge.ts b/bridge/webui_bridge.ts new file mode 100644 index 00000000..528b591d --- /dev/null +++ b/bridge/webui_bridge.ts @@ -0,0 +1,544 @@ +'use-strict' // Force strict mode for transpiled + +/* + WebUI Bridge + + http://webui.me + https://github.com/webui-dev/webui + Copyright (c) 2020-2023 Hassan Draga. + Licensed under MIT License. + All rights reserved. + Canada. + + Converted from JavaScript to TypeScript + By Oculi Julien. Copyright (c) 2023. +*/ + +//@ts-ignore use *.ts import real extension +import { AsyncFunction, addRefreshableEventListener } from './utils.ts' + +type B64string = string +type JSONValue = + | string + | number + | boolean + | { [x: string]: JSONValue | undefined } + | JSONValue[] + +class WebUiClient { + // WebUI settings + #port: number + #winNum: number + #log: boolean + #bindList: unknown[] = [] + + // Internals + #ws: WebSocket + #wsStatus = false + #wsStatusOnce = false + #closeReason = 0 + #closeValue: string + #hasEvents = false + #fnId = 1 + #fnPromiseResolve: (((data: string) => unknown) | undefined)[] = [] + + // WebUI const + #HEADER_SIGNATURE = 221 + #HEADER_JS = 254 + #HEADER_JS_QUICK = 253 + #HEADER_CLICK = 252 + #HEADER_SWITCH = 251 + #HEADER_CLOSE = 250 + #HEADER_CALL_FUNC = 249 + #HEADER_SEND_RAW = 248 + + constructor({ + port, + winNum, + bindList, + log = false, + }: { + port: number + winNum: number + bindList: unknown[] + log?: boolean + }) { + // Constructor arguments are injected by webui.c + this.#port = port + this.#winNum = winNum + this.#bindList = bindList + this.#log = log + + if ('webui' in globalThis) { + throw new Error( + 'Sorry. WebUI is already defined, only one instance is allowed.' + ) + } + + if (!('WebSocket' in window)) { + alert('Sorry. WebSocket is not supported by your web browser.') + if (!this.#log) globalThis.close() + } + + this.#start() + + // Handle navigation server side + if ('navigation' in globalThis) { + globalThis.navigation.addEventListener('navigate', (event) => { + const url = new URL(event.destination.url) + this.#sendEventNavigation(url.href) + }) + } else { + // Handle all link click to prevent natural navigation + // Rebind listener if user inject new html + addRefreshableEventListener( + document.body, + 'a', + 'click', + (event) => { + event.preventDefault() + const { href } = event.target as HTMLAnchorElement + if (this.#isExternalLink(href)) { + this.#close(this.#HEADER_SWITCH, href) + } else { + this.#sendEventNavigation(href) + } + } + ) + } + + // Prevent F5 refresh + document.addEventListener('keydown', (event) => { + // Disable F5 + if (this.#log) return + if (event.key === 'F5') event.preventDefault() + }) + + onbeforeunload = () => { + this.#close() + } + setTimeout(() => { + if (!this.#wsStatusOnce) { + this.#freezeUi() + alert( + 'Sorry. WebUI failed to connect to the background application. Please try again.' + ) + if (!this.#log) globalThis.close() + } + }, 1500) + } + + #close(reason = 0, value = '') { + if (reason === this.#HEADER_SWITCH) this.#sendEventNavigation(value) + this.#wsStatus = false + this.#closeReason = reason + this.#closeValue = value + this.#ws.close() + } + + #freezeUi() { + document.body.style.filter = 'contrast(1%)' + } + + #getString(buffer: Uint8Array, startIndex: number): string { + let stringBytes: number[] = []; + + for (let i = startIndex; i < buffer.length; i++) { + if (buffer[i] === 0) { // Check for null byte + break; + } + stringBytes.push(buffer[i]); + } + + // Convert the array of bytes to a string + let stringText = new TextDecoder().decode(new Uint8Array(stringBytes)); + + return stringText; + } + + #start() { + if (this.#bindList.includes(this.#winNum + '/')) { + this.#hasEvents = true + } + + this.#ws = new WebSocket( + `ws://localhost:${this.#port}/_webui_ws_connect` + ) + this.#ws.binaryType = 'arraybuffer' + + this.#ws.onopen = () => { + this.#wsStatus = true + this.#wsStatusOnce = true + this.#fnId = 1 + if (this.#log) console.log('WebUI -> Connected') + this.#clicksListener() + } + + this.#ws.onerror = () => { + if (this.#log) console.log('WebUI -> Connection Failed') + this.#freezeUi() + } + + this.#ws.onclose = (event) => { + this.#wsStatus = false + if (this.#closeReason === this.#HEADER_SWITCH) { + if (this.#log) { + console.log( + `WebUI -> Connection lost -> Navigation to [${ + this.#closeValue + }]` + ) + } + globalThis.location.replace(this.#closeValue) + } else { + if (this.#log) { + console.log(`WebUI -> Connection lost (${event.code})`) + this.#freezeUi() + } else { + this.#closeWindowTimer() + } + } + } + + this.#ws.onmessage = async (event) => { + const buffer8 = new Uint8Array(event.data) + if (buffer8.length < 4) return + if (buffer8[0] !== this.#HEADER_SIGNATURE) return + + if(buffer8[1] !== this.#HEADER_SEND_RAW) { + // UTF8 Text based commands + + const data8 = + buffer8[buffer8.length - 1] === 0 + ? buffer8.slice(3, -1) + : buffer8.slice(3) // Null byte (0x00) can break eval() + const data8utf8 = new TextDecoder().decode(data8) + + // Process Command + switch (buffer8[1]) { + case this.#HEADER_CALL_FUNC: + { + const callId = buffer8[2] + if (this.#log) { + console.log(`WebUI -> Func Response [${data8utf8}]`) + } + if (this.#fnPromiseResolve[callId]) { + if (this.#log) { + console.log( + `WebUI -> Resolving Response #${callId}...` + ) + } + this.#fnPromiseResolve[callId]?.(data8utf8) + this.#fnPromiseResolve[callId] = undefined + } + } + break + case this.#HEADER_SWITCH: + this.#close(this.#HEADER_SWITCH, data8utf8) + break + case this.#HEADER_CLOSE: + globalThis.close() + break + case this.#HEADER_JS_QUICK: + case this.#HEADER_JS: + { + const data8utf8sanitize = data8utf8.replace( + /(?:\r\n|\r|\n)/g, + '\n' + ) + if (this.#log) + console.log(`WebUI -> JS [${data8utf8sanitize}]`) + + // Get callback result + let FunReturn = 'undefined' + let FunError = false + try { + FunReturn = await AsyncFunction(data8utf8sanitize)() + } catch (e) { + FunError = true + FunReturn = e.message + } + if (buffer8[1] === this.#HEADER_JS_QUICK) return + if (FunReturn === undefined) { + FunReturn = 'undefined' + } + + // Logging + if (this.#log && !FunError) + console.log(`WebUI -> JS -> Return [${FunReturn}]`) + if (this.#log && FunError) + console.log(`WebUI -> JS -> Error [${FunReturn}]`) + + // Format ws response + const Return8 = Uint8Array.of( + this.#HEADER_SIGNATURE, + this.#HEADER_JS, + buffer8[2], + FunError ? 0 : 1, + ...new TextEncoder().encode(FunReturn) + ) + + if (this.#wsStatus) this.#ws.send(Return8.buffer) + } + break + } + } + else { + // Raw binary commands + + // Process Command + switch (buffer8[1]) { + case this.#HEADER_SEND_RAW: + { + // 0: [Signature] + // 1: [Type] + // 2: [ID] + // 3: [Function] + // 4: [Null] + // 5: [Raw Data] + + // [0xDD] [0xF8] [0x00] [0xFF 0xFF 0xFF 0xFF] [0x00] [0x11 0x11 0x11] + + // Get function name + const functionName: string = this.#getString(buffer8, 3) + + // Get the raw data + const rawDataIndex: number = 3 + functionName.length + 1 + const userRawData = buffer8.subarray(rawDataIndex); + + // Call the user function, and pass the raw data + if (typeof window[functionName] === 'function') + window[functionName](userRawData); + else + await AsyncFunction(functionName + '(userRawData);')() + } + break + } + } + } + } + + #clicksListener() { + Object.keys(window).forEach((key) => { + if (/^on(click)/.test(key)) { + globalThis.addEventListener(key.slice(2), (event) => { + if (!(event.target instanceof HTMLElement)) return + if ( + this.#hasEvents || + (event.target.id !== '' && + this.#bindList.includes( + this.#winNum + '/' + event.target?.id + )) + ) { + this.#sendClick(event.target.id) + } + }) + } + }) + } + + #sendClick(elem: string) { + if (this.#wsStatus) { + const packet = + elem !== '' + ? Uint8Array.of( + this.#HEADER_SIGNATURE, + this.#HEADER_CLICK, + 0, + ...new TextEncoder().encode(elem) + ) + : Uint8Array.of( + this.#HEADER_SIGNATURE, + this.#HEADER_CLICK, + 0, + 0 + ) + this.#ws.send(packet.buffer) + if (this.#log) console.log(`WebUI -> Click [${elem}]`) + } + } + + #sendEventNavigation(url: string) { + if (this.#hasEvents && this.#wsStatus && url !== '') { + const packet = Uint8Array.of( + this.#HEADER_SIGNATURE, + this.#HEADER_SWITCH, + ...new TextEncoder().encode(url) + ) + this.#ws.send(packet.buffer) + if (this.#log) console.log(`WebUI -> Navigation [${url}]`) + } + } + + #isExternalLink(url: string) { + return new URL(url).host === globalThis.location.host + } + #closeWindowTimer() { + setTimeout(function () { + globalThis.close() + }, 1000) + } + #fnPromise(fn: string, value: string) { + if (this.#log) console.log(`WebUI -> Func [${fn}](${value})`) + const callId = this.#fnId++ + + const packet = Uint8Array.of( + this.#HEADER_SIGNATURE, + this.#HEADER_CALL_FUNC, + callId, + ...new TextEncoder().encode(fn), + 0, + ...new TextEncoder().encode(value), + 0 + ) + + return new Promise((resolve) => { + this.#fnPromiseResolve[callId] = resolve + this.#ws.send(packet.buffer) + }) + } + + // -- APIs -------------------------- + + /** + * Call a backend binding from the frontend. + * @param bindingName - Backend bind name. + * @param payload - Payload to send to the binding, accept any JSON valid data + * (string, number, array, object, boolean, undefined). + * @return - Response of the backend callback as JSON compatible value. + * @example + * __Backend (C)__ + * ```c + * webui_bind(window, "get_cwd", get_current_working_directory); + * ``` + * __Frontend (JS)__ + * ```js + * const cwd = await webui.call("get_cwd"); + * ``` + * @example + * __Backend (C)__ + * ```c + * webui_bind(window, "write_file", write_file); + * ``` + * __Frontend (JS)__ + * ```js + * webui.call("write_file", "content to write") + * .then(() => console.log("Success")) + * .catch(() => console.error("Can't write the file")) + * ``` + * @example + * __Backend (C)__ + * ```c + * //complex_datas() returns the following JSON string + * //'{ "count": 1, "list": [ 1, 2, 3 ], "isGood": true }' + * webui_bind(window, "complex_datas", complex_datas); + * ``` + * __Frontend (JS)__ + * ```js + * type ComplexDatas = { + * count: number; + * list: number[]; + * isGood: boolean; + * } + * + * const { count, list, isGood } = await webui + * .call("complex_datas"); + * + * //count = 1; + * //list = [ 1, 2, 3 ]; + * //isGood = true; + * ``` + */ + async call< + Response extends JSONValue = string, + Payload extends JSONValue = JSONValue + >(bindingName: string, payload?: Payload): Promise { + if (!bindingName) + return Promise.reject(new SyntaxError('no binding name provided')) + + if (!this.#wsStatus) + return Promise.reject(new Error('websocket is not connected')) + // Check binding list + if ( + !this.#hasEvents && + !this.#bindList.includes(`${this.#winNum}/${bindingName}`) + ) + return Promise.reject( + new ReferenceError(`no binding was found for "${bindingName}"`) + ) + + // Get the binding response + const response = (await this.#fnPromise( + bindingName, + payload === undefined + ? '' + : typeof payload === 'string' + ? payload + : JSON.stringify(payload) + )) as string | void + + // Handle response type (void, string or JSON value) + if (response === undefined) return + + try { + return JSON.parse(response) + } catch { + //@ts-ignore string is a valid JSON value + return response + } + } + + /** + * Active or deactivate webui debug logging. + * @param status - log status to set. + */ + setLogging(status: boolean) { + if (status) { + console.log('WebUI -> Log Enabled.') + this.#log = true + } else { + console.log('WebUI -> Log Disabled.') + this.#log = false + } + } + + /** + * Encode datas into base64 string. + * @param datas - string or JSON value. + */ + encode(datas: JSONValue): B64string { + if (typeof datas === 'string') return btoa(datas) + return btoa(JSON.stringify(datas)) + } + + /** + * Decode a base64 string into any JSON valid format + * (string, number, array, object, boolean). + * @param b64 - base64 string to decode. + */ + decode(b64: B64string): T { + try { + return JSON.parse(atob(b64)) + } catch { + //@ts-ignore string a valid JSON value + return atob(b64) + } + } +} + +type webui = WebUiClient +export default webui +export type { WebUiClient } + +// Wait for the html to be parsed +addEventListener('load', () => { + document.body.addEventListener('contextmenu', (event) => + event.preventDefault() + ) + addRefreshableEventListener( + document.body, + 'input', + 'contextmenu', + (event) => event.stopPropagation() + ) +})