From bcb48ddb18b5372bc1e0237e47c810d0d26ee07b Mon Sep 17 00:00:00 2001 From: Ingo Schommer Date: Thu, 26 Nov 2009 03:17:27 +0000 Subject: [PATCH] MINOR Moved jsparty/SWFUpload to cms/thirdparty/swfupload git-svn-id: svn://svn.silverstripe.com/silverstripe/open/modules/cms/branches/2.4@93559 467b73ca-7a2a-4603-9d3b-597d59a354a9 --- thirdparty/swfupload/license.txt | 11 + thirdparty/swfupload/swfupload.js | 1052 +++++++++++++++++++++++ thirdparty/swfupload/swfupload.queue.js | 98 +++ thirdparty/swfupload/swfupload.swf | Bin 0 -> 33328 bytes 4 files changed, 1161 insertions(+) create mode 100644 thirdparty/swfupload/license.txt create mode 100755 thirdparty/swfupload/swfupload.js create mode 100755 thirdparty/swfupload/swfupload.queue.js create mode 100755 thirdparty/swfupload/swfupload.swf diff --git a/thirdparty/swfupload/license.txt b/thirdparty/swfupload/license.txt new file mode 100644 index 00000000..dd26171a --- /dev/null +++ b/thirdparty/swfupload/license.txt @@ -0,0 +1,11 @@ +/** + * mmSWFUpload 1.0: Flash upload dialog - http://profandesign.se/swfupload/ + * + * SWFUpload is (c) 2006-2007 Lars Huring, Olov Nilzén and Mammon Media and is released under the MIT License: + * http://www.opensource.org/licenses/mit-license.php + * + * + * SWFUpload Revision 7.0 is (c) 2007 Jake Roberts and is released under the MIT License: + * http://www.opensource.org/licenses/mit-license.php + * + */ \ No newline at end of file diff --git a/thirdparty/swfupload/swfupload.js b/thirdparty/swfupload/swfupload.js new file mode 100755 index 00000000..e1aaa3f7 --- /dev/null +++ b/thirdparty/swfupload/swfupload.js @@ -0,0 +1,1052 @@ +/** + * SWFUpload: http://www.swfupload.org, http://swfupload.googlecode.com + * + * mmSWFUpload 1.0: Flash upload dialog - http://profandesign.se/swfupload/, http://www.vinterwebb.se/ + * + * SWFUpload is (c) 2006-2007 Lars Huring, Olov Nilzén and Mammon Media and is released under the MIT License: + * http://www.opensource.org/licenses/mit-license.php + * + * SWFUpload 2 is (c) 2007-2008 Jake Roberts and is released under the MIT License: + * http://www.opensource.org/licenses/mit-license.php + * + */ + + +/* ******************* */ +/* Constructor & Init */ +/* ******************* */ +var SWFUpload; + +if (SWFUpload == undefined) { + SWFUpload = function (settings) { + this.initSWFUpload(settings); + }; +} + +SWFUpload.prototype.initSWFUpload = function (userSettings) { + try { + this.customSettings = {}; // A container where developers can place their own settings associated with this instance. + this.settings = {}; + this.eventQueue = []; + this.movieName = "SWFUpload_" + SWFUpload.movieCount++; + this.movieElement = null; + + + // Setup global control tracking + SWFUpload.instances[this.movieName] = this; + + // Load the settings. Load the Flash movie. + this.initSettings(userSettings); + this.loadFlash(); + this.displayDebugInfo(); + } catch (ex) { + delete SWFUpload.instances[this.movieName]; + throw ex; + } +}; + +/* *************** */ +/* Static Members */ +/* *************** */ +SWFUpload.instances = {}; +SWFUpload.movieCount = 0; +SWFUpload.version = "2.5.0 2009-11-04 Alpha"; +SWFUpload.QUEUE_ERROR = { + QUEUE_LIMIT_EXCEEDED : -100, + FILE_EXCEEDS_SIZE_LIMIT : -110, + ZERO_BYTE_FILE : -120, + INVALID_FILETYPE : -130 +}; +SWFUpload.UPLOAD_ERROR = { + HTTP_ERROR : -200, + MISSING_UPLOAD_URL : -210, + IO_ERROR : -220, + SECURITY_ERROR : -230, + UPLOAD_LIMIT_EXCEEDED : -240, + UPLOAD_FAILED : -250, + SPECIFIED_FILE_ID_NOT_FOUND : -260, + FILE_VALIDATION_FAILED : -270, + FILE_CANCELLED : -280, + UPLOAD_STOPPED : -290, + RESIZE_ERROR : -300 +}; +SWFUpload.FILE_STATUS = { + QUEUED : -1, + IN_PROGRESS : -2, + ERROR : -3, + COMPLETE : -4, + CANCELLED : -5 +}; +SWFUpload.UPLOAD_TYPE = { + NORMAL : -1, + RESIZED : -2 +}; + +SWFUpload.BUTTON_ACTION = { + SELECT_FILE : -100, + SELECT_FILES : -110, + START_UPLOAD : -120, + JAVASCRIPT : -130 +}; +SWFUpload.CURSOR = { + ARROW : -1, + HAND : -2 +}; +SWFUpload.WINDOW_MODE = { + WINDOW : "window", + TRANSPARENT : "transparent", + OPAQUE : "opaque" +}; + +SWFUpload.RESIZE_ENCODING = { + JPEG : -1, + PNG : -2 +}; + +// Private: takes a URL, determines if it is relative and converts to an absolute URL +// using the current site. Only processes the URL if it can, otherwise returns the URL untouched +SWFUpload.completeURL = function (url) { + try { + var path = "", indexSlash = -1; + if (typeof(url) !== "string" || url.match(/^https?:\/\//i) || url.match(/^\//) || url === "") { + return url; + } + + indexSlash = window.location.pathname.lastIndexOf("/"); + if (indexSlash <= 0) { + path = "/"; + } else { + path = window.location.pathname.substr(0, indexSlash) + "/"; + } + + return path + url; + } catch (ex) { + return url; + } +}; + + +/* ******************** */ +/* Instance Members */ +/* ******************** */ + +// Private: initSettings ensures that all the +// settings are set, getting a default value if one was not assigned. +SWFUpload.prototype.initSettings = function (userSettings) { + this.ensureDefault = function (settingName, defaultValue) { + var setting = userSettings[settingName]; + if (setting != undefined) { + this.settings[settingName] = setting; + } else { + this.settings[settingName] = defaultValue; + } + }; + + // Upload backend settings + this.ensureDefault("upload_url", ""); + + this.ensureDefault("preserve_relative_urls", false); + this.ensureDefault("file_post_name", "Filedata"); + this.ensureDefault("post_params", {}); + this.ensureDefault("use_query_string", false); + this.ensureDefault("requeue_on_error", false); + this.ensureDefault("http_success", []); + this.ensureDefault("assume_success_timeout", 0); + + // File Settings + this.ensureDefault("file_types", "*.*"); + this.ensureDefault("file_types_description", "All Files"); + this.ensureDefault("file_size_limit", 0); // Default zero means "unlimited" + this.ensureDefault("file_upload_limit", 0); + this.ensureDefault("file_queue_limit", 0); + + // Flash Settings + this.ensureDefault("flash_url", "swfupload.swf"); + this.ensureDefault("prevent_swf_caching", true); + + // Button Settings + this.ensureDefault("button_image_url", ""); + this.ensureDefault("button_width", 1); + this.ensureDefault("button_height", 1); + this.ensureDefault("button_text", ""); + this.ensureDefault("button_text_style", "color: #000000; font-size: 16pt;"); + this.ensureDefault("button_text_top_padding", 0); + this.ensureDefault("button_text_left_padding", 0); + this.ensureDefault("button_action", SWFUpload.BUTTON_ACTION.SELECT_FILES); + this.ensureDefault("button_disabled", false); + this.ensureDefault("button_placeholder_id", ""); + this.ensureDefault("button_placeholder", null); + this.ensureDefault("button_cursor", SWFUpload.CURSOR.ARROW); + this.ensureDefault("button_window_mode", SWFUpload.WINDOW_MODE.WINDOW); + + // Debug Settings + this.ensureDefault("debug", false); + this.settings.debug_enabled = this.settings.debug; // Here to maintain v2 API + + // Event Handlers + this.settings.return_upload_start_handler = this.returnUploadStart; + this.ensureDefault("swfupload_loaded_handler", null); + this.ensureDefault("file_dialog_start_handler", null); + this.ensureDefault("file_queued_handler", null); + this.ensureDefault("file_queue_error_handler", null); + this.ensureDefault("file_dialog_complete_handler", null); + + this.ensureDefault("upload_start_handler", null); + this.ensureDefault("upload_progress_handler", null); + this.ensureDefault("upload_error_handler", null); + this.ensureDefault("upload_success_handler", null); + this.ensureDefault("upload_complete_handler", null); + + this.ensureDefault("button_action_handler", null); + + this.ensureDefault("debug_handler", this.debugMessage); + + this.ensureDefault("custom_settings", {}); + + // Other settings + this.customSettings = this.settings.custom_settings; + + // Update the flash url if needed + if (!!this.settings.prevent_swf_caching) { + this.settings.flash_url = this.settings.flash_url + (this.settings.flash_url.indexOf("?") < 0 ? "?" : "&") + "preventswfcaching=" + new Date().getTime(); + } + + if (!this.settings.preserve_relative_urls) { + this.settings.upload_url = SWFUpload.completeURL(this.settings.upload_url); + this.settings.button_image_url = SWFUpload.completeURL(this.settings.button_image_url); + } + + delete this.ensureDefault; +}; + +// Private: loadFlash replaces the button_placeholder element with the flash movie. +SWFUpload.prototype.loadFlash = function () { + var targetElement, tempParent, wrapperType; + + // Make sure an element with the ID we are going to use doesn't already exist + if (document.getElementById(this.movieName) !== null) { + throw "ID " + this.movieName + " is already in use. The Flash Object could not be added"; + } + + // Get the element where we will be placing the flash movie + targetElement = document.getElementById(this.settings.button_placeholder_id) || this.settings.button_placeholder; + + if (targetElement == undefined) { + throw "Could not find the placeholder element: " + this.settings.button_placeholder_id; + } + + wrapperType = (targetElement.currentStyle && targetElement.currentStyle["display"] || window.getComputedStyle && document.defaultView.getComputedStyle(targetElement, null).getPropertyValue("display")) !== "block" ? "span" : "div"; + + // Append the container and load the flash + tempParent = document.createElement(wrapperType); + tempParent.innerHTML = this.getFlashHTML(); // Using innerHTML is non-standard but the only sensible way to dynamically add Flash in IE (and maybe other browsers) + + // Experiment -- try to get the movie element immediately + var els = tempParent.getElementsByTagName("object"); // FIXME - JSLint if this works + if (!els || els.length > 1 || els.length === 0) { + // Oh crap...bail + } else if (els.length === 1) { + this.movieElement = els[0]; + this.debug("Got the movie. WOOT!"); + } + + targetElement.parentNode.replaceChild(tempParent.firstChild, targetElement); + + // Fix IE Flash/Form bug + if (window[this.movieName] == undefined) { + window[this.movieName] = this.getMovieElement(); + } + +}; + +// Private: getFlashHTML generates the object tag needed to embed the flash in to the document +SWFUpload.prototype.getFlashHTML = function () { + // Flash Satay object syntax: http://www.alistapart.com/articles/flashsatay + return ['', + '', + '', + '', + '', + '', + '', + ''].join(""); +}; + +// Private: getFlashVars builds the parameter string that will be passed +// to flash in the flashvars param. +SWFUpload.prototype.getFlashVars = function () { + // Build a string from the post param object + var httpSuccessString, paramString; + + paramString = this.buildParamString(); + httpSuccessString = this.settings.http_success.join(","); + + // Build the parameter string + return ["movieName=", encodeURIComponent(this.movieName), + "&uploadURL=", encodeURIComponent(this.settings.upload_url), + "&useQueryString=", encodeURIComponent(this.settings.use_query_string), + "&requeueOnError=", encodeURIComponent(this.settings.requeue_on_error), + "&httpSuccess=", encodeURIComponent(httpSuccessString), + "&assumeSuccessTimeout=", encodeURIComponent(this.settings.assume_success_timeout), + "&params=", encodeURIComponent(paramString), + "&filePostName=", encodeURIComponent(this.settings.file_post_name), + "&fileTypes=", encodeURIComponent(this.settings.file_types), + "&fileTypesDescription=", encodeURIComponent(this.settings.file_types_description), + "&fileSizeLimit=", encodeURIComponent(this.settings.file_size_limit), + "&fileUploadLimit=", encodeURIComponent(this.settings.file_upload_limit), + "&fileQueueLimit=", encodeURIComponent(this.settings.file_queue_limit), + "&debugEnabled=", encodeURIComponent(this.settings.debug_enabled), + "&buttonImageURL=", encodeURIComponent(this.settings.button_image_url), + "&buttonWidth=", encodeURIComponent(this.settings.button_width), + "&buttonHeight=", encodeURIComponent(this.settings.button_height), + "&buttonText=", encodeURIComponent(this.settings.button_text), + "&buttonTextTopPadding=", encodeURIComponent(this.settings.button_text_top_padding), + "&buttonTextLeftPadding=", encodeURIComponent(this.settings.button_text_left_padding), + "&buttonTextStyle=", encodeURIComponent(this.settings.button_text_style), + "&buttonAction=", encodeURIComponent(this.settings.button_action), + "&buttonDisabled=", encodeURIComponent(this.settings.button_disabled), + "&buttonCursor=", encodeURIComponent(this.settings.button_cursor) + ].join(""); +}; + +// Public: get retrieves the DOM reference to the Flash element added by SWFUpload +// The element is cached after the first lookup +SWFUpload.prototype.getMovieElement = function () { + if (this.movieElement == undefined) { + this.movieElement = document.getElementById(this.movieName); + } + + if (this.movieElement === null) { + throw "Could not find Flash element"; + } + + return this.movieElement; +}; + +// Private: buildParamString takes the name/value pairs in the post_params setting object +// and joins them up in to a string formatted "name=value&name=value" +SWFUpload.prototype.buildParamString = function () { + var name, postParams, paramStringPairs = []; + + postParams = this.settings.post_params; + + if (typeof(postParams) === "object") { + for (name in postParams) { + if (postParams.hasOwnProperty(name)) { + paramStringPairs.push(encodeURIComponent(name.toString()) + "=" + encodeURIComponent(postParams[name].toString())); + } + } + } + + return paramStringPairs.join("&"); +}; + +// Public: Used to remove a SWFUpload instance from the page. This method strives to remove +// all references to the SWF, and other objects so memory is properly freed. +// Returns true if everything was destroyed. Returns a false if a failure occurs leaving SWFUpload in an inconsistant state. +// Credits: Major improvements provided by steffen +SWFUpload.prototype.destroy = function () { + var movieElement; + + try { + // Make sure Flash is done before we try to remove it + this.cancelUpload(null, false); + + // Stop the external interface check from running + this.callFlash("StopExternalInterfaceCheck"); + + movieElement = this.cleanUp(); + + // Remove the SWFUpload DOM nodes + if (movieElement) { + // Remove the Movie Element from the page + try { + movieElement.parentNode.removeChild(movieElement); + } catch (ex) {} + } + + // Remove IE form fix reference + window[this.movieName] = null; + + // Destroy other references + SWFUpload.instances[this.movieName] = null; + delete SWFUpload.instances[this.movieName]; + + this.movieElement = null; + this.settings = null; + this.customSettings = null; + this.eventQueue = null; + this.movieName = null; + + + return true; + } catch (ex2) { + return false; + } +}; + + +// Public: displayDebugInfo prints out settings and configuration +// information about this SWFUpload instance. +// This function (and any references to it) can be deleted when placing +// SWFUpload in production. +SWFUpload.prototype.displayDebugInfo = function () { + this.debug( + [ + "---SWFUpload Instance Info---\n", + "Version: ", SWFUpload.version, "\n", + "Movie Name: ", this.movieName, "\n", + "Settings:\n", + "\t", "upload_url: ", this.settings.upload_url, "\n", + "\t", "flash_url: ", this.settings.flash_url, "\n", + "\t", "use_query_string: ", this.settings.use_query_string.toString(), "\n", + "\t", "requeue_on_error: ", this.settings.requeue_on_error.toString(), "\n", + "\t", "http_success: ", this.settings.http_success.join(", "), "\n", + "\t", "assume_success_timeout: ", this.settings.assume_success_timeout, "\n", + "\t", "file_post_name: ", this.settings.file_post_name, "\n", + "\t", "post_params: ", this.settings.post_params.toString(), "\n", + "\t", "file_types: ", this.settings.file_types, "\n", + "\t", "file_types_description: ", this.settings.file_types_description, "\n", + "\t", "file_size_limit: ", this.settings.file_size_limit, "\n", + "\t", "file_upload_limit: ", this.settings.file_upload_limit, "\n", + "\t", "file_queue_limit: ", this.settings.file_queue_limit, "\n", + "\t", "debug: ", this.settings.debug.toString(), "\n", + + "\t", "prevent_swf_caching: ", this.settings.prevent_swf_caching.toString(), "\n", + + "\t", "button_placeholder_id: ", this.settings.button_placeholder_id.toString(), "\n", + "\t", "button_placeholder: ", (this.settings.button_placeholder ? "Set" : "Not Set"), "\n", + "\t", "button_image_url: ", this.settings.button_image_url.toString(), "\n", + "\t", "button_width: ", this.settings.button_width.toString(), "\n", + "\t", "button_height: ", this.settings.button_height.toString(), "\n", + "\t", "button_text: ", this.settings.button_text.toString(), "\n", + "\t", "button_text_style: ", this.settings.button_text_style.toString(), "\n", + "\t", "button_text_top_padding: ", this.settings.button_text_top_padding.toString(), "\n", + "\t", "button_text_left_padding: ", this.settings.button_text_left_padding.toString(), "\n", + "\t", "button_action: ", this.settings.button_action.toString(), "\n", + "\t", "button_disabled: ", this.settings.button_disabled.toString(), "\n", + + "\t", "custom_settings: ", this.settings.custom_settings.toString(), "\n", + "Event Handlers:\n", + "\t", "swfupload_loaded_handler assigned: ", (typeof this.settings.swfupload_loaded_handler === "function").toString(), "\n", + "\t", "file_dialog_start_handler assigned: ", (typeof this.settings.file_dialog_start_handler === "function").toString(), "\n", + "\t", "file_queued_handler assigned: ", (typeof this.settings.file_queued_handler === "function").toString(), "\n", + "\t", "file_queue_error_handler assigned: ", (typeof this.settings.file_queue_error_handler === "function").toString(), "\n", + "\t", "upload_start_handler assigned: ", (typeof this.settings.upload_start_handler === "function").toString(), "\n", + "\t", "upload_progress_handler assigned: ", (typeof this.settings.upload_progress_handler === "function").toString(), "\n", + "\t", "upload_error_handler assigned: ", (typeof this.settings.upload_error_handler === "function").toString(), "\n", + "\t", "upload_success_handler assigned: ", (typeof this.settings.upload_success_handler === "function").toString(), "\n", + "\t", "upload_complete_handler assigned: ", (typeof this.settings.upload_complete_handler === "function").toString(), "\n", + "\t", "debug_handler assigned: ", (typeof this.settings.debug_handler === "function").toString(), "\n" + ].join("") + ); +}; + +/* Note: addSetting and getSetting are no longer used by SWFUpload but are included + the maintain v2 API compatibility +*/ +// Public: (Deprecated) addSetting adds a setting value. If the value given is undefined or null then the default_value is used. +SWFUpload.prototype.addSetting = function (name, value, default_value) { + if (value == undefined) { + return (this.settings[name] = default_value); + } else { + return (this.settings[name] = value); + } +}; + +// Public: (Deprecated) getSetting gets a setting. Returns an empty string if the setting was not found. +SWFUpload.prototype.getSetting = function (name) { + if (this.settings[name] != undefined) { + return this.settings[name]; + } + + return ""; +}; + + + +// Private: callFlash handles function calls made to the Flash element. +// Calls are made with a setTimeout for some functions to work around +// bugs in the ExternalInterface library. +SWFUpload.prototype.callFlash = function (functionName, argumentArray) { + var movieElement, returnValue, returnString; + + argumentArray = argumentArray || []; + movieElement = this.getMovieElement(); + + // Flash's method if calling ExternalInterface methods (code adapted from MooTools). + try { + if (movieElement && movieElement.CallFunction) { + returnString = movieElement.CallFunction('' + __flash__argumentsToXML(argumentArray, 0) + ''); + returnValue = eval(returnString); + } else { + this.debug("Can't call flash because the movie wasn't found."); + } + } catch (ex) { + this.debug("Exception calling flash: " + ex.message); + } + + // Unescape file post param values + if (returnValue != undefined && typeof returnValue.post === "object") { + returnValue = this.unescapeFilePostParams(returnValue); + } + + return returnValue; +}; + +/* ***************************** + -- Flash control methods -- + Your UI should use these + to operate SWFUpload + ***************************** */ + +// WARNING: this function does not work in Flash Player 10 +// Public: selectFile causes a File Selection Dialog window to appear. This +// dialog only allows 1 file to be selected. +SWFUpload.prototype.selectFile = function () { + this.callFlash("SelectFile"); +}; + +// WARNING: this function does not work in Flash Player 10 +// Public: selectFiles causes a File Selection Dialog window to appear/ This +// dialog allows the user to select any number of files +// Flash Bug Warning: Flash limits the number of selectable files based on the combined length of the file names. +// If the selection name length is too long the dialog will fail in an unpredictable manner. There is no work-around +// for this bug. +SWFUpload.prototype.selectFiles = function () { + this.callFlash("SelectFiles"); +}; + + +// Public: startUpload starts uploading the first file in the queue unless +// the optional parameter 'fileID' specifies the ID +SWFUpload.prototype.startUpload = function (fileID) { + this.callFlash("StartUpload", [fileID]); +}; + +// Public: startUpload starts uploading the first file in the queue unless +// the optional parameter 'fileID' specifies the ID +SWFUpload.prototype.startResizedUpload = function (fileID, width, height, encoding, quality) { + this.callFlash("StartUpload", [fileID, { "width": width, "height" : height, "encoding" : encoding, "quality" : quality }]); +}; + +// Public: cancelUpload cancels any queued file. The fileID parameter may be the file ID or index. +// If you do not specify a fileID the current uploading file or first file in the queue is cancelled. +// If you do not want the uploadError event to trigger you can specify false for the triggerErrorEvent parameter. +SWFUpload.prototype.cancelUpload = function (fileID, triggerErrorEvent) { + if (triggerErrorEvent !== false) { + triggerErrorEvent = true; + } + this.callFlash("CancelUpload", [fileID, triggerErrorEvent]); +}; + +// Public: stopUpload stops the current upload and requeues the file at the beginning of the queue. +// If nothing is currently uploading then nothing happens. +SWFUpload.prototype.stopUpload = function () { + this.callFlash("StopUpload"); +}; + + +// Public: requeueUpload requeues any file. If the file is requeued or already queued true is returned. +// If the file is not found or is currently uploading false is returned. Requeuing a file bypasses the +// file size, queue size, upload limit and other queue checks. Certain files can't be requeued (e.g, invalid or zero bytes files). +SWFUpload.prototype.requeueUpload = function (indexOrFileID) { + return this.callFlash("RequeueUpload", [indexOrFileID]); +}; + + +/* ************************ + * Settings methods + * These methods change the SWFUpload settings. + * SWFUpload settings should not be changed directly on the settings object + * since many of the settings need to be passed to Flash in order to take + * effect. + * *********************** */ + +// Public: getStats gets the file statistics object. +SWFUpload.prototype.getStats = function () { + return this.callFlash("GetStats"); +}; + +// Public: setStats changes the SWFUpload statistics. You shouldn't need to +// change the statistics but you can. Changing the statistics does not +// affect SWFUpload accept for the successful_uploads count which is used +// by the upload_limit setting to determine how many files the user may upload. +SWFUpload.prototype.setStats = function (statsObject) { + this.callFlash("SetStats", [statsObject]); +}; + +// Public: getFile retrieves a File object by ID or Index. If the file is +// not found then 'null' is returned. +SWFUpload.prototype.getFile = function (fileID) { + if (typeof(fileID) === "number") { + return this.callFlash("GetFileByIndex", [fileID]); + } else { + return this.callFlash("GetFile", [fileID]); + } +}; + +// Public: getFileFromQueue retrieves a File object by ID or Index. If the file is +// not found then 'null' is returned. +SWFUpload.prototype.getQueueFile = function (fileID) { + if (typeof(fileID) === "number") { + return this.callFlash("GetFileByQueueIndex", [fileID]); + } else { + return this.callFlash("GetFile", [fileID]); + } +}; + + +// Public: addFileParam sets a name/value pair that will be posted with the +// file specified by the Files ID. If the name already exists then the +// exiting value will be overwritten. +SWFUpload.prototype.addFileParam = function (fileID, name, value) { + return this.callFlash("AddFileParam", [fileID, name, value]); +}; + +// Public: removeFileParam removes a previously set (by addFileParam) name/value +// pair from the specified file. +SWFUpload.prototype.removeFileParam = function (fileID, name) { + this.callFlash("RemoveFileParam", [fileID, name]); +}; + +// Public: setUploadUrl changes the upload_url setting. +SWFUpload.prototype.setUploadURL = function (url) { + this.settings.upload_url = url.toString(); + this.callFlash("SetUploadURL", [url]); +}; + +// Public: setPostParams changes the post_params setting +SWFUpload.prototype.setPostParams = function (paramsObject) { + this.settings.post_params = paramsObject; + this.callFlash("SetPostParams", [paramsObject]); +}; + +// Public: addPostParam adds post name/value pair. Each name can have only one value. +SWFUpload.prototype.addPostParam = function (name, value) { + this.settings.post_params[name] = value; + this.callFlash("SetPostParams", [this.settings.post_params]); +}; + +// Public: removePostParam deletes post name/value pair. +SWFUpload.prototype.removePostParam = function (name) { + delete this.settings.post_params[name]; + this.callFlash("SetPostParams", [this.settings.post_params]); +}; + +// Public: setFileTypes changes the file_types setting and the file_types_description setting +SWFUpload.prototype.setFileTypes = function (types, description) { + this.settings.file_types = types; + this.settings.file_types_description = description; + this.callFlash("SetFileTypes", [types, description]); +}; + +// Public: setFileSizeLimit changes the file_size_limit setting +SWFUpload.prototype.setFileSizeLimit = function (fileSizeLimit) { + this.settings.file_size_limit = fileSizeLimit; + this.callFlash("SetFileSizeLimit", [fileSizeLimit]); +}; + +// Public: setFileUploadLimit changes the file_upload_limit setting +SWFUpload.prototype.setFileUploadLimit = function (fileUploadLimit) { + this.settings.file_upload_limit = fileUploadLimit; + this.callFlash("SetFileUploadLimit", [fileUploadLimit]); +}; + +// Public: setFileQueueLimit changes the file_queue_limit setting +SWFUpload.prototype.setFileQueueLimit = function (fileQueueLimit) { + this.settings.file_queue_limit = fileQueueLimit; + this.callFlash("SetFileQueueLimit", [fileQueueLimit]); +}; + +// Public: setFilePostName changes the file_post_name setting +SWFUpload.prototype.setFilePostName = function (filePostName) { + this.settings.file_post_name = filePostName; + this.callFlash("SetFilePostName", [filePostName]); +}; + +// Public: setUseQueryString changes the use_query_string setting +SWFUpload.prototype.setUseQueryString = function (useQueryString) { + this.settings.use_query_string = useQueryString; + this.callFlash("SetUseQueryString", [useQueryString]); +}; + +// Public: setRequeueOnError changes the requeue_on_error setting +SWFUpload.prototype.setRequeueOnError = function (requeueOnError) { + this.settings.requeue_on_error = requeueOnError; + this.callFlash("SetRequeueOnError", [requeueOnError]); +}; + +// Public: setHTTPSuccess changes the http_success setting +SWFUpload.prototype.setHTTPSuccess = function (http_status_codes) { + if (typeof http_status_codes === "string") { + http_status_codes = http_status_codes.replace(" ", "").split(","); + } + + this.settings.http_success = http_status_codes; + this.callFlash("SetHTTPSuccess", [http_status_codes]); +}; + +// Public: setHTTPSuccess changes the http_success setting +SWFUpload.prototype.setAssumeSuccessTimeout = function (timeout_seconds) { + this.settings.assume_success_timeout = timeout_seconds; + this.callFlash("SetAssumeSuccessTimeout", [timeout_seconds]); +}; + +// Public: setDebugEnabled changes the debug_enabled setting +SWFUpload.prototype.setDebugEnabled = function (debugEnabled) { + this.settings.debug_enabled = debugEnabled; + this.callFlash("SetDebugEnabled", [debugEnabled]); +}; + +// Public: setButtonImageURL loads a button image sprite +SWFUpload.prototype.setButtonImageURL = function (buttonImageURL) { + if (buttonImageURL == undefined) { + buttonImageURL = ""; + } + + this.settings.button_image_url = buttonImageURL; + this.callFlash("SetButtonImageURL", [buttonImageURL]); +}; + +// Public: setButtonDimensions resizes the Flash Movie and button +SWFUpload.prototype.setButtonDimensions = function (width, height) { + this.settings.button_width = width; + this.settings.button_height = height; + + var movie = this.getMovieElement(); + if (movie != undefined) { + movie.style.width = width + "px"; + movie.style.height = height + "px"; + } + + this.callFlash("SetButtonDimensions", [width, height]); +}; +// Public: setButtonText Changes the text overlaid on the button +SWFUpload.prototype.setButtonText = function (html) { + this.settings.button_text = html; + this.callFlash("SetButtonText", [html]); +}; +// Public: setButtonTextPadding changes the top and left padding of the text overlay +SWFUpload.prototype.setButtonTextPadding = function (left, top) { + this.settings.button_text_top_padding = top; + this.settings.button_text_left_padding = left; + this.callFlash("SetButtonTextPadding", [left, top]); +}; + +// Public: setButtonTextStyle changes the CSS used to style the HTML/Text overlaid on the button +SWFUpload.prototype.setButtonTextStyle = function (css) { + this.settings.button_text_style = css; + this.callFlash("SetButtonTextStyle", [css]); +}; +// Public: setButtonDisabled disables/enables the button +SWFUpload.prototype.setButtonDisabled = function (isDisabled) { + this.settings.button_disabled = isDisabled; + this.callFlash("SetButtonDisabled", [isDisabled]); +}; +// Public: setButtonAction sets the action that occurs when the button is clicked +SWFUpload.prototype.setButtonAction = function (buttonAction) { + this.settings.button_action = buttonAction; + this.callFlash("SetButtonAction", [buttonAction]); +}; + +// Public: setButtonCursor changes the mouse cursor displayed when hovering over the button +SWFUpload.prototype.setButtonCursor = function (cursor) { + this.settings.button_cursor = cursor; + this.callFlash("SetButtonCursor", [cursor]); +}; + + +/* ******************************* + Flash Event Interfaces + These functions are used by Flash to trigger the various + events. + + All these functions a Private. + + Because the ExternalInterface library is buggy the event calls + are added to a queue and the queue then executed by a setTimeout. + This ensures that events are executed in a determinate order and that + the ExternalInterface bugs are avoided. +******************************* */ + +SWFUpload.prototype.queueEvent = function (handlerName, argumentArray) { + // Warning: Don't call this.debug inside here or you'll create an infinite loop + var self = this; + + if (argumentArray == undefined) { + argumentArray = []; + } else if (!(argumentArray instanceof Array)) { + argumentArray = [argumentArray]; + } + + if (typeof this.settings[handlerName] === "function") { + // Queue the event + this.eventQueue.push(function () { + this.settings[handlerName].apply(this, argumentArray); + }); + + // Execute the next queued event + setTimeout(function () { + self.executeNextEvent(); + }, 0); + + } else if (this.settings[handlerName] !== null) { + throw "Event handler " + handlerName + " is unknown or is not a function"; + } +}; + +// Private: Causes the next event in the queue to be executed. Since events are queued using a setTimeout +// we must queue them in order to garentee that they are executed in order. +SWFUpload.prototype.executeNextEvent = function () { + // Warning: Don't call this.debug inside here or you'll create an infinite loop + + var f = this.eventQueue ? this.eventQueue.shift() : null; + if (typeof(f) === "function") { + f.apply(this); + } +}; + +// Private: unescapeFileParams is part of a workaround for a flash bug where objects passed through ExternalInterface cannot have +// properties that contain characters that are not valid for JavaScript identifiers. To work around this +// the Flash Component escapes the parameter names and we must unescape again before passing them along. +SWFUpload.prototype.unescapeFilePostParams = function (file) { + var reg = /[$]([0-9a-f]{4})/i, unescapedPost = {}, uk, k, match; + + if (file != undefined) { + for (k in file.post) { + if (file.post.hasOwnProperty(k)) { + uk = k; + while ((match = reg.exec(uk)) !== null) { + uk = uk.replace(match[0], String.fromCharCode(parseInt("0x" + match[1], 16))); + } + unescapedPost[uk] = file.post[k]; + } + } + + file.post = unescapedPost; + } + + return file; +}; + +// Private: Called by Flash to see if JS can call in to Flash (test if External Interface is working) +SWFUpload.prototype.testExternalInterface = function () { + try { + return this.callFlash("TestExternalInterface"); + } catch (ex) { + return false; + } +}; + +// Private: This event is called by Flash when it has finished loading. Don't modify this. +// Use the swfupload_loaded_handler event setting to execute custom code when SWFUpload has loaded. +SWFUpload.prototype.flashReady = function () { + // Check that the movie element is loaded correctly with its ExternalInterface methods defined + var movieElement = this.getMovieElement(); + + if (!movieElement) { + this.debug("Flash called back ready but the flash movie can't be found."); + return; + } + + this.cleanUp(); + + this.queueEvent("swfupload_loaded_handler"); +}; + +// Private: removes Flash added fuctions to the DOM node to prevent memory leaks in IE. +// This function is called by Flash each time the ExternalInterface functions are created. +SWFUpload.prototype.cleanUp = function () { + var key, movieElement = this.getMovieElement(); + + // Pro-actively unhook all the Flash functions + try { + if (movieElement && typeof(movieElement.CallFunction) === "unknown") { // We only want to do this in IE + this.debug("Removing Flash functions hooks (this should only run in IE and should prevent memory leaks)"); + for (key in movieElement) { + try { + if (typeof(movieElement[key]) === "function") { + movieElement[key] = null; + } + } catch (ex) { + } + } + } + } catch (ex1) { + + } + + // Fix Flashes own cleanup code so if the SWF Movie was removed from the page + // it doesn't display errors. + window["__flash__removeCallback"] = function (instance, name) { + try { + if (instance) { + instance[name] = null; + } + } catch (flashEx) { + + } + }; + + return movieElement; +}; + +/* When the button_action is set to JavaScript this event gets fired and executes the button_action_handler */ +SWFUpload.prototype.buttonAction = function () { + this.queueEvent("button_action_handler"); +}; + +/* This is a chance to do something before the browse window opens */ +SWFUpload.prototype.fileDialogStart = function () { + this.queueEvent("file_dialog_start_handler"); +}; + + +/* Called when a file is successfully added to the queue. */ +SWFUpload.prototype.fileQueued = function (file) { + file = this.unescapeFilePostParams(file); + this.queueEvent("file_queued_handler", file); +}; + + +/* Handle errors that occur when an attempt to queue a file fails. */ +SWFUpload.prototype.fileQueueError = function (file, errorCode, message) { + file = this.unescapeFilePostParams(file); + this.queueEvent("file_queue_error_handler", [file, errorCode, message]); +}; + +/* Called after the file dialog has closed and the selected files have been queued. + You could call startUpload here if you want the queued files to begin uploading immediately. */ +SWFUpload.prototype.fileDialogComplete = function (numFilesSelected, numFilesQueued, numFilesInQueue) { + this.queueEvent("file_dialog_complete_handler", [numFilesSelected, numFilesQueued, numFilesInQueue]); +}; + +SWFUpload.prototype.uploadStart = function (file) { + file = this.unescapeFilePostParams(file); + this.queueEvent("return_upload_start_handler", file); +}; + +SWFUpload.prototype.returnUploadStart = function (file) { + var returnValue; + if (typeof this.settings.upload_start_handler === "function") { + file = this.unescapeFilePostParams(file); + returnValue = this.settings.upload_start_handler.call(this, file); + } else if (this.settings.upload_start_handler != undefined) { + throw "upload_start_handler must be a function"; + } + + // Convert undefined to true so if nothing is returned from the upload_start_handler it is + // interpretted as 'true'. + if (returnValue === undefined) { + returnValue = true; + } + + returnValue = !!returnValue; + + this.callFlash("ReturnUploadStart", [returnValue]); +}; + + + +SWFUpload.prototype.uploadProgress = function (file, bytesComplete, bytesTotal) { + file = this.unescapeFilePostParams(file); + this.queueEvent("upload_progress_handler", [file, bytesComplete, bytesTotal]); +}; + +SWFUpload.prototype.uploadError = function (file, errorCode, message) { + file = this.unescapeFilePostParams(file); + this.queueEvent("upload_error_handler", [file, errorCode, message]); +}; + +SWFUpload.prototype.uploadSuccess = function (file, serverData, responseReceived) { + file = this.unescapeFilePostParams(file); + this.queueEvent("upload_success_handler", [file, serverData, responseReceived]); +}; + +SWFUpload.prototype.uploadComplete = function (file) { + file = this.unescapeFilePostParams(file); + this.queueEvent("upload_complete_handler", file); +}; + +/* Called by SWFUpload JavaScript and Flash functions when debug is enabled. By default it writes messages to the + internal debug console. You can override this event and have messages written where you want. */ +SWFUpload.prototype.debug = function (message) { + this.queueEvent("debug_handler", message); +}; + + +/* ********************************** + Debug Console + The debug console is a self contained, in page location + for debug message to be sent. The Debug Console adds + itself to the body if necessary. + + The console is automatically scrolled as messages appear. + + If you are using your own debug handler or when you deploy to production and + have debug disabled you can remove these functions to reduce the file size + and complexity. +********************************** */ + +// Private: debugMessage is the default debug_handler. If you want to print debug messages +// call the debug() function. When overriding the function your own function should +// check to see if the debug setting is true before outputting debug information. +SWFUpload.prototype.debugMessage = function (message) { + var exceptionMessage, exceptionValues, key; + + if (this.settings.debug) { + exceptionValues = []; + + // Check for an exception object and print it nicely + if (typeof message === "object" && typeof message.name === "string" && typeof message.message === "string") { + for (key in message) { + if (message.hasOwnProperty(key)) { + exceptionValues.push(key + ": " + message[key]); + } + } + exceptionMessage = exceptionValues.join("\n") || ""; + exceptionValues = exceptionMessage.split("\n"); + exceptionMessage = "EXCEPTION: " + exceptionValues.join("\nEXCEPTION: "); + SWFUpload.Console.writeLine(exceptionMessage); + } else { + SWFUpload.Console.writeLine(message); + } + } +}; + +SWFUpload.Console = {}; +SWFUpload.Console.writeLine = function (message) { + var console, documentForm; + + try { + console = document.getElementById("SWFUpload_Console"); + + if (!console) { + documentForm = document.createElement("form"); + document.getElementsByTagName("body")[0].appendChild(documentForm); + + console = document.createElement("textarea"); + console.id = "SWFUpload_Console"; + console.style.fontFamily = "monospace"; + console.setAttribute("wrap", "off"); + console.wrap = "off"; + console.style.overflow = "auto"; + console.style.width = "400px"; + console.style.height = "450px"; + + // ss fixes + console.style.position = "absolute"; + console.style.top = "5px"; + console.style.zIndex = "100"; + + documentForm.appendChild(console); + } + + console.value += message + "\n"; + + console.scrollTop = console.scrollHeight - console.clientHeight; + } catch (ex) { + alert("Exception: " + ex.name + " Message: " + ex.message); + } +}; diff --git a/thirdparty/swfupload/swfupload.queue.js b/thirdparty/swfupload/swfupload.queue.js new file mode 100755 index 00000000..69e619da --- /dev/null +++ b/thirdparty/swfupload/swfupload.queue.js @@ -0,0 +1,98 @@ +/* + Queue Plug-in + + Features: + *Adds a cancelQueue() method for cancelling the entire queue. + *All queued files are uploaded when startUpload() is called. + *If false is returned from uploadComplete then the queue upload is stopped. + If false is not returned (strict comparison) then the queue upload is continued. + *Adds a QueueComplete event that is fired when all the queued files have finished uploading. + Set the event handler with the queue_complete_handler setting. + + */ + +var SWFUpload; +if (typeof(SWFUpload) === "function") { + SWFUpload.queue = {}; + + SWFUpload.prototype.initSettings = (function (oldInitSettings) { + return function () { + if (typeof(oldInitSettings) === "function") { + oldInitSettings.call(this); + } + + this.queueSettings = {}; + + this.queueSettings.queue_cancelled_flag = false; + this.queueSettings.queue_upload_count = 0; + + this.queueSettings.user_upload_complete_handler = this.settings.upload_complete_handler; + this.queueSettings.user_upload_start_handler = this.settings.upload_start_handler; + this.settings.upload_complete_handler = SWFUpload.queue.uploadCompleteHandler; + this.settings.upload_start_handler = SWFUpload.queue.uploadStartHandler; + + this.settings.queue_complete_handler = this.settings.queue_complete_handler || null; + }; + })(SWFUpload.prototype.initSettings); + + SWFUpload.prototype.startUpload = function (fileID) { + this.queueSettings.queue_cancelled_flag = false; + this.callFlash("StartUpload", [fileID]); + }; + + SWFUpload.prototype.cancelQueue = function () { + this.queueSettings.queue_cancelled_flag = true; + this.stopUpload(); + + var stats = this.getStats(); + while (stats.files_queued > 0) { + this.cancelUpload(); + stats = this.getStats(); + } + }; + + SWFUpload.queue.uploadStartHandler = function (file) { + var returnValue; + if (typeof(this.queueSettings.user_upload_start_handler) === "function") { + returnValue = this.queueSettings.user_upload_start_handler.call(this, file); + } + + // To prevent upload a real "FALSE" value must be returned, otherwise default to a real "TRUE" value. + returnValue = (returnValue === false) ? false : true; + + this.queueSettings.queue_cancelled_flag = !returnValue; + + return returnValue; + }; + + SWFUpload.queue.uploadCompleteHandler = function (file) { + var user_upload_complete_handler = this.queueSettings.user_upload_complete_handler; + var continueUpload; + + if (file.filestatus === SWFUpload.FILE_STATUS.COMPLETE) { + this.queueSettings.queue_upload_count++; + } + + if (typeof(user_upload_complete_handler) === "function") { + continueUpload = (user_upload_complete_handler.call(this, file) === false) ? false : true; + } else if (file.filestatus === SWFUpload.FILE_STATUS.QUEUED) { + // If the file was stopped and re-queued don't restart the upload + continueUpload = false; + } else { + continueUpload = true; + } + + if (continueUpload) { + var stats = this.getStats(); + if (stats.files_queued > 0 && this.queueSettings.queue_cancelled_flag === false) { + this.startUpload(); + } else if (this.queueSettings.queue_cancelled_flag === false) { + this.queueEvent("queue_complete_handler", [this.queueSettings.queue_upload_count]); + this.queueSettings.queue_upload_count = 0; + } else { + this.queueSettings.queue_cancelled_flag = false; + this.queueSettings.queue_upload_count = 0; + } + } + }; +} \ No newline at end of file diff --git a/thirdparty/swfupload/swfupload.swf b/thirdparty/swfupload/swfupload.swf new file mode 100755 index 0000000000000000000000000000000000000000..71ff884c33caf257d0d4bc101027d4b0a974d42e GIT binary patch literal 33328 zcmZ^|WlSAR`0a~Zad)S}jXS63{&Vj=UrsVJ z$$WW|`DM+@GqWVL)RCTFAs{^08oLmEHKdwF{LfkZ-rOxLzWtdqf$2ksD&s7m3Zu4# zilsg|84XdIQ!J1bnBRnS`nmOu94VNx9swz$b%Nol01ByfClO{JbxEw{qQ zN0#u&Z|m)AKU;6TTwSxYLMg|kBC|YgV@7svSeiaZRw^ThM)vjE-GM{4olAoNpRd_6 z;&^y1v;9W2=yR@t0kfQJrRDlyEa~n$+UU2i?~j)r;32%Hsq5{QfG^?R6Rcb{Jn-g9 zDT}Yt%miN$Wk4&Xh5=bQ>XH}TB_kS--8UwOG;Qhn$v(1NFg5$Qo z*N13Xy@@e7e#L_n%iZGgvWC`kg#I?sTS#Rv4zI$a;_VaS!gIf7+G8w*TF!rNMZ*C) zV&=6Q*92<&J+qv>>gbg-b+AYjTEha~IvZ?$8iF;H+UqUC*j2V=qIpo{LyRL@6qpYv zhun+13;`$gVeLd`!AVkBb^86~2rqsK#*|?>GKbvV?U5+mk)IP$GI#ZsnNPELU?Uy@ zzA+auP-%ew=THG&vX|91aI)E%Eg(&HlY>y;_dsGlC@<8Gw;V-3Xwe@=^ z5c5mQ&9AuR-eNNTjz!l=X5?EM$@?pa_a`aS__Icv21BxPF2Ji=zAw`e0{cOkAMn2N)Uz^IIT@FOb0qXvKQkl%t)U$6PD_(+)@M8V(QG`sdJPsX{bef{}b)8a-Ehv`P zadJmoaB6cpp!D|%_m%h=Ixj=RmzHL`@Sx@1>vv+0`i1)IhJ@?~ulRe4aL@cP+AGBU z@bCl?xYXWXsr#~Arjn2dk4ot7HZ|j^r@WijZY%3-srcKr23n2=PoBnOo{UPCo0cHRWzHYMOTvLas{V{t?AZ4^)Pk=kp=u zE`PJXL`jC-HS*hOaK#GV4;gzj>pUO2jR1@HK!YsjahU_IYtI1nkAqD&qO9CC*A3o_ zNcInZ;(O1ZQ{dYY2Y7?}(}bx-{yY@I9tKzAjl!v4ON5C6^x6g)xH-w)P2Feh*xmfM z?@5+2ZPKtr{huaLHt*{!VZ^aHcoUUqn#%o9MB3ViHLdy2!x17H$CU(z;cPpVH^>pS4J*B#^9;p@ut)n>JF5n?NKdRbPv_k^(K1)nAK`&bm~ ztX5@ZqBwC@%jdZvV|{C{gaLyNh4*s9L4TS_(Sir{R_MRCD>4TQmE zPGv28VXBu@3?12}Qtbgs&M~gohp)oE?H#-}D~g2MC8tlm&co%xRTeuNlm{70o&keI zdv?PGek*1|@lpt3Ej2+CTqHkk?!)dVBH}_K>xmDF8G1(4T#ioAT)=)?so0JgKM)g$ ztpU76IT?6ycIN;tz|p=G;#<&=WQ`K=x|_8W4Veb-BGiy58RnFwDV0BkcjVQ#7QKG| z8a-P(I}l7LjL?sBou*IVW8|A&Egj6iiW~lsl|A0dhJmPv;RE2GUJ1cTa^01AKEewo zFPDsJ#Blx#PV{IWHQHjUYn|3Y&Cl+X_(epSV7z&wdjd!=rUqamgsSY@*ShcXj}_sS zOF^ZiHhgW&a{)t0mqYWpLOXKcDi;Fw=}WkPhL{;@``2Ky-^0%gjLQ6E?(zNEQWkk| zrGJ9&JLi93^Mv&Gsc<-9gF~xweuuD{ihp_=jfyOh4aEzJ1C(TtH6= zGnm$QZGV*skBB@l#fJ)@S2QRw5GEaK9H(z4G$`e(|GAW1{2U`O9r85|q3R@(9Zf_o z!g8bL_(*9hMV|!vu~T=TZ7Ss(toBniyghfq8QND8mR5?*jiM78=7{X|=ho>8Gp;U` zgUTDD1Zh+=EnU156&2iaR@w&6q56ufRSjtH)&|ZC63;gdEcL-4o z<<{WXC4a>^o#~b`Y-Mqnj`*71gvH&6o@p{9S^|{_GMY%soc$-!?Pp1M@kj(OV0=jM zbFl;!eFL7Pk{Z_;IyQi)+(NBruRY4xyr0L4w*JD}7r9GWy=4*C&O#Y3=gd#OqTJDQ zxA(lFuGM(V5I&0!8(A9kP1<pjnEb~7%A(BB;nOk-0 zg%&&DF}1ddgA*2N;RB6C`Hr+i8Z}MIjxF1T2&3$*hn3n zTMk?yR3bm7b=i(>i9|g)pcquJY-OzwrWnpWr{Xa%YFyj>bZWW$=Sfn1G9oFJx4Pp? zH2`!QS|MA5WGW^3`d$iTlBdKhIdWG1B{Zuxtjag3OjBxVR2v6CJB2-~~fm3SgnBcLolQ1L&OEb`(XP+Y>iv(NhO2+A3#z()8r(x#@ zjeD`uucoVH@m(yk+7ej0LwtrFjul;k1QyGxALbq6ZWT~FuPi-GB?!Md{!uS2iD;L> zsidQ;ueJK1@j-N+0>=q{Ftp|}5~VxUFRR^O+Ew_AnCxU8>p z#=^)*N1y^sh+1k(EWhdX`#Ulu+qtJZW30 z9*nph#tVPx;J2h{I*u8B8a0&1%uzw^7Ds`os;x1+m);Y~Yogc(g@UFh#Y7Kj4!|7L z$^BJ!6}pU0&UOUDSzMxb=9T@B>4^78Dvoz_)C7oF3jk`hJ-AUFke`V9($&`2*U(?+ zrYMn-A@Q}4N^CnV9MU;-GK8O1kn_r}EHLnzBrz4_Q-cPRHaz~gnI>aEURr$d!Vy?i z$J%h#`8AS~>MfIo6Gx;M42jH$Z;(uB?X+1%*Oh`-8y#w-@*k~)jx2a|uYazdVn7Br z%~g)8zHnc(^vCzKMJKVpbpczUUN7&>)yh5oez&YQ*b56z-Whfqr!1gRt)$s(%m9mo{w$U|Ec+Ej-n3LiQ<#g-;=%O~ zdT?AM6Eg7}KAaoO-IxP5*QcVxVU9!IB<0ob1){uEOKi9FgUWIc(|#9ihdBO~j-60` zzn7hxt=W&)QSzAV6}A85T`4_;4?9cL)qhF!jr|CSc>l^k#D#Y=tWCUQmZ%D-=p3n# z*pM#aRv(_vNXJ9wrCf=N)y`TSZaIlEkSiLho76j2W{rPk2-kSCVK5Mvk0iH~sPtjFW|{1@az zOd$MP5u7j({S3$0^;5wKsK?srW=6e*2%f@k8Ee?L)ZHLagUFO3Ni>A?KxuS(8jL<& z`LrSPXucu3D%d$_pSB}nq<@GbP}j#ca<&6&BR^%%nFzN&j`?QLgVP*Ii1u2%8wEG_ z|HGs>r(>qyXF4pkaW9x8RCUx8ligj}HI?hgUemd-5)1>m-T&IQ*MFL_SePw{onwNhAA zqm=s5o`Xe5mCD9b zrSUImX{T{qdZE3e`9V$@mt58C0b_q*vht01mc+v-|EmykT-Qu4iVp8Vkh+WZZ|Dck zxUEZ80_HWX`-qoa!6dvGK))JGb=;I?`broVOq^C zVbW?rHntl=tk|3Pz&No@=WiYgSM6>?fS)GV8hdefc%?1Q6D2ePuJf2(K}zd~$LQT= z9@)z54Y8by2E(z0)8|#qaXMO)24_((mHO<<>1qaosx2Ep=>^)O=3{4D$NG79Px=RK ziIh*mZR`{!^3qFcmk4Wy>VlXh=`Kzc0{R+yA`ea7f)08rVp{~wXH(&>>D~X#b3%tdc)98834wLDB}*?WWk+C^cqI$`i>jJY89cH(`kfS2DUt(HYF%fu zY=|{|?*#1N6XqXp|J`4S1^RRks-E19>I@1=)l8pz>Q1c6IdVu4p?q z&-z>9*7$jvqQrw{@*>v?boDn?n;%qX^J*Xl!nD=lw9;4K-9UT(q35Eg8Bw z8blf9#&gfnXECA97F(BjIt? z?V_WeZd-|EHpaspy;SHvgcc-7*5R-Vs)K*Oaf~`KVGqk%Qb-n*zFn?PRHAKjLZ~E$ z#=W4rF6|2DW2_3@e^I`ogH28*49Ed0h6fD`$uM-0yWPp{VRKm~fi30Ur}71rL=+TT zr(8!ib1Ph-GgIjn4C-u*!&@DcxuX0{*)2}(2m6bqCTU%c(QB<04 zA!lzkES`mkb4d`Jh9(32qEF+9>n#%-)Tent2$<9Jgyp4~(=!k*avG=Ehbwfq0&8n2 z-2T)EVc?U?FH=2jBW{F;f^#Q_s#a+-)u5#%&VS-3Ydl*U zTLNEm3cJi{LSd<*V;#9{{*xf#ts>uIL+2V)wysCZZXVk`>Lz4gR&p(?t!OV%VHlmf*q7U+^jMug)I!jE5Tim zs$fSjN_WnImC~9;k5=;ouV&0vz@n%Wv6Y`$UZ0qh&d3!5pBXCNVShONCTJ@9zG&>m zM++~Jq80A@0E(#Ds3$crqg6ys0PfJqu%qs=@k*6(;arr3Anx|GBgrrDV`x@ZF!oEg z1( zI#sfjeuY}-iJU}yq!<1%6W#uNdBJ<2F>)ws2l@3&ZHVr6P0LO)Vdnq#2u;_mVhJeI zqr^07|4qM`#MHO)z$G~y5s)ELyEqY!S|_F*oV9ckH1BgfI!|#DTZfNa1p@_qHNgLRBE2QWku0$VWmDX%~>#mGF2m z?}ZEXzVQ$&DohxjhTHBDUf^Tt&4-@Km$1T8o`dgGG8Py5ucWq>#(O!oZ+5|kXt$(DP_!S{p z7s&jRyHYyZ$|@+GigI9jAnehUSL0D|=(&FponA$iLFnW5ZYGw@swISQR!MSVeV$@) z{bnWBmz{t200Q-Y_j)Nw=g6OTa;ux||i@o!jbEbQ}paI~zorx?E{zu7Q8`urh18 zncQi~lM2^%0#99SLlzf_9m351H!0QP5GyE%^s^!?PR2ic5U0jHGSyoLMUL}~(7KHu zA2*FYg=Ek`qxCyJB6M1u(alv&Kha?w03Nz9=`cvH?@4xrN(s>n_K)@5yIi;8ExXk-265n*P zPlPwXFC{aatrmATy)dgRz$o-kw@9GZ--vx%mGbi#_1dDqD>j?vwgb zRr64}Q;RqMi`IL5$GCxY>1Fwr3LdBeRq~ZODV1_JpR<~j6LX#7_J(pI;yyW|e^6pN zx4f0XVwi<$=6o^izBsbD@K-^Sw(yda^%Qm`l62Z}-93^39K$cKc5|1X{d75evt&^p zqq~!4g;DP1^0~BUu`TO$Dlev*@!W%SYFj$ET~V#)WqiSSd70#?iV}W)|5ZIdCk377 zdd0DQFs*GP<6Y8bBGxbO^Ycs_P@_m9gZzNt2vKU8#h6==MXj8 zj672oE%1j#OBTM@M(eTR*N9MWtJuGPv^!o0Kss+E?EF_Xqms{hu`J*m?$;5zPg_|=~OZq#)6m8rcIoifpMcsuBPh1@b-z`^pJ(?l6X zGVI3l?rOf3gRsAokE>XLjcVW((MYFONq^a#+K_ZW?mNnmvqPGb1@>L7e(X;+XZIhq z`6X(^&?zaYKne!uMe{!+6zNCUT13!7I^cz>mxu{#yyZAeVx@QlJQtl6Wn2S3P5q;{ zP{b9`r9c>q{-{*MXd2u))^($PDoSMwnZNtXox^IC`K&83xt$FkJnF^mt zWVS%vP#EoI6mY_qM$Cy~pfhppegRIRnE`h9x8rX&*6Mn7;1GimKK^GrU8uh-QN!zq zmU^JVtL5>ZOj>4Y*jOq_8qI7)f||X1*>P190xxPf-D#Q?k4EF$Y1!$3Ac4%!uJFvx zJH1_PNk4rb_&?~nc;eVBNWUs+`ATx4bKgbog{Qs)^j$*wZ8p+w!tx*mA1T!Pn-0P3`!-T1 zd3ZO}0Z^K)9mcQVpj74?E`cfnwFXdzM`KKx9! zjVd4Epx?(<%SYT2O8!XOwW%8*tGB}buP@xb46jEMI0=AwcjD4+O?AA&*tvIR{W#Ai zV1_40wxOC-wmTn98jQ8`Jbm&77KOu!@cDn_(aMQ<`#x;E2*?;C8%J) zPK!JYO^)k^w~JeQ=B3IpHjgwn}D2`5mDbh6Eh5 z$yLjE<2#}_-RxAjz&KvH+`hC?kYCWB1>kZ{LZiB5uEK1yS<|(>zv;n2m zmLuq5U{9eEEEZacEIpW{&r8#$c8`z4Faq~AT5|TtNFvktt z49Go8D$zc?3erihTj$vK<%E*Y$B*J;3Q3DsjNI>alzdrm1_$*_5Wm3WB3lEbPV*Ki z7V#9J%6v|eZ3gHyr^8rDE?8wlLJ35cIDd=0pQDQ`g$$m*>92x;+JGoJ^s9o9iq-wr z7n{r8*0>_)=IC%0XoJ;U^$$c;ym%G?*ff;&cx?9}QuPM;m=ke@T|?LPbaE_-4YV|H zO7X+Z;*!x`lzHi$oOz#UM&8zE2uhv%DQyYlc}pAv|DT*k8gt#f!s3OHx0p$u7BZ3~ zqs(_Qe^ufy7={@chwH+bH0Rp}-IODJPciFaw?ay$+k|EStq2vKjVc)_c2Tp))HH9I z4vWRyMf=h|>v>CAwW0Chf!<6p?dz{5RD=SRhuEc=PN)qkEO!);6@tzdfm3;j9$qNu z_QVvUc*(<5P?bT2nOTY8v}^5;AP1ROP$T=w9tQ76rKLJdW<%!sdICM%msC}NlUBotA5La;b_d8uQ3HpK>1kg`(+%Hd1(hs~1qDlFise|z=*l6=!d!TCrjv@wYm zHEoz+lCp8M>w4&nQQy~;T-KN?{Fj05JemO~{cL^41f)-1^Q)SS_(OTWZwYHgRmO9~ zo#HC_e!?+K)vq#V8FgO?@USnoXVTv#pb1tk*37!Fw2#_R^)j)1ZnMh0dGwK=y{>Qj z`Pq+OyEv_SdYLrsUk6CI0wz@Nz-hSQX)b+IpeP2TGW2Y^h}H{CCNf>*d}Bo&HyTEl zNLty`r*H5C`oKOm{ucw1V ze7Nq~d4KCAmN9vrQk627*J5Y4KzY&#uGk)Qmykb4a5n0eX?VH{?olH@`Clv+*J2-v z1DI;jm~-U;k5rvKt<_Wi(T06wVS_Q5FGMj~b8;G6`0-F2xkIe08a5&A3f8oa2?4&A z1cNU(!Lz76qlj-*OGI5UgIdn~FAPF&rVo24@M-)-_ctD%LP%0Iuh`%;@5McY=yQ>= z`yN+|%~;Dr4N@X4fe`g5O!S{F?;=I`gGY`7|-4oSYJt=;PGSZ2!GWLY0NxfvDk8N;3OT%a)hOm$0UC5n;|k4 z{N$q%ccfH^X`cjUG)C_6OJ4mlDZ@wfez^2>3Ukk%Z#c$`={9XFMT>pZ8FXpkB%_6w z{dwQc8bdmR0`)UkwH}ig-zHL^55~X!8;9f32je2;32U#uuQ%EvulkaCpZ9IQg`rPe zf~1RI-UR~#-oOq4FD3rBig@F^6wX1u^ALw6{vQy~#FEY3BCr9NVj>v&)WM&Wttv3k zl8$120Xe*;q0m*ec{l}$-s=BK{zsPE87M5eU{A^Aive%?3dy1d`H|dT;N+~DFHn^n zfP|D{a&2s?(Gz|0II8Tz*{jM0sw%71V6H%gIq{PdW^aP?#^kL_a9j$7;h}8m{)@tQ zV=u`=G%#GBZ|ms&emkrS6i0E>g*dOCqie~76c}ufOChdmB!0PbPYmWx-@Zxz8W0(n zdyK_P-GC+0k!iv@_f#BdtJ=q^+Ltcr8mxcfuwy-Mm7KQMXq2XTbEoM@TB7$cdsLIs zt1xp=ZDf{v6pVU|OB9ls>Ne~!>@YZe-X<{uHeG8RKUt@BRZXB-r;#nPh?E=n13TUe z+)u0R<~z6;NVb;*yDM!(P7Lg|8b$6|avF!GS;*VhR?Va54oPTeriQRzs_es#FRqRc zveyUxGnbpOr$5eF|HW>hwRGuA!`uR|o=u=|xZm0O)trXJ|(#N6f!;=b-X>kdg!+i6f^m+*}KJCk`7H+c!rd zV;*DF9rs?6z_vg^$U6uR$RlW62wW&!$SXLeRJSJ~glkwPScSg^6X^GI1``+?@Y;~A zWVM(#5IbVM5`p26@eri2060(LTBKUSTDV%=TGU$78yI8g9ob&>K)~h$SFi=d3{);O z0L>G!7UPC;ho*NTP%&^SkU3Bbq6VrNsu{8w+7P-E)f4*WyD|I@bMJbf2gEg0Cd5=A zZm&|WPoP2IW}r}DSD;_u6XY8t8H6wlF$6ITF%&TzF{CdHAJQ|vBk~R6j(V>};0&Y@ zL^q5t>@%Swu`yIPr0=(9)El84_}=)yJO~kJ{{**@|AUI!l1^bksS>OLv;zDFayn$I z)a+_Cf(6u1NPFl>xJgylL-*uO$n&E4nfbBZ3mpg#i3Uju2Y~X# zzQNyd>SgG)*1WET+tm#@hd75+ChrnkOeuw&q5LH7Ki2$+iH+z%@RVJg*$8p`wu94K z8CV@?7kC-Ctg#6e=>La@vKx9=FR%sj8e$8U3o;XuIWQ;i38Dj{1JVb=M{~0aZTC$> zd3N&+!~Y+l7kG5i|Eqq`^B{~MyWxo8(*qqKwkw7`I5>r&07%aX?E5GoEmo7BM7tD4 zMxxK$#wdUAIQ>PJtR>^2a-n>YwZCbjd15&dA9i3gL*&A|!&t&`L0-WVi@vb;>P2h^ z{lum8C2)jcBXaDBIqk$cJ_qy~WP&DTS`lisIlIm1^n#z&dO3QXd;J1&GPmsV=WvQ` z5_I7`F>kQ{DMUUKTrzxb?_ks3PIijMWt!jbdI(WQCOJiw>6ARKIM}ls(?(}H|2y~c zZ^snmMv#O*%Z^ew`$%8RVW3;D)|K1I`2Ry)^%K8e2Ezo4%@+9NJ(ve!3jsj%B)th6 zcn*?YxnLt5w9JF=gw_rOnA4v1KxB*j9gz;NgMRT)H;N;_E*n^hxJPsp4Pw*4ExdjU z`XU(bhVn)EcgL{)M>r9XtzfVMz0X5D*(xQ2d&78ZSjhk%C+ zhX{w1fgpp7gA#@#hW3Se#=gn0=VCx_%{w>Hg!VSk3U?CsF#aSNCd(YqM)K6l=XW`~ z_*u#xO(7gkz?qGDvlZk9-M#x;&5@iwR>>6c%)S5q{m@VRwWf4*mo;RIMW-Us70T`I5m6n<|->7r08< z{%=PR+9@-!)l`8$j=6=IQ-;ii1VncpL(EWhW9q@nBBaUOu+(4btvsHNmVSDXuyuN(=1NvTjrg z396anPID)f=6{zHhFsRbo<6T)-%cogOq2;#w^z6tnzGVg`nu9HM|{m|z{S=pyawSOm}Q7Wu*f^zoj z6g<3l1Kv287p4aUe&?SDALoskNxd7P*Fq?s3|e)8s|y@{x>0ps+FM@OX+gDR4(k$1 z7?|2skH_3|QAMOjl$I{v@uhr8B$qZhkTp-tBXeU8DRL4Pv?dXHSt>}6YU~e76I3f& z4a#xaTffuFD}HG0_vq-Z1#o}1P;*Dc-Av;TYb-@15Y5k;mj6l+{-szL-UVz+@_H&0=iJ z@|m>@meo)6!bGJoH@Vuf}UXcsA`y-;oDbSYK>g|8e(=mr}4&3xApefi_Rv@(f+xwg?{ zZ&6e^A$oUGB>eNCqPsfvIk!XK+-Y;Q8sYy0Qvek!%M=88?5Q(F8~zGsTY0jDaBSrt zu${x93hgJ9-w(ecWmf}Ii!@IEeJ!I(CKTw4kI6^&8>MsIa(qW2p_WaPhgCQOq{|kE zDx9ee7VVjc6ZIE$<|lF~5Kb47QhCnQ{4PqEqhlbR8uN;r!~gEqnJD{fn4?@B5v4F$ zmTFjaOjF^^hg<4%yoh4?PguS_qwI8Ya*r6H;Yd-#u)JFMzm2?F23OFHufiE{x@ZCE zyBCAl_~9+*X+H#xqL~^HCyAx}r`qd7CzvQ*Lz_z0N{u;*rA8uE9uf1WP?GoOFWCWc z1p(H{B1jCSvLH{vNLjz{oTqz48Lmgz-*a5B%s-Q4@!q2uKC@&^Kfm$Y!`4#>Nd+Y* zeR8F^m%#LiDk_zdYqk-zF(*@rNgHo)(&v^;7LXgXq5QYC`kXBkZkqVJ_dX#V z!p>IO>Ny8{M&$^6+wtttZHX`^)^1BtDpx=uq~1ovFBQ!{jVa061)mr66jhR{_Pdx# z0yym)=S=nm`s17U4`prQ-eod8y2!qm;VXIpEZRQjD~7MPNR;xpX$u6#+>AL2WW(LAJO;K0i8~n(*IB$+o1*!`@CWy`7gVha~VB*0tg2Tmn5#) z9V{40-bba~5WI5;AKUL$+u~j(1%r{245h@zfa7O>epCNP#_Hjv~dTcQGwI=DLV}+~3JlbwwYI!F#ShEVNNv>Ftlx-#5 zj;*vE+c`?=YrpZW2z5?alD3OgyNL`OhIW(jP9dz0iogJmVa7O4fkAvkCDdYjO$wKzNhuT94)qe?v1+O-Ui^&Aryugq-;K%4 zl1e^S7D zU4!yQNB6vlVRlFV={-N;eEOyE)~0Y;5yd;m9FDBo_^KHmZ}UFmJ+|IsulLz>4MlcO z5d{v>3yo|IJ?ShB%4fZ_gwAh7zK^W<07`8#1@-#Do${_fTM*Xhr7ccrN{9!#^$$GrNy!aM)`c^U3pV(26~tjyt)(`!WbY1R9G(;BqIQV;d&z1yLWjvD$q zxxBTz)?wa-%>BG}as8KxNRXw^k@h69NZ}ghG3exe1c{T)83E0&#BY8C;}<(F}Fu>!G6Ek^GvnFT4{f8A#>+*j{ULVIKu@aj^=9 zA?PLL2OG$4Iw{B?EPj+?`T#mB?fUuA&m;Q9i}~b$Y%$^o?l&HkRKku+j&fol_cm9C z?aALEz$52}f&+Eicf__QP%omF;q~Seb2nDKx_f>0I2Znp01=Ag|3<}NHN%ixrkx&R z7`lebw$5$)WmltBGaOW^GA5Dk6bq^`tUcn|e-(C1Aqe@laNJ#57JDGfV+{DFnewQ5 zDfipPnKYx9D5d-HA1TGXkUDVvEknO$neDZi+#soL4zJ)Z*JY_`PSaY)v)l2*kjVL% z6(Ca~p#mO5)VQ$e9;-A??^@mno9dES!|DUdfxHWCYr7{dG;z za6`l(V#%mn4M~Xhwx~#4un~tBObm^XPOw5UQNsA9P#U6yDCF2sPxr0th>&MNf9Ct7 ziZgHJmLB#`;Yh>7|4^Ec* zx<=O`s`$r4)>C>(q8vab-E?yv3_)H|*DOODgPFrU{n9%pptb&5%#RD_Hm7d2iL4c< z17@aL(Tp8bCKv~6Go`x}%Vx$}y3`K_T1Ba?j@dW6KZ}w8ZX+za@t~pc!-~xh689s_ zL+7b!-{t8}nYN7|7FUg&*P1NLmy=!YM{0-8r8!=rW(+~*cg)whTathNi`>D=$Gc7 z(oOs+OyU`j(kPqd*n2SR7NcI8BC1s<_Y1Cchu()xX14h~x@BqrQ~)*2xEE+7XQ=aJ zVT*(RwjPWR;(^j}3xeSfkHYz7N6Nrdk6)A-BI*U<*Rn(Jp(f}E%JfGyzO>00nuRmt2NTIPTY_2BM41LgX3dIavl{FQoLrRu&fMymH(Q4Gj_5zM38i&hI z{iW+sLW}9Bi5F;o!@K6zY^>3jG=4#rV`}H0Y5i8fgNCw3Pn{iW*BOyey^ zTIVC!z6{Mt{k00SLOR6E30<5{IwThEv=#=>NW6pT1t1qJi$Q|mHvGr1y6(H%Y2qHJ#Ur2m7OKSMaOuiUV3t*UnR;24>+*P-79n#!Mr681Y9WD~*=gD7Z8 z6+|7@5xQ}nA;s)HTqW=#54KUHnr~Q!o)|cTFKToRx3FvlyTv7{#xcs_mSG{mt*fDT z->^Wr64zYJmRB{ntkWFB(2X$LLl6AEXays(xsx8Yz&Il98f znJTFdFS9+=cx=gNwVRFn#(4+LUl^^q{$u%5Ww`EW6U0^#(2A00)bMigLCYCGcy{jo z5g$>$wJi0ayuJ`H0NQ5wnxfkrtAEMJo?R?BZ#?x^a`o}?pyR;!Y@h1gibA~*|4AC} zHd%|9zCu3v)_k(^WOvqsRgIRk`A#9-YmW7tfaR%${@gS*nyJKIe{?dM%C`E>%)`~9 z`0T;nh|At6UF^2(F5Lkfnk<)Vw4mn+vO;>e5Sne!OI{LM$GPl-LcRpj>?22uRwx>m z1Rr+jfv+&A9d)VESF+5&USDwKAhT@q1i1#;&7gMc848BGE3CmQ>-oH=!jHDZj62g! z*%m9NKUWu8on#0|(Ryyj17<$?gZc%MPvT*Ur=+kxyAs`asf>zS)?@lXJ2i=Im`quf zUT>UtkY)hnMKFbVKMO*jOBivg4p1hso^oI8NQi;+4x_kSX3=y~zZhXrnp>+-FD>t_ zJeMlARUbqMW8Of|W*JQ7DB8AR&PZ-UKjVWA|0G~;d6YH`wcG`2lo(F};VuhD`JQ|K z?HZ3A1wO@JiO@OI9WE^hs$qEXJzOq4(cPM#T{L#gq3h%{Q&opj8kGqB{`3@}T%U_C z2@p#lAV4#(nie(l8IFu0$cU&K-AHcBp$z9BYOtRYKM1NK(P74BZ#Zh!TR=@fxqNIA zl*D+br5wA%Ii;Q~vY*qCQtObV9R((-nf+|-JXB z<|~i*Hs~IISV$anZ%%mFoxg(gA+G2x!R|q)(&&;84+FX*4MMudRo=%(d-i;_%N=GX zEIT~)@FYwWbmZM9xV}Xuz79glwcoQM77SX2%FnR){e30A)Z_LZj$C2)^vRP@4N$9~ zu`yduA>y`Q{3b&Z{6oC3(K0EAvtcg_NS*ak+weH35DhrHTtZ5v3xSR>>l?gn)5Q zVToZZ%6-#Z$PX&?qf=AB2lm|8!Ktz*VY_PY%zPf0t9%Ua_Wl^qMS7Uz_4+N>UhI{0 zwl@s`Jz{1YIrp=vK!v@WUF<@>CpYG|@kib~}}ncU~b|Vt4&B?DQuW9q!Uf?T-u%7wpCC zAIsVKnJs^gx^&fd)_Q+52P14C**&i1c0W-}!-xu`x`Wz{RI zHjn84X}-ANKwS5tcqoT|uu5p>lnJ&!Jn){kj&U{s(z9K`4L3~Aw~_2cdu_ZCxPM{d zbbRTQZ83x}?MnOwP5$`Tba%v1i7)x1I)Q_0-P5ASsRe+++)wLOV+Q5bmO2Svf~?mYQ+Ewjy)M>fRO{EjhH-AWNTT;aQ! zBg=hR#8`7*icEpw+|qqineX3`-PuuvWgUiw!Oh%p9{WeN^gQ8HOT<_Ga$b4n1?(=o zo-bufwlne#+9|&77kprkcy5^~E(xHR%LbCak=>a=K3sEy7mjY5F6gD1v-C(~>cjdD z#$rcr)dM|>Dbst>`pik;^EWHDmDCl3F7m=4I|5XpQ@61fh)z=8fnL z)Yxv67fCy&W)@GkGU^a5tDnD<-$FbbGdqedi8Mfb56~M>fNeS`zNnhgo_3V z9b#3j4hvv`Cp>QWIA{f$wAjCzXNfP>YZ@T$k=hu-zn{5$g|J7zIOCkFH+HjTvQbNa zeu@%dbiM@L9no^#xVruVNKBSC=i=CXFllq*IL0=~mu2Ih2qCb16!1KdvwTSFpD8#W z;9g}4TGccr{kF+|6&ud7^+56FQM5Vh$`WWUHK%=$3+l`U4Lw+LdOxqE*&xf{SSR{fik>q(7%GUDqV1(&h2%|;K37q_Em2R>KUuzaa$*lT8i;$!+ji2dIX%`7 zU(HVXG=j^~5z4FB-CDeAmc;vgIQOFa5770 zb#`yKN;FS|7_*Nx@r4-mM^?WpwxbR5+St+rGiSd4{t4B=^O z<$CncfltWNjhclAQ5$yDr!FngP489dT>;#%(~piAJ0IFWPWuF!wT`oInJ-W%UE&jE zsWkh1K8o`^!HP9Daf%3AfA6O<+f<3JZCRFUv&Qrmu%9_~33fFiR*#}jw(}+^Y6+SN zzguB76EmY{!nia5LGXW+{}SqTmGxV77o-R_kp8gr2|wD1g4>#lvCC}Jv=OgXTT=Ov zzV7)hHT+$(b@EcTZ5F%LU(?|h&Vh}UiwA9KWmfa z-DJhyf(@h12=)77XV6OSur?xak!WJe`|IEONVj|YicpCE7XVK{u)jhBJ9z_#qYccm z8+cDNKs1lqG(V1~c`PZ-Pe5}Qr}=4Hn!7nothI7&9u`|UU#T5#|Kp_j6{_vA7VcjA zZ2DTWR6)vbi7JD~Y3HA%!s_{&%iA9`+v?e;Nk3@jk6P3C4kJ29zVYTySQg{03xWrP zBJs186?Z}Ko91V^vo&%-P;8D?E1M^Qb}5?8k?76|wr=3k89-=skf%}P8zO%mn*sc3 zj;7rAQM*Pgs_72i^>JJQz6F)WkN<(Yq6uTf4~l#h^ZtmndaENNr?p-^6Qn-mdi9W> za8{FIO-l7`j-l*9wuxiUOti5R9jW+yyvo-(TO5oqy@%(!y%D-ldPhWCAwIuLxr-Q3xqiv0BG*`%W zIa;zVB#jtD{35D&d?`+?Ju${@wRMi%uQ>ZMI-t@%RQftv>A0x0-@%pFjO%2GMn`j2 zcRFakWy%4EdBD-sJmfaU=oCKapi?cj^`~u03EW_wa9_I}G%CVEP({wcL zq{a9R?~P#N_h48*p#Olef1~Z>BmY*6{Kt59?c~h*PB4q;|IC@SGoDqy^97R8AHC^A z`ua4TGh)aeie&L&y1sK^?hjgfQbKOl`Er_}XGlmj>cHf}Vx2gbcY0Q3z5peDmcG-| z?jSI3(_=iGttaQ&96cG=?$i^xHcwCB+I&66wFP>VYYTP3wI#aX+C6%VYfE*(wPku6 zt}WM3$F&uD8?HSl`0$vHt=L_G*?70`aq8HLdycaoHEFF*_9I)To9hU7x4B+#UYPrn z*5y(XSwCy?6T10?K0dv9NID~ZPKQ3XUfiYZ6pGcFtW-4qBzXL1vY$YMZ^EaE&M#V* z_N43SP2-K`AqE@rZ${dcLan7{JmnQ!S_8VPU7v`o@$fN3X3mv0 z!zE7Z{W=|K&ONpW->;LXVjt+{2f8JycAFpSuzu3BY3WQ=GuV%57=da_7>wBvH zBQ5A=60;{1BGNNTue$kLB9T!sBEJ)n6EuQ2BIhZZ<(r@8BqHGBH0N>lhsG#4 zp~)1S)RgH?bGj2;rR{S+gAX3jvYWv6#Plg(S4J%*XHoV0Z5M-;9iZbI8+ z=LoWMI6e7xr+K?gZ;yG06PzS5IoG+f#k-HemL^*BIj!Dg5?@HP?&h=_9n#%SbFmY9 z8Pb(DtAoax%U1JCRC5XF`c^UXUMJSe`LgXXUB)XAHG3=8`Ls`&t~In5zGfWA+6um_yxgM@gg`H-`z#W#lU8$nvNZ^9cF1cH%y1}AAh^Y$K8N5|hqej9OowBe(_G^un>u%v!(8i} zvB!MEIpL&|dz)i0Ydood{ZBfZhcv3vj9unaFe}wuHe{+QBlVoKnGkOW;*e=7%>N3_ zeBN2Eagjz65+*1=b+Sl2zu+7{9nvR9qUA7MrS0;fbNtO}%aEH@Hc31?Y9Z&Wu$Fh5 zn*{lJG4c*`vlI5sDx18+B2VtBEhyo%F@SB(a~quvuxGbBcjn&Z;O?x~oHw4N4SM=o_uDi&t3WkajuE-3b-;P=#k;T2h64s*pn!-sctWc1Z6# z&HYX+xOTK=J|N_vd4O>H5pEa4J;ZSrJETKS^DtpV%p-)+KZV$sXAaw0j)vQztzxORa^a;F&=$&CZ@ytNK}UEj!Ncbx5B&&Ci@o zS4qB0%rBf|Oz^XA2I)pfQbz7l2Nuc*6#4fuUa$fMwGz3o&6T3y z4#th52Mn$%P9V!SgEr2?!1PJxW5k3%lRI-YKh{_A##cF{)y8qQ+QHTs=4yj)%QXg< zLhJY#o9WTodLC_|M{66XpZw1KNuJphXvq0vWy=bbWsD~654pFBOZjJ_2q!FrKBWF3 z_cej=d=%lNg+PMoMbX%u)Y{9`>5J)vn9N_`@;*;jrOoK`euZr|%q<31MLJ2YS7^4^ zFmtOxstApIn}K7a!F(MA|K1c>!+dwB<{Ki>;F}9|5AhtkV24QXg15mk{??Y7A4v1n zgNr`i{2GWp!)&J3mP6PXIFc6g=N|77_9fKW62jiivDZ4J-RSH(2is?ud#KW4X6`e_ z->HtcQLQhy+}i6~J@-1Ft}|Rsxtlnp>8_|9btm)WZgy}l$IUM8 z5t-o{YR+;sXI=qSlYTO0&UQ7$+nPX`gLbav#wM+=+eN+GTya*WL%1(sXTEguWJZO= z?Rt5h%be%3l;u60~P{uv*wDta=bzNW^wt#e^lF(Vebc(futLG7VsHYyeMT z0I!GvEOT+L{hOo&kY9DgT{YkD5)O{;fl5?g@UxZgAN$_caIG z;G!e;bw+0_m%T4Iqzx|fNj?g0#y0}u2*nY*1-4~6` zq}YhpnZ_G1UvSZ>J0T-L&pBSQ9$SmN%m7_^-@vn8LW6Je246;Oha=X|irlvxD`Ks! z$bH*N@+O-C7px*}IQJcgSds5yMdmhHC^JP3>#lASZ`S)Rw$~O{hOgCGVZOqPJ?*gc z%va-ky-4-mt;*)s_+Bp-dE3QAEJ4mafO}OkH*#C}s-VN?4cAb1`Cal7I&bBrI9*?7 z(lVSvY0_W~a;lM^1UoP{o*BEv?+#q%TVTL@oE7hgWi^f#@h%5@*JZxzY7Wr*>kGJT zoV(jWwsGzr$Bf-(6Csa3%IL=0dc&|>ZCNqmD3iI@t?iOAchVv$bU=iRJ_Bx^$d%ImtVoCS(&V~iFC$(91`Tfke{}RgbossSU?1@1 zm&P@`#w`A0f*Da2Z@)wOz-4|ITZ#wJlMgsM4q_=DrAc5}n@B{u@IUT~eHHe|=O}0z z@)wB+nqQ*&D&eJWUke&vx#Dk2KXmXhnJ(Lp`>iY9bNihu&U5=ck+prdSk6BPk@HiG z0d=%0au4t+&$u3q{es30ay>C{pSmLVkYh!hH25_^8vO2xcd2$pSD)+(M;-=*)E^6+F z+UADxOs{lSs<|Iw_fT{>dT+-+Qljx852(@#Oqe+fO?@2K)NStQW_U2V8K{^qi8=13 z9^Qvk(#bMz!hr5{+w7n3j%WV@cOu6Zy5pu}k(;xBFVg~kbuco@QTqPeE z84IL1J_aI{J=)Vv?&AqOSQS6!wPMWcF`zH_fS#}h)WS!z!Humpgx>en@t?c6?Yo^X z9n!OI^Ldaep`X~8FSv)AFS(n>4;wK|@(nd#M#0b~-{a8gcr37yc~?OL+TtevY2uB{ zEAA$171)rgjkLg6=G=jh}%3$|7*(qfsf}H@Hy+Lj`@k3 zR%27(yxbq5E1d6Lqbla7gwbh4CyB_JpQGl_{1`-^_?71@af*H6wlZ@h-&)oD63IT@ zYSj$-3B36=6)N6!V90SBk8*OvK3tDx%xKfUQ_~!OjS2-4`4gT{?G`tveYy>KQk8q} z3D>GnUvs2R%TJy(zeBegb?V0tQ94s~dk8;TYbRbH{nTphDCRF%I|Ck)SBw4k6n0xD z>1pi3VG_X@_87Tg*Vdkv}t{)~zS17vS+Q(PyY@7J(l;doM&gLPw<^MJIB;ZjL zS$9=ePxp|SWO8u|M(Kee1cP|)sw?UmlvT6p%8#yLlO7$jF8Hqky6&$30&;`gHwqzK z;l5Ah3do^=bC3j2l*(#5{y?Ryk-mB_rosaY2lBX%(D$9bYKYl6N}uwHJcUoLi7S#nU#Z$*CT6!Mf~imT8_MP{kj#T&S74nI*E&b35JB z1`yx&kSlho$8wE@43^7oQ}!Ynn=si)gNyrKh&T*gFbKF9R^vTG_eX>zHU*wUC zJoIuO6f74*!-LR>o&$oquRFBf(k)jjBy5Q%oHtsxU?CZ!!!p>De99!oOFa}V*eqBE z>ch)Cv7#*k09yn@@1+8!owus*Pf$Pb62m8Y&$huQZyd za*ZeIRM;A=<7+F7URB*Hs&0-`-9}FYwF>;@P0$Or3TDC^Z{ith!t#u z5=v$Y-zn7Grs(P>;Pq5pZ1%{_o}!JS>qf9Vu_NS`WX?U9OvF|oV%jfqZd(%P@Q7R` z^te^eEIL_3?Ox%uduM`8_a@h{>))_xcRicX@4bggkJgvHlgeJ_l)ca93D7F{dm^A+ z90yI)69EBy6z9zY_Qs1RK5tIf*#S?zdoO^qCe4>`>&gL-tOmj+vW&iX^2Ou$@{YI) zDjgTzL67~Kr;4VLTYl_ujuWVP@96PIqybxrxINXeeV=FTv67y2^Z%|d|qt}<|%25vr0z2i&o2AR6o__n^;SSdfE@J30xu7iF)4d~1DXk5snWUe_yo${a$bBE)@JPVjBu;8CP;RuT9c@M14 zg}DFn7i9KDkG)Gq{)~$>U$aXdc?sv#YTs=No>;5X_+^j0>`Cm5$t#{1dG+xf;~1TJ z$l!_+eF!q*L9nQ^$+Z>4roY#$1Ht}1R{0`%N4-f^4)ju$gS>K(w_%loy>hTO9J(`J zLRT+B-GCEb>8Lx7R>8_P5wfh&#U!ts=q++bWA-wG^TH&rRlkJ66g9<* zTPJB~oJ{qi1<`QrBA4NGNQkdxGco&Ck%d!JS)%?~UVL{+&hg@+CTMz{;H9&@QKYsM zsGaA99(}?EOYa{mGdl3gV=wcZlZq&8qUbzf75VPlgWPv7^1I-|kILE{K zDpz=MhbI*`a8`PwMQc^$h~+BSB{;raMF7BX_yQ1|f|h#Y8>KNMa2OD{)(eVkPq_~1 zd=fpuGlr&01=XnnR}9&iCXptNzKIghe^%E_}-*uVtijxGcmqD zshJr6D5;qkk6<&O;*1#`!yU1m?VneQQ#%$n?pXYx=vcfLe*55;1OK}#E$Lq=y%W$5 z@^#}(XxAfMwE2W>}9TNY=U78DQ!R@*XIOqNYpeCve z{sODu?+8_eze80K0E~wf*)AL@-NR&VI93{AvVAyOx}V9suq8@kOm+xcT4|Wc{BS77 zig&ZnCmbgPFPV)t3lY(9r2-Uf~BuB)z; z;ndhW;9E+Zp$32TE4dUA}^=ZNIz2q5UHCk#KT_MPUTEeos+U z6s40htZm!8U3%O}&^28YMg^IO_k!69Ea=>YrQiB%G8CWIg)3!0we0@5O0ZjJ_oGHo zneaw}6>z`&t^6&SB8x?$xma-l7)ka;43tGaOe^~Y)xr9}ChB(xEy{LEunoJy7+AND z__|)b#6L=IJ*N`et@l_1>OQ!dI#~#$?I#D{<6W5fkN)cEnC*&Vww}zbiz~)?c;+&Hd`dAcHGDdBXe?*VVe)vV$?7qE(e3q0iH8e_4Fj@dq zlSQ~QhY$@_OrevA2M0& za6ks3p`X}Qe<}(-5iInXK%U4@IP_t>WiSZr@v@gWja-^h4kMxTd6v)n_HxTVlR0a~ z@iFV{g3kr2iSF{gy&B0ElMzM>EGZcwMfQYt9K?2@&oQN_Y4H~#bVw95WnB*nmAXOp zf)rFf^`b9@spR65%{3iL?E0k;MPDJj>sM5)r|>Ws+Al+~HKJ<`*Z|nW@)bxi3Xj0( z>y1wijabfXhdL~5cHvRzLr`donjr?Jv@w;g%>=RRRlssNZ836ka@rIg6E69BVm6_3 z-+zbP!+7y99y-rW)^!-?Bt-Hbkjq<~Nx~Af2hcwWWc#}J*`PNNg!L3o;LLXyl=m+v z4__R`Ny&V!>m;s{Fv@<|=+uS<_9s|8yL^-RZoYaT4rC36-RIX%DykgJy0BL!yJom> z#HAh=iUEB5S}1xm!v;oZ1{jW)=RB(cRz6~l zjAM;t@+~66b}ZS>_!vW%5@s8P*@|GX60qoC#ui0C3TL%y+?~PFw40{K#(>s?F;&=i zB>jnVRWv=-OVSej55+4}iwCHY!qZS>8l)EsRTX|nPq)+4YuOttU1lIs(HA^g@C9dp z%w;AZm$)=l+z-fEHgZ-iJE1f9`v!+UQ#3V8Hg+<`Fk`#`2tmuUOA@jvlw@H^4?s!H z?2?+*vXeS%hHubt`1`%CHj^!q+mKXbQc*3Ts9>Ce>+PbhM+&Z&IoD8d10X*ar=Ycs z+!~SL&ks6>zqPvBTKfNUwQZrK=i?;>?2-al68w=mF6#3&H6U~Ub4htnQYc4i8eI@u+4!Zvl1w_d}F+X1;0k=p?B9X9eESQmq}{u=CG z1NNU$jv52@-8S~!@*c!10679X<3&t;22#7znI28)E}xDRyH}AP;F+SYd8FWL&IVNZ zIzs%}NU_&WDJnV+DaR=VU0i>P6sN8t-KDtbGf4RiQ)CdG0)J7VwfRs($f+Sz%TDR+ z1^EJ=xB5}fJFVZ(`_-w{vNRHfI3D+cY&|uhipL<^ivU3syVEz{Uv$mr=Q|AMc6 z^r@CTO{Gr_-uU2_FGXTNd?Xh7iFjM`laRe)WBY)yk^Lno;(x`)^wOZm9)(h0am@6y zy7CI0-RmuTgYg)-Y?jcP^f<}QizO!^HdnZs_K@7X zP$D5VN9fIa)MA;n5UUVIiyo)3%+uJCmj#GG=Tql&*#}#5SyTGRzH}JwXFcycbWX7m z`kp(d@Lr{a3;O*m8TuNs;T0?=56gKy+%fN>o_9%?e~*|-=qxOU1?L1aeFZ-YR%Tu@ z1sF}d4D$4L>sq64Ic92!8dFd}3+i;WB`G)0vnXm!v0iE|8>1>MYgs>owZzk)yrpb~ ztiC?{lu~+($s9UCRC^DCNC@fios+; z$DB(KF==8Bwe$-n+lKR|sxUi%ot`&I1+_l(1_u)rDYi_@IOMpe!Ji7te}zvJ0TRCUl`qVTkiE zz0OmeGl<;RV5aHH!?J56;}x{_2OI2nwQPvNACbSaJpqrHN>IbX1_WKcU*Xt=Zf-TG zMm~zb82O!U#H>RN^)dNau@Ngc#mVbY7)2i{;DCr?Qy=N%($Y7>(8hNSo`^n##L7P) z1`zu<6_}HY?Ry%S^Gq^d|45NGAQY@*Fe=Rug&eOVJ2NmxF${=dhAcsmLb3ll&JN9C zc7QakXozM{4{FO&10i^$$3G}9ofZQXr^i{Iw@8$p#o_u-V5O_$so{pL80=FOFwJME z4F1kkxmTuzBM&p_1MBlR1Kl82`ZbdoknauDKwywzPM2*itMI?O00qQ{Kzv*Ie~`#* zEO)U`@_L-(W@mptqrBuC*8DH7YOdQ)jWFb0h%wSo?yAM>y6=KGjK#adML)5wKQX2B zGy?&OlwM{aL($TcOy1iCZz;#@w_xkwJO}5;Hb2tgCOF8{-Y7uY3)Z zb9-9{CW61=lo$^E$U-v(I_qC2=lTRATyTXcWhJ9Dv<-T)#NN+8>?d)1~DCa;%`XPFjy7k2$tLzZ?Q0Kla`!8eHz%_yMldND6=Lj1Q`6oef{kYl4PP+{DOTi>fD>=*LMAXm+GsERdSmuhR@!;x4l*L&wpZRXOc1@}Hh3;Gs?@moFg6_QcG8<@b?t+S^W~u5_ z=+-96G))m%%5)7)uOSRAtUP4!5>kB14P^!)%UGRwK8dAXKBu>y}$tBo-}rTVsXqfP`*g(XoB1 zqvZGf3I=Osq71zKv;KJpi#ScNL}-RqI8(#xKojX387@N4JB!dB;=wS+fN@#Kg1vFZ z?ZpdTF>yFkHO+O17<9yDP=Y&07|qZ}h)MhyF-e8d{Y?_J-!`NcFGM=Wh+bgJ2}TNb z6D0T~i-1~OPw@#x+BJ{?BpwA{b#_^kocGV3dgmN6O8Nuwn96%dPXpP91oj@DRyEd|Yh(o#Ez+t$Y zzLlV71drb^#N}Iw7L9VyME1p3%G`dBW)i#f(vp&o>%iq z6^zXzAj#`EO6+**gX^)Xjq$2B;(ebH|M2F8Wg6b?iFgwdeYG`?x0TCE9x-pElD8Au z#6)pB<7hj%+zrJod4`JHLwJ)&sdU~@qsF+7-AT|NK zDGYVnTakd3Lh<#u3@k0Z46I)&Sb7iiQkI^F*b3+{n6H)#^%U!Ik+&_mh?Pubnh;u; zomyz%bb+&76;8=G$-taZe37Rw#VLO&Q-Bgs6Nd3NkQ1g5cgIa=~8WU=x*V(1gg?K2;HaKc4+MBo0K%rZM3b+S?o{8%*81 zTU7>g)bJSwGgOYjD4`DF*!5x*Is{zWB#uP@kYp1R965+mtnzB&7!~J!vB2=zfx@pWOPEpoM!!mH;okbhoWsu#{ zfwdyePCzP$3SC&?9C*;FeRGjZ)5(hHgiLDgm_N;H*&dZOmo3l;X$f}6L@rx_-2szh z4z#K8XAu1xA?w@BC0r>Bh{0xjduExz%=+ya+E3Z8DyD2J+d2y87%l_$>q#&-w-1NL z@O+J$lZVe8a_Bifaf*-2j`kV35j-?X6wZazo9h9iZ9pg5keR2wnw##SwPqqQ?=oLR z&b3<+zrzh!GVQeAN%0%0rn~UjRA^SX2QpD3TGKJt3tW|*omP)STdHt4Q2txrEm!;8 z!LFJQHc~;d=iPC;Cwbi;>cU!o&raLhTos_qHB%Ol8ut!!f%)+T4Z*H)^JArBPUq7Qa{2#YBGHeiW2W@ndVH+YLxb#?sBy1MCgb?_v++r%eZCQsYMKl6VP z&t(yqh~=z;h*xHy;CMF@!GDSqyvk7iga-XMUbqm-v*LYW5(xX^`8dd*L-A6qG7}+P zGi??6&(|7GFaDqHGV4&yh~FgL5g-Fp2g-(3c|fwDiXz z@)~X=j^MNzR*yJJm<+eV3KnU$p+csnspR79_YY(dnU6Thyn!*8Cs3q)FXIIg3?Yt; z4`6m9d=H_dyvgj!>;v(mc)?-~tSXMCC1feeqJeT!{+zg;CzpeFW z!<<%TF97}wWqAA9D83bMKO4pA_OoH^Dk1jamiq`$Fy8`EeT(7D*RbcnEG5Yr&HiuE z8Vkmfe;wa!JK?}s;#tZPFqxVvOUYs?qiIU&*f--7A7U^-o3Ohjxp(^5hmgrO#Xz$I zmmTPKVAz4%4jS1(iXC|Dz)M_CrN3$P*C!{z0uZlK#%*9Or#MfloEo=_!L+pd1q7sb zuT(H1o#-ftrpX1&DG?7+j>67M_3YyKQ3vX1TX|Z_;zE@RD(o`I0y2SRFL!eLI0Fe- zk&pl%Nx(9c055$H0{1FS-#lD%fD>RXIv~RVx#SuLWXE;6&W_U+MzdfwF0&Kda=o2^ z+p9b&p%GY@l%SJQpGZidk4cbJyNR6l;?YJF-4u_eIL4w~FLHLPQx)=dn^QV+x3ZqQ z$bp_dl3gD@!7nZQ$18Qd?!c+{X&SQdXf;MOm#WdX}h%Z zY$`xKnD(GRmDelykT0!hb3(y)fr3AbRuep!H5)(HsoA^ObC}DmxwfdMJ}~6tsIFJz z!DRU9s6W=i0;@bu4xA@z*@p)ILoM5Ds84}jXNaEi4`$~Y`IL#5a&&{7z8<8q?>DsW zvU^d}aHxVuLtC^+x!I{K-&J1Fl=TKx^=Ukn=Rv*q8IuKFbff4WEf)w^D!vu)EIa^K zk8lXDNuEw6fTp=cliezLG?x7~EC?lu%62eUPzJHGcdxBXm(PJ_YghI>RHjp9Axn=} z_5xO>%Rh%hA0{f(v9gl-%KieC;WlPa^Npk`KQi=}&_@jFHGT+C{xuvb=U`VPw;2A1 zLu>WISsI>7-=Y<@ z=-NWb4Z5)vmfLV61w)wSij`DxSkJ+@&`YXu6|WR>IIC2l7^DqM3CP?SRl|`iX0o|8 zP-UeKo#<;k0)V3!y+|>S2^b#FBB?uYcN-62!V6Y&URuWS!#x1ofOl`(uzg^O z6Kn;*Ds9*%4$~~cwgGIT4O_(R4^Pb}hJMMhmX8>5v<9UhF*d3VB?6qQF<6xN$YT&3 zG}HqSd~Ap+2tF~iYW)0^$*N%5G(l-Tz|1t@ZZ#v}|A{#Hsp0wY#3Im< zRWNsfz|XA)$}3&a|Dv&g#P5;Q70{WQ>o|$-8S(^vZYXCMZB?Fw;0uHQ%+MweRq@`{ z=miK>^YOiFd~>kz7g@9@%Ve>+ph{L`G{wt?pi4trI6}jr#T*kBly2c*|Hrn~;0J{8 z<;%r-v)w>0>KoJ zGEX3w76|$R!Sp~dBM{6C1hWFc>_D(_AlM`jY#InQ3j~`7f-M5U>jJ@+fncjZ@cKY7 zClI_L5WF!EY#j)ifuKJSY!e8!4Fm&$V7ovtHxO(e2<8QX9Rk6d0>S)15L$3^AlNAo zyd@C4H4wZFof*nFUds*{41+HXJ`sYi3>BRjhYf+j5rbSCM-3MS#|#~VAUJDWw+(`GM$1YFel}Wdhv2+%{SF8&7&$v3xM+c)+AAg zz*z`f$E_Atv$A}>yl?P2xju%BH4l;#RhmN%e2$R;HC+ zhV^gbP)Cbd`34l+QdaVOx7D=VY6)qr<2DytK zfs`B3Gh5#e){RyxYSjlxU5G$x)rU#FZ{1*BPndg?ItYP;xu3^OqpWugdel6Y$MR<9 zU9OW+68V@d9!1KqjbKrqPN{#ytJyYs$-V2HZ|9#b0Xz6nnj4RhyTz|rRJcoBjT?wc<`Fw)%# z{kdd9%rTf-?s;s(7$g6FNj3gniu|d8hAwOt?nkEVP$2KS@NytC3L4hP8|I`L` zOcL_XY|x!aLjFZu$Xm-paUnP5mvJHY%dg@>-bNmd3wc|4BrfCuc{DEM?c}kzkmt&8 zxYgQf2hjHNTY3a&p8Sqmeyc4&JIE9C2+*74_w_>F-s(V|{X-Ik2&B%I+`7rivxPig zo=Resm1pHsz8{llMj+)o!>wE^KutNzt$@{r>OaS=HkMh2^Hei-iu>o)6VYSo)+q6-m7 zts1B%df&R$>O`1>)Ie56XEO`64M%wl=$9*rg*p^<5Fj2aHT z!yTZNmYk7GL<5xk0R6TNLN~^r`wSNio9({9;V1U$tg3`#DXtp+7Vk7C`*paN=7S>r(mVC zlOuDI(dH&c=HbDjMMO)CXsJM27TUD5rOb!A@5J>~%O_9Wvfg(vB z28pEMHdrJPG$grzp~)%3k_#AaNA9J_h~$)!cyw?Xb7gC;gBrGYtUx&q8t_YpUk3a# z;g?m*#<`WTf)sxY#=AKN6Wl5W6Ws!XNp5XC1e4va2?7mWeWJi2U`&EwirYO|;8<=n z1%j#Wl&Jz81)k{;Omll@Krr2%T0vi)Nm~ZN+iu@-A;;TSfo{>zUmzzy%rBW8)#W5% z`aoltEX;dBOPC_SNJzo&D@CFOG0yw740_~r0j>Aq-isT*xD?t-UKPuW?i>#VxOhw# zm0rthrDPw3UYtQ_RB3Eh?_g?utZ$7h6IQCJWZ^BKv+(0I1TTD#Gd#X3XA8$#PPMIN zL(V}YGMEk9k%PE$E`F?Ny$vHk1yYdab7LzP2rF${FwIJ%3)1YjrnYh`4RB3mQ926s zB7vz{Xkjjf3S3mi5)peyE)ymT`h3U9dGL-qeIx1j@$jIkWmndshlnxiqT`la+O6bAQ;{LLEYC5KQ00(%eW~Jj_Y-K zqztgiac{kvk_xtINQC@YpdXAp|EN=A%-#n;by|>9vjWv<$n-w9Rn~m3Wt8WqTJG|) zeBfGnnZF++t?hF_+8#&pAyPUac@T-*M}V*@j^IIr3_{3^BODU2T7M*LUrzR!D|Nsq z$0b<>5&8nv3O1Js%~kHh9yv;1R~o9)=cnem83r>oepE<*7(Id3zl4oV>$i`C0jm^0Vcg@YFcpo!_LJ0rjup@~#Aj?gl=j0Chf~HUN~| zBkwUixxlVWV9&43yUjb~Zy@G%5PoGoXx=IB1xPxO-x4zXm-&11H?lLZt1%FNr}c`DQRT*9^*sAeIenyWfdF3~9}wUW(<)u7Kzy<>t!Y#h)tpu z$&tsBBGiO;ao@JS4fOGGkRq0wOFt$4>y{3<>$n`3j0>o+xPp+O*uj_rVQOTibn^ge znBx|2aOyy73gsHKhN zR0fjX6h=dH=+HJG@c}uF!NAA`!N1MC9s2Z6^H*{@1MzqOy8A)1!0ZAY`LKMOnO)5% z%|Dn=ncbk5yPHqTcbNH%8HCP#-V8wpmzsZ;Gno0J+1u=6_BCHMUjsRKUCw0Y-~Deg z(9HdVn13+y4`KeH%s&hdJo|?;|2XC!&-@dZeJhH0Cd7{@Khw zhxz9+|2*cOkH?_>70kbY`4=+(O6Fh1{HvLN4fC%B+ll$tG5>nz-@yDEnZJ_xw=@3^ z=6@e7DdykF{JWTcH}mgd{tuWx%KS0rKLBel^H(u{HS^an|3T*enE5|p{;!z-Fj!g4 ze}wsuGXF8=KhFGLGygZt|1I->hli{Er9ahH|0S3tK|qNF+9J+*bd8N!v6o7hfxF9A!+UIZz{UBiL(H_%@E4^!4(# zgw>ayPBq*hmoktx7YxDsK-zSWx0mHI2BLQ(NgGt31wu9!Y(f+}N7~#VdAESXfw-+e z*+XHAFcdYAy<6o<y{ZA}3cfnnsgEPOf3*!wp4Fu4U%a4Mk3_ zW9FY5ikw`}Uc-Kmu+~f$}wNfWH zJA!wu)X6O{3ARK}pLtM%WmxIzd6hCLS zisAd_H({fP)5j2Fx-wkDk2k_E5((iKXh#eAmKF)k(+cNtAxB}h)#OyT4YQ4*Y!z;0 zjE2{EGYmdeIR-~nb&Q7JXpBT-mZ049p~f|gL+&TY-9@<O6@+sjTn*t$2-iUPHm46G7S4rm0~ND}%Z>D~i_3TEVK&T+ zzN_#HfwV!Ib{8^Wv0M38li%8V!kGM>7NK-jhTFj>w1~a?3h}w)aZ~st${QMMKiK`> zf%;!+&Z*0V^`|aRVFNa>#7zqu>AXrBHs+jWzruYUao(l#E}g<1F~wK3BXQnEZ`rbR z5_R|)t>}H{^-ZH?X$u6ULe}?K^81?xzQ4K3d4F>g69UiPEOAS^hH{3gcxu@yjltj5 z8u!T5aPe6ljXkX5tDL1ZT>2o_W@w}4O2u4Is>}+9YS1&ig-$9oLvRxSH$zHmcyX;- zEY+@=Dqw6SB3c0vfa5CKsnx&u=>{S)5sI^8Y9^iwee%Bwp89Lg|1Nn>=?t;|1=E_O E+CYH~eE