Plugins and Language Packs for Family Historian

Improve Website or CD DVD HTML.fh_lua

--[[
@Title:			Improve Website or CD DVD HTML
@Type:				Standard
@Author:			Mike Tate
@Contributors:	
@Version:			3.3
@Keywords:		
@LastUpdated:		25 Feb 2026
@Licence:			This plugin is copyright (c) 2026 Mike Tate & contributors and is licensed under the MIT License which is hereby incorporated by reference (see https://pluginstore.family-historian.co.uk/fh-plugin-licence)
@Description:		Ensure user URL are hyperlinks, abbreviate long URL, offer alternative image popups, add Table of Contents pages, add alternate & married names and ids to Index of Names, and create GenDex file.
@Version Log:		See end of file.
]]

if fhGetAppVersion() > 5 then fhSetStringEncoding("UTF-8") end				-- Cater for Unicode UTF-8 for FH v6+

--[[
@Title:			aa Library Functions Preamble
@Author:			Mike Tate
@Version:			4.1
@LastUpdated:		18 Feb 2026
@Description:		All the library functions prototype closures for Plugins.
]]

--[[
@Module:			+fh+stringx_v3
@Author:			Mike Tate
@Version:			3.0
@LastUpdated:	19 Sep 2020
@Description:	Extended string functions to supplement LUA string library.
@V3.0:				Function Prototype Closure version with Lua 5.1 & 5.3 comaptibility; Added inert(strTxt) function;
@V2.5:				Support FH V6 Encoding = UTF-8;
@V2.4:				Tolerant of integer & nil parameters just link match & gsub;
@V1.0:				Initial version.
]]

local function stringx_v3()

	local fh = {}									-- Local environment table

	-- Supply current file encoding format --
	function fh.encoding()
		if fhGetAppVersion() > 5 then return fhGetStringEncoding() end
		return "ANSI"
	end -- function encoding

	-- Split a string using "," or chosen separator --
	function fh.split(strTxt,strSep)
		local tblFields = {}
		local strPattern = string.format("([^%s]+)", strSep or ",")
		strTxt = tostring(strTxt or "")
		strTxt:gsub(strPattern, function(strField) tblFields[#tblFields+1] = strField end)
		return tblFields
	end -- function split

	-- Split a string into numbers using " " or "," or "x" separators	-- Any non-number remains as a string
	function fh.splitnumbers(strTxt)
		local tblNum = {}
		strTxt = tostring(strTxt or "")
		strTxt:gsub("([^ ,x]+)", function(strNum) tblNum[#tblNum+1] = tonumber(strNum) or strNum end)
		return tblNum
	end -- function splitnumbers

	local strMagic = "([%^%$%(%)%%%.%[%]%*%+%-%?])"							-- UTF-8 replacement for "(%W)"

	-- Hide magic pattern symbols	^ $ ( ) % . [ ] * + - ?
	function fh.plain(strTxt)
		-- Prefix every magic pattern character with a % escape character,
		-- where %% is the % escape, and %1 is the original character capture.
		strTxt = tostring(strTxt or ""):gsub(strMagic,"%%%1")
		return strTxt
	end -- function plain

	-- matches is plain text version of string.match()
	function fh.matches(strTxt,strFind,intInit)
		strFind = tostring(strFind or ""):gsub(strMagic,"%%%1")			-- Hide magic pattern symbols
		return tostring(strTxt or ""):match(strFind,tonumber(intInit))
	end -- function matches

	-- replace is plain text version of string.gsub()
	function fh.replace(strTxt,strOld,strNew,intNum)
		strOld = tostring(strOld or ""):gsub(strMagic,"%%%1")				-- Hide magic pattern symbols
		return tostring(strTxt or ""):gsub(strOld,function() return strNew end,tonumber(intNum))	-- Hide % capture symbols
	end -- function replace

	-- Hide % escape/capture symbols in replacement so they are inert
	function fh.inert(strTxt)
		strTxt = tostring(strTxt or ""):gsub("%%","%%%%")					-- Hide all % symbols
		return strTxt
	end -- function inert

	-- convert is pattern without captures version of string.gsub()
	function fh.convert(strTxt,strOld,strNew,intNum)
		return tostring(strTxt or ""):gsub(tostring(strOld or ""),function() return strNew end,tonumber(intNum))	-- Hide % capture symbols
	end -- function convert

	local dicUpper = { }
	local dicLower = { }
	local dicCaseX = { }
	-- ASCII unaccented letter translations for Upper, Lower, and Case Insensitive
	for intUpper = string.byte("A"), string.byte("Z") do
		local strUpper = string.char(intUpper)
		local strLower = string.char(intUpper - string.byte("A") + string.byte("a"))
		dicUpper[strLower] = strUpper
		dicLower[strUpper] = strLower
		local strCaseX = "["..strUpper..strLower.."]"
		dicCaseX[strLower] = strCaseX
		dicCaseX[strUpper] = strCaseX
	end

	-- Supply character length of ANSI text --
	function fh.length(strTxt)
		return string.len(strTxt or "")
	end -- function length

	-- Supply character substring of ANSI text --
	function fh.substring(strTxt,i,j)
		return string.sub(strTxt or "",i,j)
	end -- function substring

	-- Translate upper/lower case ANSI letters to pattern that matches both --
	function fh.caseless(strTxt)
		strTxt = tostring(strTxt or ""):gsub("[A-Za-z]",dicCaseX)
		return strTxt
	end -- function caseless

	if fh.encoding() == "UTF-8" then

		-- Supply character length of UTF-8 text --
		function fh.length(strTxt)
			isFlag = fhIsConversionLossFlagSet()
			strTxt = fhConvertUTF8toANSI(strTxt or "")
			fhSetConversionLossFlag(isFlag)
			return string.len(strTxt)
		end -- function length

		local strUTF8 = "([%z\1-\127\194-\244][\128-\191]*)"			-- Cater for Lua 5.1 %z or Lua 5.3 \0
		if fhGetAppVersion() > 6 then
			strUTF8 = "([\0-\127\194-\244][\128-\191]*)"
		end

		-- Supply character substring of UTF-8 text --
		function fh.substring(strTxt,i,j)
			local strSub = ""
			j = j or -1
			if j < 0 then j = j + length(strTxt) + 1 end
			if i < 0 then i = i + length(strTxt) + 1 end
			for strChr in string.gmatch(strTxt or "",strUTF8) do
				if j <= 0 then break end
				j = j - 1
				i = i - 1
				if i <= 0 then strSub = strSub..strChr end
			end
			return strSub
		end -- function substring

		-- Translate lower case to upper case UTF-8 letters --
		function fh.upper(strTxt)
			strTxt = tostring(strTxt or ""):gsub("([a-z\194-\244][\128-\191]*)",dicUpper)
			return strTxt
		end -- function upper

		-- Translate upper case to lower case UTF-8 letters --
		function fh.lower(strTxt)
			strTxt = tostring(strTxt or ""):gsub("([A-Z\194-\244][\128-\191]*)",dicLower)
			return strTxt
		end -- function lower

		-- Translate upper/lower case UTF-8 letters to pattern that matches both --
		function fh.caseless(strTxt)
			strTxt = tostring(strTxt or ""):gsub("([A-Za-z\194-\244][\128-\191]*)",dicCaseX)
			return strTxt
		end -- function caseless

		-- Following tables use ASCII numeric coding to be immune from ANSI/UTF-8 encoding --

		local arrPairs =	-- Upper & Lower case groups of UTF-8 letters with same prefix --
		{--	{ Prefix; Beg ; End ; Inc; Offset Upper > Lower };			-- These include all ANSI letters and many more
			{ "\195"; 0x80; 0x96;  1 ; 32 };								-- 195=0xC3 À U+00C0 to Ö U+00D6 and à U+00E0 to ö U+00F6
			{ "\195"; 0x98; 0x9E;  1 ; 32 };								-- 195=0xC3 Ø U+00D8 to Þ U+00DE and ø U+00F8 to þ U+00FE
			{ "\196"; 0x80; 0xB6;  2 ;  1 };								-- 196=0xC4 A U+0100 to k U+0137 in pairs
			{ "\196"; 0xB9; 0xBD;  2 ;  1 };								-- 196=0xC4 L U+0139 to l U+013E in pairs
			{ "\197"; 0x81; 0x87;  2 ;  1 };								-- 197=0xC5 L U+0141 to n U+0148 in pairs
			{ "\197"; 0x8A; 0xB6;  2 ;  1 };								-- 197=0xC5 ? U+014A to y U+0177 in pairs
			{ "\197"; 0xB9; 0xBD;  2 ;  1 };								-- 197=0xC5 Z U+0179 to ž U+017E in pairs
			{ "\198"; 0x82; 0x84;  2 ;  1 };								-- 198=0xC6 ?  U+0182 to ?  U+0185 in pairs
			-- Add more Unicode groups here as usage increases --
		}
		local dicPairs =	-- Upper v Lower case UTF-8 letters that don't fit groups above --
		{	[string.char(0xC4,0xBF)] = string.char(0xC5,0x80);			-- ? U+013F and ? U+0140
			[string.char(0xC5,0xB8)] = string.char(0xC3,0xBF);			-- Ÿ U+0178 and ÿ U+00FF
		}

		local intBeg1 = string.byte(string.sub("À",1))
		local intBeg2 = string.byte(string.sub("À",2))
		local intEnd1 = string.byte(string.sub("Z",1))
		local intEnd2 = string.byte(string.sub("Z",2))
	--	print(string.format("%#x %#x %#x %#x",intBeg1,intBeg2,intEnd1,intEnd2)) -- Useful to work out numeric coding

		-- Populate the UTF-8 letter translation dictionaries --
		for intGroup, tblGroup in ipairs ( arrPairs ) do				-- UTF-8 accented letter groups
			local strPrefix = tblGroup[1]
			for intUpper = tblGroup[2], tblGroup[3], tblGroup[4] do
				local strUpper = string.char(intUpper)
				local strLower = string.char(intUpper + tblGroup[5])
				local strCaseX = strPrefix.."["..strUpper..strLower.."]"
				strUpper = strPrefix..strUpper
				strLower = strPrefix..strLower
				dicUpper[strLower] = strUpper
				dicLower[strUpper] = strLower
				dicCaseX[strLower] = strCaseX
				dicCaseX[strUpper] = strCaseX
			end
		end
		for strUpper, strLower in pairs ( dicPairs ) do					-- UTF-8 accented letters where upper & lower have different prefix
			dicUpper[strLower] = strUpper
			dicLower[strUpper] = strLower
			local strCaseX = ""
			for intByte = 1, #strUpper do									-- Matches more than just the two letters, but can't do any better
				strCaseX = strCaseX.."["..strUpper:sub(intByte,intByte)..strLower:sub(intByte,intByte).."]"
			end
			dicCaseX[strLower] = strCaseX
			dicCaseX[strUpper] = strCaseX
		end

	end

	-- overload fh functions into string table
	for strIndex, anyValue in pairs(fh) do
		if type(anyValue) == "function" then
			string[strIndex] = anyValue
		end
	end

	return fh

end -- local function stringx_v3

local stringx = stringx_v3()													-- To access FH string extension module

--[[
@Module:			+fh+iterate_v3
@Author:			Mike Tate
@Version:			3.0
@LastUpdated:	25 Aug 2020
@Description:	An iterater functions module to supplement LUA functions.
@V3.0:				Function Prototype Closure version.
@V1.2:				RecordTypes() includes HEAD tag.
@V1.1:				?
@V1.0:				Initial version.
]]

local function iterate_v3()

	local fh = {}																-- Local environment table

	-- Iterator for all records of one chosen type --
	function fh.Records(strType)
		local ptrAll = fhNewItemPtr()										-- Pointer to all records in turn
		local ptrRec = fhNewItemPtr()										-- Pointer to record returned to user
		ptrAll:MoveToFirstRecord(strType)
		return function ()
			ptrRec:MoveTo(ptrAll)
			ptrAll:MoveNext()
			if ptrRec:IsNotNull() then return ptrRec end
		end
	end -- function Records

	-- Iterator for all the record types --
	function fh.RecordTypes()
		local intNext = -1														-- Next record type number
		local intLast = fhGetRecordTypeCount()								-- Last record type number
		return function()
			intNext = intNext + 1
			if intNext == 0 then												-- Includes HEAD tag -- V1.2
				return "HEAD"
			elseif intNext <= intLast then
				return fhGetRecordTypeTag(intNext)							-- Return record type tag
			end
		end
	end -- function RecordTypes

	-- Iterator for all items in all records of chosen types --
	function fh.Items(...)
		local arg = {...}
		local intType = 1														-- Integer record type number
		local tblType = {}														-- Table of record type tags
		local ptrNext = fhNewItemPtr()										-- Pointer to next item in turn
		local ptrItem = fhNewItemPtr()										-- Pointer to item returned to user

		if #arg == 0 then
			for intType = 1, fhGetRecordTypeCount() do					-- No parameters so use all record types
				tblType[intType] = fhGetRecordTypeTag(intType)
			end
		else
			tblType = arg														-- Got parameters so use them instead
		end
	--	print(tblType[intType],intType)
		ptrNext:MoveToFirstRecord(tblType[intType])						-- Get first record of first type

		return function()
			repeat
				while ptrNext:IsNotNull() do									-- Loop through all items
					ptrItem:MoveTo(ptrNext)
					ptrNext:MoveNextSpecial()
					if ptrItem:IsNotNull() then return ptrItem end
				end
				intType = intType + 1											-- Loop through each record type
				if intType <= #tblType then
					ptrNext:MoveToFirstRecord(tblType[intType])
				end
			until intType > #tblType
		end
	end -- function Items

	-- Iterator for all facts of an individual --
	function fh.Facts(ptrIndi)
		local ptrItem = fhNewItemPtr()										-- Pointer to each item at level 1
		local ptrFact = fhNewItemPtr()										-- Pointer to each fact returned to user
		ptrItem:MoveToFirstChildItem(ptrIndi)
		return function ()
			while ptrItem:IsNotNull() do
				ptrFact:MoveTo(ptrItem)
				ptrItem:MoveNext()
				if fhIsFact(ptrFact) then return ptrFact end
			end
		end
	end -- function Facts

	return fh

end -- local function iterate_v3

local iterate = iterate_v3()													-- To access FH iterate items module

--[[
@Module:			+fh+general_v3
@Author:			Mike Tate
@Version:			3.5
@LastUpdated:	12 Dec 2024
@Description:	A general functions module to supplement LUA functions, where filenames use UTF-8 but for a few exceptions.
@V3.5:				Further fix for Crossover/WINE file attributes;
@V3.4:				Further fix for Unix/WINE file attributes;
@V3.3:				Fix problem in fh.MakeFolder(...) when folder path is invalid; Remove Type, ShortName & ShortPath from attributes(...) as unsupported in WINE;
@V3.2:				Added function DetectOldModules(); Updated functions RenameFile(), RenameFolder() & GetFolderContents();
@V3.1:				Functions derived from FH V7 fhFileUtils library using File System Objects, plus additional features;
@V3.0:				Function Prototype Closure version; GetDayNumber() error message reasons;
@V1.5:				Revised SplitFilename(strFilename) for missing extension.
@V1.4:				Revised EstimatedBirthDates() & EstimatedDeathDates() to fix null Dates.
@V1.3:				Add GetDayNumber(), EstimatedBirthDates(), EstimatedDeathDates().
@V1.2:				SplitFilename() updated for directory only paths, and MakeFolder() added.
@V1.1:				pl.path experiment revoked. New DirTree with omit branch option. Avoid using stringx_v2.
@V1.0:				Initial version.
]]

local function general_v3()

	local fh = {}													-- Local environment table

	require("luacom")												-- To create File System Object
	fh.FSO = luacom.CreateObject("Scripting.FileSystemObject")

	-- Report error message --
	local function doError(strMessage,errFunction)
		-- strMessage		~ error message text
		-- errFunction		~ optional error reporting function
		if type(errFunction) == "function" then
			errFunction(strMessage)
		else
			error(strMessage)
		end
	end -- local function doError

	-- Convert filename to ANSI alternative and indicate success --
	function fh.FileNameToANSI(strFileName,strAnsiName)
		-- strFileName		~ full file path
		-- strAnsiFile		~ ANSI file name & type
		-- return values	~ ANSI file path, true if original path was ANSI compatible
		if stringx.encoding() == "ANSI" then return strFileName, true end
		local isFlag = fhIsConversionLossFlagSet()
		fhSetConversionLossFlag(false)
		local strAnsi = fhConvertUTF8toANSI(strFileName)
		local wasAnsi = true
		if fhIsConversionLossFlagSet() then
			strAnsiName = strAnsiName or "ANSI.ANSI"
			strAnsi = fhGetContextInfo("CI_APP_DATA_FOLDER").."\\Plugin Data\\"..strAnsiName
			wasAnsi = false
		end
		fhSetConversionLossFlag(isFlag)
		return strAnsi, wasAnsi
	end -- local function FileNameToANSI

	-- Get parent folder --
	function fh.GetParentFolder(strFileName)
		-- strFileName		~ full file path
		-- return value		~ parent folder path
		local strParent = fh.FSO:GetParentFolderName(strFileName)	--! Faulty in FH v6 with Unicode chars in path
		if fhGetAppVersion() == 6 then
			local _, wasAnsi = fh.FileNameToANSI(strFileName)
			if not wasAnsi then
				strParent = strFileName:match("^(.+)[\\/][^\\/]+[\\/]?$")
			end
		end
		return strParent
	end -- function GetParentFolder

	-- Check if file exists --
	function fh.FlgFileExists(strFileName)
		-- strFileName		~ full file path
		-- return value		~ true if it exists
		return fh.FSO:FileExists(strFileName)
	end -- function FlgFileExists

	-- Check if folder exists --
	function fh.FlgFolderExists(strFolderName)
		-- strFolderName	~ full file path
		-- return value		~ true if it exists
		return fh.FSO:FolderExists(strFolderName)
	end -- function FlgFolderExists

	-- Delete a file if it exists --
	function fh.DeleteFile(strFileName,errFunction)
		-- strFileName		~ full file path
		-- errFunction		~ optional error reporting function
		-- return value		~ true if file does not exist or is deleted else false
		if fh.FSO:FileExists(strFileName) then
			fh.FSO:DeleteFile(strFileName,true)
			if fh.FSO:FileExists(strFileName) then
				doError("File Not Deleted:\n"..strFileName.."\n",errFunction)
				return false
			end
		end
		return true
	end -- function DeleteFile

	-- Delete a folder if it exists including contents --
	function fh.DeleteFolder(strFolderName,errFunction)
		-- strFolderName	~ full folder path
		-- errFunction		~ optional error reporting function
		-- return value		~ true if folder does not exist or is deleted else false
		if fh.FSO:FolderExists(strFolderName) then
			fh.FSO:DeleteFolder(strFolderName,true)
			if fh.FSO:FolderExists(strFolderName) then
				doError("Folder Not Deleted:\n"..strFolderName.."\n",errFunction)
				return false
			end
		end
		return true
	end -- function DeleteFolder

	-- Rename a file if it exists --
	function fh.RenameFile(strFileName,strNewName)
		-- strFileName		~ full file path
		-- strNewName		~ new file name & type
		-- return value		~ true if file exists but new name does not and rename is OK else false
		local strNewFile = fh.GetParentFolder(strFileName).."\\"..strNewName
		if fh.FSO:FileExists(strFileName) and not fh.FSO:FileExists(strNewFile) then
			local fileObject = fh.FSO:GetFile(strFileName)
			fileObject.Name = strNewName
			if fh.FSO:FileExists(strNewFile) then
				return true
			end
		end
		return false
	end -- function RenameFile

	-- Rename a folder if it exists --
	function fh.RenameFolder(strFolderName,strNewName)
		-- strFolderName	~ full folder path
		-- strNewName		~ new folder name
		-- return value		~ true if folder exists but new name does not and rename is OK else false
		local strNewFolder = fh.GetParentFolder(strFolderName).."\\"..strNewName
		if fh.FSO:FolderExists(strFolderName) and not fh.FSO:FolderExists(strNewFolder) then
			local folderObject = fh.FSO:GetFolder(strFolderName)
			folderObject.Name = strNewName
			if fh.FSO:FolderExists(strNewFolder) then
				return true
			end
		end
		return false
	end -- function RenameFolder

	-- Copy a file if it exists and destination is not a folder --
	function fh.CopyFile(strFileName,strDestination)
		-- strFileName		~ full source file path
		-- strDestination	~ full target file path
		-- return value		~ true if file exists and is copied else false
		if fh.MakeFolder(fh.GetParentFolder(strDestination)) and fh.FSO:FileExists(strFileName) and not fh.FSO:FolderExists(strDestination) then
			fh.FSO:CopyFile(strFileName,strDestination)
			if fh.FSO:FileExists(strDestination) then
				return true
			end
		end
		return false
	end -- function CopyFile

	-- Copy a folder if it exists and destination is not a file --
	function fh.CopyFolder(strFolderName,strDestination)
		-- strFolderName	~ full source folder path
		-- strDestination	~ full target folder path
		-- return value		~ true if folder exists and is copied else false
		if fh.MakeFolder(fh.GetParentFolder(strDestination)) and fh.FSO:FolderExists(strFolderName) and not fh.FSO:FileExists(strDestination) then
			fh.FSO:CopyFolder(strFolderName,strDestination)
			if fh.FSO:FolderExists(strDestination) then
				return true
			end
		end
		return false
	end -- function CopyFolder

	-- Move a file if it exists and destination is not a folder --
	function fh.MoveFile(strFileName,strDestination)
		-- strFileName		~ full source file path
		-- strDestination	~ full target file path
		-- return value		~ true if file exists and is moved else false
		if fh.MakeFolder(fh.GetParentFolder(strDestination)) and fh.FSO:FileExists(strFileName) and not fh.FSO:FolderExists(strDestination) then
			if fh.DeleteFile(strDestination) then
				fh.FSO:MoveFile(strFileName,strDestination)
				if fh.FSO:FileExists(strDestination) then
					return true
				end
			end
		end
		return false
	end -- function MoveFile

	-- Move a folder if it exists and destination is not a file --
	function fh.MoveFolder(strFolderName,strDestination)
		-- strFolderName	~ full source folder path
		-- strDestination	~ full target folder path
		-- return value		~ true if folder exists and is moved else false
		if fh.MakeFolder(fh.GetParentFolder(strDestination)) and fh.FSO:FolderExists(strFolderName) and not fh.FSO:FileExists(strDestination) then
			if fh.DeleteFolder(strDestination) then
				fh.FSO:MoveFolder(strFolderName,strDestination)
				if fh.FSO:FolderExists(strDestination) then
					return true
				end
			end
		end
		return false
	end -- function MoveFolder

	local function CreateFolder(strFolderName)				-- V3.3
		fh.FSO:CreateFolder(strFolderName)
	end -- local function CreateFolder(strFolderName)

	-- Make subfolder recursively if does not exist --
	function fh.MakeFolder(strFolderName,errFunction)
		-- strFolderName	~ full source folder path
		-- errFunction		~ optional error reporting function
		-- return value		~ true if folder exists or created else false
		if not fh.FSO:FolderExists(strFolderName) then
			if #strFolderName > 4									-- V3.3
			and not fh.MakeFolder(fh.GetParentFolder(strFolderName),errFunction) then
				return false
			end
			if not pcall(CreateFolder,strFolderName)			-- V3.3
			or not fh.FSO:FolderExists(strFolderName) then
				doError("Cannot Make Folder Path:                 \n"..strFolderName.." \n",errFunction)
				return false
			end
		end
		return true
	end -- function MakeFolder

	-- Check if folder writable --
	function fh.FlgFolderWrite(strFolderName)
		-- strFolderName	~ full source folder path
		-- return value		~ true if folder writable else false
		if fh.FlgFolderExists(strFolderName) then
			if fh.MakeFolder(strFolderName.."\\vwxyz") then
				fh.FSO:DeleteFolder(strFolderName.."\\vwxyz",true)
				return true
			end
		end
		return false
	end -- function FlgFolderWrite

	-- Open File with ANSI path and return Handle --
	function fh.OpenFile(strFileName,strMode)
		-- strFileName		~ full file path
		-- strMode			~ "r", "w", "a" optionally suffixed with "+" &/or "b"
		-- return value		~ file handle
		local fileHandle, strError = io.open(strFileName,strMode)
		if fileHandle == nil then
			error("\n Unable to open file in \""..strMode.."\" mode. \n "..strFileName.." \n "..strError.." \n")
		end
		return fileHandle
	end -- function OpenFile

	-- Save string to file --
	function fh.SaveStringToFile(strContents,strFileName,strFormat)
		-- strContents		~ text string
		-- strFileName		~ full file path
		-- strFormat			~ optional "UTF-8" or "UTF-16LE"
		-- return value		~ true if successful else false
		strFormat = strFormat or "UTF-8"
		if fhGetAppVersion() > 6 then
			return fhSaveTextFile(strFileName,strContents,strFormat)
		end
		local strAnsi, wasAnsi = fh.FileNameToANSI(strFileName)
		local fileHandle = fh.OpenFile(strAnsi,"w")
		fileHandle:write(strContents)
		assert(fileHandle:close())
		if not wasAnsi then
			fh.MoveFile(strAnsi,strFileName)
		end
		return true
	end -- function SaveStringToFile

	-- Load string from file --
	function fh.StrLoadFromFile(strFileName,strFormat)
		-- strFileName		~ full file path
		-- strFormat			~ optional "UTF-8" or "UTF-16LE"
		-- return value		~ file contents
		strFormat = strFormat or "UTF-8"
		if fhGetAppVersion() > 6 then
			return fhLoadTextFile(strFileName,strFormat)
		end
		local strAnsi, wasAnsi = fh.FileNameToANSI(strFileName)
		if not wasAnsi then
			fh.CopyFile(strFileName,strAnsi)
		end
		local fileHandle = fh.OpenFile(strAnsi,"r")
		local strContents = fileHandle:read("*all")
		assert(fileHandle:close())
		return strContents
	end -- function StrLoadFromFile

	-- Returns the Path, Filename, and Extension as 3 values --
	function fh.SplitFilename(strFileName)
		-- strFileName		~ full file path
		-- return values	~ path, name.type, type
		if fh.FSO:FolderExists(strFileName) then
			local strPath = strFileName:gsub("[\\/]$","")
			return strPath.."\\","",""
		end
		strFileName = strFileName.."."
		return strFileName:match("^(.-)([^\\/]-%.([^\\/%.]-))%.?$")
	end -- function SplitFilename

	-- Convert dd/mm/yyyy hh:mm:ss format to integer seconds -- (DateTime format is used in attributes returned by GetFolderContents and DirTree below)
	function fh.IntTime(strDateTime)
		-- strDateTime		~ date time string
		-- return value		~ integer seconds since 01/01/1970 00:00:00 
		local strDay,strMonth,strYear,strHour,strMin,strSec = strDateTime:match("^(%d%d)/(%d%d)/(%d+) (%d%d):(%d%d):(%d%d)")
		if tonumber(strYear) < 1970 then return 0 end
		local isDST = false
		if tonumber(strMonth) > 4 and tonumber(strMonth) < 11 then isDST = true end	-- Approximation is sometimes wrong
		local intTime = os.time( { year=strYear; month=strMonth; day=strDay; hour=strHour; min=strMin; sec=strSec; isdst=isDST; } )
		local tblDat = os.date("*t",intTime)
		if tblDat.isdst then
			intTime = intTime + 3600
			isDST = true
		end
		return intTime
	end -- function IntTime

	-- Return table of attributes for folder --
	local function attribFolder(tblAttr)
		-- tblAttr		~ folder attributes table
		-- return value	~ attributes table like LFS except datetimes
		-- WINE only supports the tblAttr.name & tblAttr.path
		return { mode="directory"; name=tblAttr.name; path=tblAttr.path; }
	end -- local function attribFolder

	-- Return table of attributes for file --
	local function attribFile(tblAttr)
		-- tblAttr		~ file attributes table
		-- return value	~ attributes table like LFS except datetimes
		-- WINE does not support the tblAttr.type, tblAttr.shortname, tblAttr.shortpath & sometimes tblAttr.datecreated
		return { mode="file"; name=tblAttr.name; path=tblAttr.path; size=tblAttr.size; modified=tblAttr.datelastmodified; attributes=tblAttr.attributes; }
	end -- local function attribFile

	-- Return attributes table of all files and folders in a specified folder --
	function fh.GetFolderContents(strFolder,doRecurse)
		-- strFolder		~ full folder path
		-- doRecurse		~ true for recursion
		-- return value	~ attributes table
		local arrList = {}
		if fh.FSO:FolderExists(strFolder) then

			local function getFileList(strFolder)
				local tblList = fh.FSO:GetFolder(strFolder)
				local tblEnum = luacom.GetEnumerator(tblList.SubFolders)
				local tblAttr = tblEnum:Next()
				while tblAttr do
					table.insert(arrList,attribFolder(tblAttr))
					if doRecurse then getFileList(tblAttr.path) end
					tblAttr = tblEnum:Next()
				end
				local tblEnum = luacom.GetEnumerator(tblList.Files)
				local tblAttr = tblEnum:Next()
				while tblAttr do
					table.insert(arrList,attribFile(tblAttr))
					tblAttr = tblEnum:Next()
				end
			end

			getFileList(strFolder)
		end
		return arrList
	end -- function GetFolderContents

	-- Return a Directory Tree entry & attributes on each iteration --
	function fh.DirTree(strDir,...)
		-- strDir			~ full folder path
		-- ...				~ list of folders to omit
		-- return value	~ full path, attributes table
		local arg = {...}
		assert( fh.FSO:FolderExists(strDir), "directory parameter is missing or empty" )

		local function yieldtree(strDir)
			local tblList = fh.FSO:GetFolder(strDir)
			local tblEnum = luacom.GetEnumerator(tblList.SubFolders)
			local tblAttr = tblEnum:Next()
			while tblAttr do	--	for _,tblAttr in luacom.pairs(tblList.SubFolders) do	-- pairs not working in FH v6 so use tblEnum code
				coroutine.yield(tblAttr.path,attributes(tblAttr,"directory"))
				local isOK = true
				for _,strOmit in ipairs (arg) do
					if tblAttr.path:match(strOmit) then 	-- Omit tree branch
						isOK = false
						break
					end
				end
				if isOK then yieldtree(tblAttr.path) end
				tblAttr = tblEnum:Next()
			end
			local tblEnum = luacom.GetEnumerator(tblList.Files)
			local tblAttr = tblEnum:Next()
			while tblAttr do	--	for _,tblAttr in luacom.pairs(tblList.Files) do		-- pairs not working in FH v6 so use tblEnum code
				coroutine.yield(tblAttr.path,attributes(tblAttr,"file"))
				tblAttr = tblEnum:Next()
			end
		end

		return coroutine.wrap(function() yieldtree(strDir) end)
	end -- function DirTree

	-- Detect FH V5/6 old library modules and advise removal --
	function fh.DetectOldModules()
		if fhGetAppVersion() > 6 then
			local strPath = fhGetContextInfo("CI_APP_DATA_FOLDER").."\\Plugins\\"
			local arrFile = { "compat53.lua"; "ltn12.lua"; "luasql\\sqlite3.dll"; "md5.lua"; "pl\\init.lua"; "socket.lua"; "utf8.lua"; "zip.dll"; }
			for _, strFile in ipairs (arrFile) do
				if fh.FSO:FileExists(strPath..strFile) then
					fhMessageBox("\n  Detected some old FH V6 library modules. \n\nPlease remove them by running the plugin: \n\n     'Delete old FH6 Plugin Module Files' \n","MB_OK","MB_ICONEXCLAMATION")
					break
				end
			end
		end
	end -- function DetectOldModules

	if fhGetAppVersion() > 6 then unpack = table.unpack end

	-- Invoke FH Shell Execute API --
	function fh.DoExecute(strExecutable,...)
		-- strExecutable	~ full path of executable
		-- ...					~ parameter list and optional error reporting function
		-- return value		~ true if successful else false
		local arg = {...}
		local errFunction = fhMessageBox
		if type(arg[#arg]) == 'function' then
			errFunction = arg[#arg]
			table.remove(arg)
		end
		local isOK, intErrorCode, strErrorText = fhShellExecute(strExecutable,unpack(arg))
		if not isOK then
			errFunction(tostring(strErrorText).." ("..tostring(intErrorCode)..")")
		end
		return isOK
	end -- function DoExecute

	-- Obtain the Day Number for any Date Point --									-- Fix problems with invalid dates in DayNumber function
	function fh.GetDayNumber(datDate)
		-- datDate		~ date point
		-- return value	~ day number
		if datDate:IsNull() then return 0 end
		local intDay = fhCallBuiltInFunction("DayNumber",datDate) 				-- Only works for Gregorian dates that were not skipped nor BC dates
		if not intDay then
			local strError = "because "													-- Error message reason	-- V3.0
			local calendar = datDate:GetCalendar()
			local oldMonth = datDate:GetMonth()
			local oldDayNo = datDate:GetDay()
			local intMonth = math.min( oldMonth, 12 ) 								-- Limit month to 12, and day to last of each month
			local intDayNo = math.min( oldDayNo, ({0;31;28;31;30;31;30;31;31;30;31;30;31;})[intMonth+1] )
			local intYear  = datDate:GetYear()
			if oldDayNo > intDayNo then strError = strError.."day "..oldDayNo.." too big "   end
			if oldMonth > intMonth then strError = strError.."month "..oldMonth.." too big " end
			if calendar == "Hebrew" and intYear > 3761 then
				intYear = intYear - 3761
				strError = strError.."Hebrew year > 3761 "
			elseif calendar ~= "Gregorian" then
				strError = strError..calendar.." disallowed "
			end
			if     intYear == 1752 and intMonth ==  9 and intDayNo <= 13 then	-- Use 2 Sep 1752 for 3 - 13 Sep 1752 dates skipped
				intDayNo = 2
				strError = strError.."3 - 13 Sep 1752 skipped "
			elseif intYear == 1582 and intMonth == 10 and intDayNo <= 14 then	-- Use 4 Oct 1582 for 5 - 14 Oct 1582 dates skipped
				intDayNo = 4
				strError = strError.."5 - 14 Oct 1582 skipped "
			end	
			local setDate = fhNewDatePt(intYear,intMonth,intDayNo,datDate:GetYearDD())
			intDay = fhCallBuiltInFunction("DayNumber",setDate) 					-- Remove BC and Julian, Hebrew, French calendars
			if not intDay then intDay = 0 end
			local oldDate = fhNewDate()		oldDate:SetSimpleDate(datDate)		-- Report problem to user
			local newDate = fhNewDate()		newDate:SetSimpleDate(setDate)
			local strIsBC = ""
			if datDate:GetBC() then
				strError = strError.." B.C. disallowed "
				intDay = -intDay
				strIsBC = "and Day Number negated"
			end
			fhMessageBox("\n Get Day Number issue for date \n "..oldDate:GetDisplayText().." \n "..strError.." \n So replaced it with date \n "..newDate:GetDisplayText().." \n "..strIsBC,"MB_OK","MB_ICONEXCLAMATION")
		end
		return intDay
	end -- function GetDayNumber

	local dtpYearMin = fhNewDatePt(1000)												-- Minimum year to use when earliest estimate is null
	local dtpYearMax = fhNewDatePt(2000)												-- Maximum year to use when latest estimate is null

	function fh.GetYearToday()																-- Get the Year for Today
		-- return value	~ integer year today
		local intYearToday = fhCallBuiltInFunction("Year",fhCallBuiltInFunction("Today"))
		dtpYearMax = fhNewDatePt(intYearToday)											-- Set maximum year date point
		return intYearToday
	end -- function GetYearToday()

	local function getDeathFacts(ptrIndi)												-- Iterate Death, Burial, Cremation facts
		-- ptrIndi		~ pointer to individual
		-- return value	~ pointer to fact
		local arrFact = { "~.DEAT"; "~.BURI"; "~.CREM"; }
		local intFact = 0
		local ptrFact = fhNewItemPtr()													-- Pointer to each fact returned to user
		return function ()
			while intFact < #arrFact do
				intFact = intFact + 1
				ptrFact = fhGetItemPtr(ptrIndi,arrFact[intFact])
				if ptrFact:IsNotNull() then return ptrFact end
			end
		end
	end -- local function getDeathFacts

	-- Ensure Estimated Date EARLIEST <= LATEST <= Fact Date --					-- Fix errors in EstimatedBirth/DeathDate function
	local function estimatedDates(strFunc,ptrIndi,intGens,getFact,intYrs)
		-- strFunc			~ "EstimatedBirthDate" or "EstimatedDeathDate"
		-- ptrIndi			~ Individual of interest
		-- intGens			~ Number of generations (may be nil)
		-- getFact			~ Iterator function for facts
		-- intYrs 			~ Years to add to After dates
		-- return values	~ EARLIEST, MID, LATEST dates
		intGens = intGens or 2
		local dtpMin = fhCallBuiltInFunction(strFunc,ptrIndi,"EARLIEST",intGens)
		local dtpMax = fhCallBuiltInFunction(strFunc,ptrIndi,"LATEST",intGens)
		local dtpMid = fhNewDatePt()
		if not ( dtpMin:IsNull() and dtpMax:IsNull() ) then 						-- Skip if both null	
			if dtpMax:IsNull() then dtpMax = dtpYearMax elseif dtpMin:IsNull() then dtpMin = dtpYearMin end
			for ptrFact in getFact(ptrIndi) do
				local datFact = fhGetValueAsDate(fhGetItemPtr(ptrFact,"~.DATE"))
				if not datFact:IsNull() then												-- Find 1st Fact Date
					local dtpLast = datFact:GetDatePt1()								-- Last date = DatePt1 for Simple, Range, and Before
					local strType = datFact:GetSubtype()								-- Between = DatePt2 and After = DatePt1 + intYrs
					if   strType == "Between" then dtpLast = datFact:GetDatePt2()
					elseif strType == "After" then dtpLast = fhNewDatePt(dtpLast:GetYear()+intYrs,dtpLast:GetMonth(),dtpLast:GetDay()) end		-- Compare only uses Year, Month, Day so omitted	,dtpLast:GetYearDD(),dtpLast:GetBC(),dtpLast:GetCalendar()
					if dtpMax:Compare(dtpLast) > 0 then dtpMax = dtpLast end
					if dtpMin:Compare(dtpMax)  > 0 then dtpMin = dtpMax  end
					if strType ~= "After" then break end								-- Now EARLIEST <= LATEST <= Last date
				end
			end	
			local intDays = ( fh.GetDayNumber(dtpMax) - fh.GetDayNumber(dtpMin) ) / 2
			local intYear,remYear = math.modf( intDays / 365.2422 )				-- Offset year @ 365.2422 days per year, and remainder fraction
			local intMnth = math.floor( ( remYear * 12 ) + 0.1 )					-- Offset month is remainder fraction of year * 12
			dtpMid = fhCallBuiltInFunction("CalcDate",dtpMin,intYear,intMnth)	-- Need approximate MID year & month
		end
		return { Min=dtpMin; Mid=dtpMid; Max=dtpMax; }								-- Return EARLIEST, MID, LATEST dates
	end -- local function estimatedDates

	-- Make EstimatedBirthDate EARLIEST <= LATEST <= 1st Fact Date --			-- Fix errors in EstimatedBirthDate function
	function fh.EstimatedBirthDates(ptrIndi,intGens)
		-- ptrInd				~ pointer to individual
		-- intGens			~ generations to include
		-- return values	~ EARLIEST, MID, LATEST dates
		return estimatedDates("EstimatedBirthDate",ptrIndi,intGens,iterate.Facts,10)
	end -- function EstimatedBirthDates

	-- Make EstimatedDeathDate EARLIEST <= LATEST <= DEAT/BURI/CREM Date --	-- Fix errors in EstimatedDeathDate function
	function fh.EstimatedDeathDates(ptrIndi,intGens)
		-- ptrInd				~ pointer to individual
		-- intGens			~ generations to include
		-- return values	~ EARLIEST, MID, LATEST dates
		return estimatedDates("EstimatedDeathDate",ptrIndi,intGens,getDeathFacts,100)
	end -- function EstimatedDeathDates

	--[[
	@function:		BuildDataRef
	@description:	Get Full Data Reference for Pointer
	@parameters:		Item Pointer
	@returns:			Data Reference String, Record Id Integer, Record Type Tag String
	@requires:		None
	]]
	function fh.BuildDataRef(ptrRef)

		local strDataRef = ""										-- Data Reference with instance indices e.g. INDI.RESI[2].ADDR
		local intRecId   = 0										-- Record Id for associated Record
		local strRecTag  = ""										-- Record Tag of associated Record type i.e. INDI, FAM, NOTE, SOUR, etc

		-- getDataRef() is called recursively per level of the Data Ref
		-- ptrRef points to the upper Data Ref levels yet to be analysed
		-- strRef compiles the lower Data Ref levels including instances

		local function getDataRef(ptrRef,strRef)
			local ptrTag = ptrRef:Clone()
			local strTag = fhGetTag(ptrTag)						-- Current level Tag
			ptrTag:MoveToParentItem(ptrTag)
			if ptrTag:IsNotNull() then							-- Parent level exists
				local intSib = 1
				local ptrSib = ptrRef:Clone()					-- Pointer to siblings with same Tag
				ptrSib:MovePrev("SAME_TAG")
				while ptrSib:IsNotNull() do						-- Count previous siblings with same Tag
					intSib = intSib + 1
					ptrSib:MovePrev("SAME_TAG")
				end
				if intSib > 1 then 	strTag = strTag.."["..intSib.."]" end
				getDataRef(ptrTag,"."..strTag..strRef)			-- Now analyse the parent level
			else
				strDataRef = strTag..strRef						-- Record level reached, so set return values
				intRecId   = fhGetRecordId(ptrRef)
				strRecTag  = strTag
				if not fhIsValidDataRef(strDataRef) then print("BuildDataRef: "..strDataRef.." is Invalid") end
			end
		end -- local function getDataRef

		if type(ptrRef) == "userdata" then getDataRef(ptrRef,"") end

		return strDataRef, intRecId, strRecTag

	end -- function BuildDataRef

	--[[
	@function:		GetDataRefPtr
	@description:	Get Pointer for Full Data Reference
	@parameters:		Data Reference String, Record Id Integer, Record Type Tag String (optional)
	@returns:			Item Pointer which IsNull() if any parameters are invalid
	@requires:		None
	]]
	function fh.GetDataRefPtr(strDataRef,intRecId,strRecTag)
		strDataRef = strDataRef or ""
		if not strRecTag then
			strRecTag = strDataRef:gsub("^(%u+).*$","%1")	-- Extract Record Tag from Data Ref
		end
		local ptrRef = fhNewItemPtr()
		ptrRef:MoveToRecordById(strRecTag,intRecId or 0)	-- Lookup the Record by Id
		ptrRef:MoveTo(ptrRef,strDataRef)						-- Move to the Data Ref
		return ptrRef
	end -- function GetDataRefPtr

	function fh.TblDataRef(ptrRef)
		local tblRef = {}
		tblRef.DataRef, tblRef.RecId, tblRef.RecTag = BuildDataRef(ptrRef)
		return tblRef
	end -- function TblDataRef

	function fh.PtrDataRef(tblRef)
		local tblRef = tblRef or {}								-- Ensure table and its fields exist
		return GetDataRefPtr(tblRef.DataRef or "",tblRef.RecId or 0,tblRef.RecTag or "")
	end -- function PtrDataRef

	return fh

end -- local function general_v3

local general = general_v3()										-- To access FH general tools module

--[[
@Module:			+fh+tablex_v3
@Author:			Mike Tate
@Version:			3.1
@LastUpdated:	08 Jan 2022
@Description:	A Table Load Save Module.
@V3.1:				Cater for full UTF-8 filenames.
@V3.0:				Function Prototype Closure version.
@V1.2:				Added local definitions of _ to ensure nil gets returned on error.
@V1.1:				?
@V1.0:				Initial version 0.94 is Lua 5.1 compatible.
]]

local function tablex_v3()

	local fh = {}									-- Local environment table

	------------------------------------------------------ Start Table Load Save
	-- require "_tableloadsave"
	--[[
	Save Table to File/Stringtable
	Load Table from File/Stringtable
	v 0.94

	Lua 5.1 compatible

	Userdata and indices of these are not saved
	Functions are saved via string.dump, so make sure it has no upvalues
	References are saved
	----------------------------------------------------
	table.save( table [, filename] )

	Saves a table so it can be called via the table.load function again
	table must a object of type 'table'
	filename is optional, and may be a string representing a filename or true/1

	table.save( table )
		on success: returns a string representing the table (stringtable)
		(uses a string as buffer, ideal for smaller tables)
	table.save( table, true or 1 )
		on success: returns a string representing the table (stringtable)
		(uses io.tmpfile() as buffer, ideal for bigger tables)
	table.save( table, "filename" )
		on success: returns 1
		(saves the table to file "filename")
	on failure: returns as second argument an error msg
	----------------------------------------------------
	table.load( filename or stringtable )

	Loads a table that has been saved via the table.save function

	on success: returns a previously saved table
	on failure: returns as second argument an error msg
	----------------------------------------------------

	chillcode, http://lua-users.org/wiki/SaveTableToFile
	Licensed under the same terms as Lua itself.
	]]--

	-- declare local variables
	--// exportstring( string )
	--// returns a "Lua" portable version of the string
	local function exportstring( s )
		s = string.format( "%q",s )
		-- to replace
		s = string.gsub( s,"\\\n","\\n" )
		s = string.gsub( s,"\r","\\r" )
		s = string.gsub( s,string.char(26),"\"..string.char(26)..\"" )
		return s
	end
--// The Save Function
function fh.save( tbl,filename )
	local charS,charE = "   ","\n"
	local file,err,_,stransi,wasansi 					-- V1.2 -- V3.1 -- Added _,stransi,wasansi	--!
	-- create a pseudo file that writes to a string and return the string
	if not filename then
		file =  { write = function( self,newstr ) self.str = self.str..newstr end, str = "" }
		charS,charE = "",""
	-- write table to tmpfile
	elseif filename == true or filename == 1 then
		charS,charE,file = "","",io.tmpfile()
	-- write table to file
	-- use io.open here rather than io.output, since in windows when clicking on a file opened with io.output will create an error
	else
		stransi,wasansi = general.FileNameToANSI(filename)	-- V3.1 -- Cater for non-ANSI filename	--!
		file,err = io.open( stransi, "w" )
		if err then return _,err end
	end
	-- initiate variables for save procedure
	local tables,lookup = { tbl },{ [tbl] = 1 }
	file:write( "return {"..charE )
	for idx,t in ipairs( tables ) do
		if filename and filename ~= true and filename ~= 1 then
			file:write( "-- Table: {"..idx.."}"..charE )
		end
		file:write( "{"..charE )
		local thandled = {}
		for i,v in ipairs( t ) do
			thandled[i] = true
			-- escape functions and userdata
			if type( v ) ~= "userdata" then
				-- only handle value
				if type( v ) == "table" then
					if not lookup[v] then
						table.insert( tables, v )
						lookup[v] = #tables
					end
					file:write( charS.."{"..lookup[v].."},"..charE )
				elseif type( v ) == "function" then
					file:write( charS.."loadstring("..exportstring(string.dump( v )).."),"..charE )
				else
					local value =  ( type( v ) == "string" and exportstring( v ) ) or tostring( v )
					file:write(  charS..value..","..charE )
				end
			end
		end
		for i,v in pairs( t ) do
			-- escape functions and userdata
			if (not thandled[i]) and type( v ) ~= "userdata" then
				-- handle index
				if type( i ) == "table" then
					if not lookup[i] then
						table.insert( tables,i )
						lookup[i] = #tables
					end
					file:write( charS.."[{"..lookup[i].."}]=" )
				else
					local index = ( type( i ) == "string" and "["..exportstring( i ).."]" ) or string.format( "[%d]",i )
					file:write( charS..index.."=" )
				end
				-- handle value
				if type( v ) == "table" then
					if not lookup[v] then
						table.insert( tables,v )
						lookup[v] = #tables
					end
					file:write( "{"..lookup[v].."},"..charE )
				elseif type( v ) == "function" then
					file:write( "loadstring("..exportstring(string.dump( v )).."),"..charE )
				else
					local value =  ( type( v ) == "string" and exportstring( v ) ) or tostring( v )
					file:write( value..","..charE )
				end
			end
		end
		file:write( "},"..charE )
	end
	file:write( "}" )
	-- Return Values
	-- return stringtable from string
	if not filename then
		-- set marker for stringtable
		return file.str.."--|"
	-- return stringttable from file
	elseif filename == true or filename == 1 then
		file:seek ( "set" )
		-- no need to close file, it gets closed and removed automatically
		-- set marker for stringtable
		return file:read( "*a" ).."--|"
	-- close file and return 1
	else
		file:close()
		if not ( wasansi ) then		-- V3.1 -- Cater for non-ANSI filename	--!
			general.MoveFile(stransi,filename)
		end
		return 1
	end
end

--// The Load Function
function fh.load( sfile )
	local tables,err,_ 					-- V1.2 -- Added _
	-- catch marker for stringtable
	if string.sub( sfile,-3,-1 ) == "--|" then
		tables,err = loadstring( sfile )
	else
		local stransi,wasansi = general.FileNameToANSI(sfile)	-- V3.1 -- Cater for non-ANSI filename	--!
		if not ( wasansi ) then
			general.CopyFile(sfile,stransi)
		end
		tables,err = loadfile( stransi )
		if not ( wasansi ) then
			general.DeleteFile(stransi)								-- V3.1 -- Cater for non-ANSI filename	--!
		end
	end
	if err then return _,err
	end
	tables = tables()
	for idx = 1,#tables do
		local tolinkv,tolinki = {},{}
		for i,v in pairs( tables[idx] ) do
			if type( v ) == "table" and tables[v[1]] then
				table.insert( tolinkv,{ i,tables[v[1]] } )
			end
			if type( i ) == "table" and tables[i[1]] then
				table.insert( tolinki,{ i,tables[i[1]] } )
			end
		end
		-- link values, first due to possible changes of indices
		for _,v in ipairs( tolinkv ) do
			tables[idx][v[1]] = v[2]
		end
		-- link indices
		for _,v in ipairs( tolinki ) do
			tables[idx][v[2]],tables[idx][v[1]] =  tables[idx][v[1]],nil
		end
	end
	return tables[1]
end

------------------------------------------------------ End Table Load Save

	-- overload fh functions into table
	for strIndex, anyValue in pairs(fh) do
		if type(anyValue) == "function" then
			table[strIndex] = anyValue
		end
	end

	return fh

end -- local function tablex_v3

local tablex  = tablex_v3 ()													-- To access FH table extension module

--[[
@Module:			+fh+encoder_v3
@Author:			Mike Tate
@Version:			3.6
@LastUpdated:	27 Aug 2024
@Description:	Text encoder module for HTML XHTML XML URI UTF8 UTF16 ISO CP1252/ANSI character codings.
@V3.6:				In fh.FileLines(...) cater for empty file;
@V3.5:				Function Prototype Closure version with Lua 5.1 & 5.3 comaptibility.
@V3.4:				Ensure expressions involving gsub return just text parameter.
@V3.3:				Adds UNICODE U+10000 to U+10FFFF UTF-16 Supplementary Planes.
@V3.2:				Update for ANSI & Unicode to ASCII for sorting, Soundex, etc.
@V3.1:				Update for Unicode UTF-16 & UTF-8 and fhConvertANSItoUTF8 & fhConvertUTF8toANSI, name change UTF to UTF8 & CP to ANSI.
@V2.0:				StrUTF8_Encode() replaced by StrUTF_CP1252() for entire UTF-8 range, plus new StrCP1252_ISO().
@V1.0:				Initial version.
]]

local function encoder_v3()

	local fh = {}													-- Local environment table

	local fhVersion = fhGetAppVersion()

	local br_Tag = "<br />"										-- Markup language break tag default
	local br_Lua = "<br ?/?>"										-- Lua pattern for break tag recognition

	local tblCodePage = {}											-- Code Page to XML/XHTML/HTML/URI/UTF8 encodings: http://en.wikipedia.org/wiki/Windows-1252 & 1250 & etc

	-- Control characters "\000" to "\031" for URI & Markup "[%c]" encodings are disallowed except for "\t" to "\r"

	tblCodePage["\000"] = ""	-- NUL
	tblCodePage["\001"] = ""	-- SOH
	tblCodePage["\002"] = ""	-- STX
	tblCodePage["\003"] = ""	-- ETX
	tblCodePage["\004"] = ""	-- EOT
	tblCodePage["\005"] = ""	-- ENQ
	tblCodePage["\006"] = ""	-- ACK
	tblCodePage["\a"] = ""		-- BEL
	tblCodePage["\b"] = ""		-- BS
	tblCodePage["\t"] = "+"	-- HT	space  in Markup	see setURIEncodings() and setMarkupEncodings() below
	tblCodePage["\n"] = "%0A"	-- LF	br_Tag in Markup
	tblCodePage["\v"] = "%0A"	-- VT	br_Tag in Markup
	tblCodePage["\f"] = "%0A"	-- FF	br_Tag in Markup
	tblCodePage["\r"] = "%0D"	-- CR	br_Tag in Markup
	tblCodePage["\014"] = ""	-- SO
	tblCodePage["\015"] = ""	-- SI
	tblCodePage["\016"] = ""	-- DLE
	tblCodePage["\017"] = ""	-- DC1
	tblCodePage["\018"] = ""	-- DC2
	tblCodePage["\019"] = ""	-- DC3
	tblCodePage["\020"] = ""	-- DC4
	tblCodePage["\021"] = ""	-- NAK
	tblCodePage["\022"] = ""	-- SYN
	tblCodePage["\023"] = ""	-- ETB
	tblCodePage["\024"] = ""	-- CAN
	tblCodePage["\025"] = ""	-- EM
	tblCodePage["\026"] = ""	-- SUB
	tblCodePage["\027"] = ""	-- ESC
	tblCodePage["\028"] = ""	-- FS
	tblCodePage["\029"] = ""	-- GS
	tblCodePage["\030"] = ""	-- RS
	tblCodePage["\031"] = ""	-- US

	-- ASCII characters "\032" to "\127" for URI "[%s%p]" encodings: http://en.wikipedia.org/wiki/URL and http://en.wikipedia.org/wiki/Percent-encoding

	tblCodePage[" "] = "+"		-- or "%20"	Space
	tblCodePage["!"] = "%21"	-- Reserved character
	tblCodePage['"'] = "%22"								--	"&quot;" in Markup	see setURIEncodings() and setMarkupEncodings() below
	tblCodePage["#"] = "%23"	-- Reserved character
	tblCodePage["$"] = "%24"	-- Reserved character
	tblCodePage["%"] = "%25"	-- Must be encoded
	tblCodePage["&"] = "%26"	-- Reserved character	-- "&amp;"  in Markup	see setURIEncodings() and setMarkupEncodings() below
	tblCodePage["'"] = "%27"	-- Reserved character	-- "&apos;" in Markup	see setURIEncodings() and setMarkupEncodings() below
	tblCodePage["("] = "%28"	-- Reserved character
	tblCodePage[")"] = "%29"	-- Reserved character
	tblCodePage["*"] = "%2A"	-- Reserved character
	tblCodePage["+"] = "%2B"	-- Reserved character
	tblCodePage[","] = "%2C"	-- Reserved character
--	tblCodePage["-"] = "%2D"	-- Unreserved character not encoded
--	tblCodePage["."] = "%2E"	-- Unreserved character not encoded
	tblCodePage["/"] = "%2F"	-- Reserved character
--	Digits 0 to 9				-- Unreserved characters not encoded
	tblCodePage[":"] = "%3A"	-- Reserved character
	tblCodePage[";"] = "%3B"	-- Reserved character
	tblCodePage["<"] = "%3C"								-- "&lt;"  in Markup	see setURIEncodings() and setMarkupEncodings() below
	tblCodePage["="] = "%3D"	-- Reserved character
	tblCodePage[">"] = "%3E"								-- "&gt;"  in Markup	see setURIEncodings() and setMarkupEncodings() below
	tblCodePage["?"] = "%3F"	-- Reserved character
	tblCodePage["@"] = "%40"	-- Reserved character
--	Letters A to Z				-- Unreserved characters not encoded
	tblCodePage["["] = "%5B"	-- Reserved character
	tblCodePage["\\"]= "%5C"
	tblCodePage["]"] = "%5D"	-- Reserved character
	tblCodePage["^"] = "%5E"
--	tblCodePage["_"] = "%5F"	-- Unreserved character not encoded
	tblCodePage["`"] = "%60"
--	Letters a to z				-- Unreserved characters not encoded
	tblCodePage["{"] = "%7B"
	tblCodePage["|"] = "%7C"
	tblCodePage["}"] = "%7D"
--	tblCodePage["~"] = "%7E"	-- Unreserved character not encoded
	tblCodePage["\127"] = ""	-- DEL

	-- Code Page 1252 Unicode characters "\128" to "\255" for UTF-8 scheme "[€-ÿ]" encodings: http://en.wikipedia.org/wiki/UTF-8

	tblCodePage["€"] = string.char(0xE2,0x82,0xAC)	-- "&euro;"
	tblCodePage["\129"] = ""  -- Undefined
	tblCodePage["‚"] = string.char(0xE2,0x80,0x9A)
	tblCodePage["ƒ"] = string.char(0xC6,0x92)
	tblCodePage["„"] = string.char(0xE2,0x80,0x9E)
	tblCodePage["…"] = string.char(0xE2,0x80,0xA6)
	tblCodePage["†"] = string.char(0xE2,0x80,0xA0)
	tblCodePage["‡"] = string.char(0xE2,0x80,0xA1)
	tblCodePage["ˆ"] = string.char(0xCB,0x86)
	tblCodePage["‰"] = string.char(0xE2,0x80,0xB0)
	tblCodePage["Š"] = string.char(0xC5,0xA0)
	tblCodePage["‹"] = string.char(0xE2,0x80,0xB9)
	tblCodePage["Œ"] = string.char(0xC5,0x92)
	tblCodePage["\141"] = ""  -- Undefined
	tblCodePage["Ž"] = string.char(0xC5,0xBD)
	tblCodePage["\143"] = ""  -- Undefined
	tblCodePage["\144"] = ""  -- Undefined
	tblCodePage["‘"] = string.char(0xE2,0x80,0x98)
	tblCodePage["’"] = string.char(0xE2,0x80,0x99)
	tblCodePage["“"] = string.char(0xE2,0x80,0x9C)
	tblCodePage["”"] = string.char(0xE2,0x80,0x9D)
	tblCodePage["•"] = string.char(0xE2,0x80,0xA2)
	tblCodePage["–"] = string.char(0xE2,0x80,0x93)
	tblCodePage["—"] = string.char(0xE2,0x80,0x94)
	tblCodePage["\152"] = string.char(0xCB,0x9C)	-- Small Tilde
	tblCodePage["™"] = string.char(0xE2,0x84,0xA2)
	tblCodePage["š"] = string.char(0xC5,0xA1)
	tblCodePage["›"] = string.char(0xE2,0x80,0xBA)
	tblCodePage["œ"] = string.char(0xC5,0x93)
	tblCodePage["\157"] = ""  -- Undefined
	tblCodePage["ž"] = string.char(0xC5,0xBE)
	tblCodePage["Ÿ"] = string.char(0xC5,0xB8)
	tblCodePage["\160"] = string.char(0xC2,0xA0)	-- "&nbsp;"	No Break Space
	tblCodePage["¡"] = string.char(0xC2,0xA1)		-- "&iexcl;"
	tblCodePage["¢"] = string.char(0xC2,0xA2)		-- "&cent;"
	tblCodePage["£"] = string.char(0xC2,0xA3)		-- "&pound;"
	tblCodePage["¤"] = string.char(0xC2,0xA4)		-- "&curren;"
	tblCodePage["¥"] = string.char(0xC2,0xA5)		-- "&yen;"
	tblCodePage["¦"] = string.char(0xC2,0xA6)
	tblCodePage["§"] = string.char(0xC2,0xA7)
	tblCodePage["¨"] = string.char(0xC2,0xA8)
	tblCodePage["©"] = string.char(0xC2,0xA9)
	tblCodePage["ª"] = string.char(0xC2,0xAA)
	tblCodePage["«"] = string.char(0xC2,0xAB)
	tblCodePage["¬"] = string.char(0xC2,0xAC)
	tblCodePage["­"] = string.char(0xC2,0xAD)		-- "&shy;"	Soft Hyphen
	tblCodePage["®"] = string.char(0xC2,0xAE)
	tblCodePage["¯"] = string.char(0xC2,0xAF)
	tblCodePage["°"] = string.char(0xC2,0xB0)
	tblCodePage["±"] = string.char(0xC2,0xB1)
	tblCodePage["²"] = string.char(0xC2,0xB2)
	tblCodePage["³"] = string.char(0xC2,0xB3)
	tblCodePage["´"] = string.char(0xC2,0xB4)
	tblCodePage["µ"] = string.char(0xC2,0xB5)
	tblCodePage["¶"] = string.char(0xC2,0xB6)
	tblCodePage["·"] = string.char(0xC2,0xB7)
	tblCodePage["¸"] = string.char(0xC2,0xB8)
	tblCodePage["¹"] = string.char(0xC2,0xB9)
	tblCodePage["º"] = string.char(0xC2,0xBA)
	tblCodePage["»"] = string.char(0xC2,0xBB)
	tblCodePage["¼"] = string.char(0xC2,0xBC)
	tblCodePage["½"] = string.char(0xC2,0xBD)
	tblCodePage["¾"] = string.char(0xC2,0xBE)
	tblCodePage["¿"] = string.char(0xC2,0xBF)
	tblCodePage["À"] = string.char(0xC3,0x80)
	tblCodePage["Á"] = string.char(0xC3,0x81)
	tblCodePage["Â"] = string.char(0xC3,0x82)
	tblCodePage["Ã"] = string.char(0xC3,0x83)
	tblCodePage["Ä"] = string.char(0xC3,0x84)
	tblCodePage["Å"] = string.char(0xC3,0x85)
	tblCodePage["Æ"] = string.char(0xC3,0x86)
	tblCodePage["Ç"] = string.char(0xC3,0x87)
	tblCodePage["È"] = string.char(0xC3,0x88)
	tblCodePage["É"] = string.char(0xC3,0x89)
	tblCodePage["Ê"] = string.char(0xC3,0x8A)
	tblCodePage["Ë"] = string.char(0xC3,0x8B)
	tblCodePage["Ì"] = string.char(0xC3,0x8C)
	tblCodePage["Í"] = string.char(0xC3,0x8D)
	tblCodePage["Î"] = string.char(0xC3,0x8E)
	tblCodePage["Ï"] = string.char(0xC3,0x8F)
	tblCodePage["Ð"] = string.char(0xC3,0x90)
	tblCodePage["Ñ"] = string.char(0xC3,0x91)
	tblCodePage["Ò"] = string.char(0xC3,0x92)
	tblCodePage["Ó"] = string.char(0xC3,0x93)
	tblCodePage["Ô"] = string.char(0xC3,0x94)
	tblCodePage["Õ"] = string.char(0xC3,0x95)
	tblCodePage["Ö"] = string.char(0xC3,0x96)
	tblCodePage["×"] = string.char(0xC3,0x97)
	tblCodePage["Ø"] = string.char(0xC3,0x98)
	tblCodePage["Ù"] = string.char(0xC3,0x99)
	tblCodePage["Ú"] = string.char(0xC3,0x9A)
	tblCodePage["Û"] = string.char(0xC3,0x9B)
	tblCodePage["Ü"] = string.char(0xC3,0x9C)
	tblCodePage["Ý"] = string.char(0xC3,0x9D)
	tblCodePage["Þ"] = string.char(0xC3,0x9E)
	tblCodePage["ß"] = string.char(0xC3,0x9F)
	tblCodePage["à"] = string.char(0xC3,0xA0)
	tblCodePage["á"] = string.char(0xC3,0xA1)
	tblCodePage["â"] = string.char(0xC3,0xA2)
	tblCodePage["ã"] = string.char(0xC3,0xA3)
	tblCodePage["ä"] = string.char(0xC3,0xA4)
	tblCodePage["å"] = string.char(0xC3,0xA5)
	tblCodePage["æ"] = string.char(0xC3,0xA6)
	tblCodePage["ç"] = string.char(0xC3,0xA7)
	tblCodePage["è"] = string.char(0xC3,0xA8)
	tblCodePage["é"] = string.char(0xC3,0xA9)
	tblCodePage["ê"] = string.char(0xC3,0xAA)
	tblCodePage["ë"] = string.char(0xC3,0xAB)
	tblCodePage["ì"] = string.char(0xC3,0xAC)
	tblCodePage["í"] = string.char(0xC3,0xAD)
	tblCodePage["î"] = string.char(0xC3,0xAE)
	tblCodePage["ï"] = string.char(0xC3,0xAF)
	tblCodePage["ð"] = string.char(0xC3,0xB0)
	tblCodePage["ñ"] = string.char(0xC3,0xB1)
	tblCodePage["ò"] = string.char(0xC3,0xB2)
	tblCodePage["ó"] = string.char(0xC3,0xB3)
	tblCodePage["ô"] = string.char(0xC3,0xB4)
	tblCodePage["õ"] = string.char(0xC3,0xB5)
	tblCodePage["ö"] = string.char(0xC3,0xB6)
	tblCodePage["÷"] = string.char(0xC3,0xB7)
	tblCodePage["ø"] = string.char(0xC3,0xB8)
	tblCodePage["ù"] = string.char(0xC3,0xB9)
	tblCodePage["ú"] = string.char(0xC3,0xBA)
	tblCodePage["û"] = string.char(0xC3,0xBB)
	tblCodePage["ü"] = string.char(0xC3,0xBC)
	tblCodePage["ý"] = string.char(0xC3,0xBD)
	tblCodePage["þ"] = string.char(0xC3,0xBE)
	tblCodePage["ÿ"] = string.char(0xC3,0xBF)

	-- Set XML/XHTML/HTML "[%c\"&'<>]" Markup encodings: http://en.wikipedia.org/wiki/XML and http://en.wikipedia.org/wiki/HTML
	local function setMarkupEncodings()
		tblCodePage["\t"] = " "		-- HT	"\t" to "\r" are treated as white space in Markup Languages by default
		tblCodePage["\n"] = br_Tag	-- LF	
		tblCodePage["\v"] = br_Tag	-- VT	line break tag	"<br>" or "<br >" or "<br/>" or "<br />" is better
		tblCodePage["\f"] = br_Tag	-- FF
		tblCodePage["\r"] = br_Tag	-- CR
		tblCodePage['"']  = "&quot;"
		tblCodePage["&"]  = "&amp;"
		tblCodePage["'"]  = "&apos;"
		tblCodePage["<"]  = "&lt;"
		tblCodePage[">"]  = "&gt;"
	end -- local function setMarkupEncodings

	-- Set URI/URL/URN "[%s%p]" encodings: http://en.wikipedia.org/wiki/URL and http://en.wikipedia.org/wiki/Percent-encoding
	local function setURIEncodings()
		tblCodePage["\t"] = "+"		-- HT	space
		tblCodePage["\n"] = "%0A" 	-- LF	newline
		tblCodePage["\v"] = "%0A" 	-- VT	newline
		tblCodePage["\f"] = "%0A" 	-- FF	newline
		tblCodePage["\r"] = "%0D" 	-- CR	return
		tblCodePage['"']  = "%22"
		tblCodePage["&"]  = "%26"
		tblCodePage["'"]  = "%27"
		tblCodePage["<"]  = "%3C"
		tblCodePage[">"]  = "%3E"
	end -- local function setURIEncodings

	-- Encode characters according to gsub pattern & lookup table --
	local function strEncode(strText,strPattern,tblPattern)
		return ( (strText or ""):gsub(strPattern,tblPattern) )		-- V3.4
	end -- local function strEncode

	-- Encode CP1252/ANSI characters into UTF-8 codes --
	function fh.StrANSI_UTF8(strText)
		if fhVersion > 5 then
			strText = fhConvertANSItoUTF8(strText)
		else
			strText = strEncode(strText,"[\127-ÿ]",tblCodePage)
		end
		return strText
	end -- function StrANSI_UTF8

	function fh.StrCP_UTF(strText)			-- Legacy
		return fh.StrANSI_UTF8(strText)
	end -- function StrCP1252_UTF8

	function fh.StrCP1252_UTF(strText)		-- Legacy
		return fh.StrANSI_UTF8(strText)
	end -- function StrCP1252_UTF

	-- Encode CP1252/ANSI or UTF-8 characters into UTF-8 --
	function fh.StrEncode_UTF8(strText)
		if stringx.encoding() == "ANSI" then
			return fh.StrANSI_UTF8(strText)
		else
			return strText
		end
	end -- function StrEncode_UTF8

	-- Encode CP1252/ANSI characters into XML/XHTML/HTML/UTF8 codes --
	local strANSI_XML = "[%z\001-\031\"&'<>\127-ÿ]"
	if fhVersion > 6 then											-- Cater for Lua 5.1 %z or Lua 5.3 \0
			strANSI_XML = "[\000-\031\"&'<>\127-ÿ]"
	end

	function fh.StrANSI_XML(strText)
		setMarkupEncodings()
		strText = (strText or ""):gsub(br_Lua,"\n")			-- Convert <br> & <br > & <br/> & <br /> to \n that becomes br_Tag
		strText = strEncode(strText,strANSI_XML,tblCodePage)
		return strText
	end -- function StrANSI_XML

	function StrCP_XML(strText)			-- Legacy
		return fh.StrANSI_XML(strText)
	end -- function StrCP_XML

	function StrCP1252_XML(strText)		-- Legacy
		return fh.StrANSI_XML(strText)
	end -- function StrCP1252_XML

	-- Encode UTF-8 ASCII characters into XML/XHTML/HTML codes --
	local strUTF8_XML = "[%z\001-\031\"&'<>\127]"
	if fhVersion > 6 then											-- Cater for Lua 5.1 %z or Lua 5.3 \0
			strUTF8_XML = "[\000-\031\"&'<>\127]"
	end

	function fh.StrUTF8_XML(strText)
		setMarkupEncodings()
		strText = (strText or ""):gsub(br_Lua,"\n")			-- Convert <br> & <br > & <br/> & <br /> to \n that becomes br_Tag
		strText = strEncode(strText,strUTF8_XML,tblCodePage)
		return strText
	end -- function StrUTF8_XML

	-- Encode CP1252/ANSI or UTF-8 ASCII characters into XML/XHTML/HTML codes --
	function fh.StrEncode_XML(strText)
		if stringx.encoding() == "ANSI" then
			return fh.StrANSI_XML(strText)
		else
			return fh.StrUTF8_XML(strText)
		end
	end -- function StrEncode_XML

	-- Encode Item Text characters into XML/HTML/UTF-8 codes --
	function fh.StrGetItem_XML(ptrItem,strTags)
		return fh.StrEncode_XML(fhGetItemText(ptrItem,strTags))
	end -- function StrGetItem_XML

	-- Encode CP1252/ANSI characters into URI codes --
	function fh.StrANSI_URI(strText)
		setURIEncodings()
		strText = (strText or ""):gsub(br_Lua,"\n")			-- Convert <br> & <br > & <br/> & <br /> to \n that becomes %0A
		strText = strEncode(strText,"[^0-9A-Za-z]",tblCodePage)
		return strText
	end -- function StrANSI_URI

	function fh.StrCP_URI(strText)
		return fh.StrANSI_URI(strText)
	end -- function StrCP_URI

	function fh.StrCP1252_URI(strText)
		return fh.StrANSI_URI(strText)
	end -- function StrCP1252_URI

	-- Encode UTF-8 ASCII characters into URI codes --
	local strUTF8_URI = "[%z\001-\127]"
	if fhVersion > 6 then											-- Cater for Lua 5.1 %z or Lua 5.3 \0
			strUTF8_URI = "[\000-\127]"
	end

	function fh.StrUTF8_URI(strText)
		setURIEncodings()
		strText = (strText or ""):gsub(br_Lua,"\n")			-- Convert <br> & <br > & <br/> & <br /> to \n that becomes br_Tag
		strText = strEncode(strText,strUTF8_URI,tblCodePage)
		return strText
	end -- function StrUTF8_URI

	-- Encode CP1252/ANSI or UTF-8 ASCII characters into URI codes --
	function fh.StrEncode_URI(strText)
		if stringx.encoding() == "ANSI" then
			return fh.StrANSI_URI(strText)
		else
			return fh.StrUTF8_URI(strText)
		end
	end -- function StrEncode_URI

	function fh.StrUTF8_Encode(strText) -- Legacy from V1.0
		return fh.StrUTF8_ANSI(strText)
	end -- function StrUTF8_Encode

	-- Encode UTF-8 bytes into single CP1252/ANSI character V2.0 upvalues --
	local strByteRange = "["..string.char(0xC0).."-"..string.char(0xFF).."]"
	local tblBytePoint = {0xC0;0xE0;0xF0;0xF8;0xFC;}		-- Byte codes for 2-byte, 3-byte, 4-byte, 5-byte, 6-byte UTF-8
	local tblUTF8 = {}
	for strByte = string.byte("€"), string.byte("ÿ") do
		local strChar = string.char(strByte)					-- Use CodePage to UTF-8 table to populate UTF-8 to CodePage table
		local strCode = tblCodePage[strChar]
		tblUTF8[strCode] = strChar
	end

	-- Encode UTF-8 bytes into single CP1252/ANSI character --
	function fh.StrUTF8_ANSI(strText)
		strText = strText or ""
		if fhVersion > 5 then return fhConvertUTF8toANSI(strText) end
		if strText:match(strByteRange) then						-- If text contains characters that need translating then
			local intChar = 0										-- Input character index
			local strChar = ""										-- Current character
			local strCode = ""										-- UTF-8 multi-byte code
			local tblLine = {}										-- Translated output line
			repeat
				intChar = intChar + 1								-- Step through each character in text
				strChar = strText:sub(intChar,intChar)
				if strChar:match(strByteRange) then				-- Convert UTF-8 bytes into CP character
					strCode = strChar								-- First UTF-8 byte code, whose top bits say how many bytes to append
					for intByte, strByte in ipairs(tblBytePoint) do
						if string.byte(strChar) >= strByte then
							intChar = intChar + 1					-- Append next UTF-8 byte code character
							strCode = strCode..strText:sub(intChar,intChar)
						else
							break
						end 
					end
					strChar = tblUTF8[strCode] or "¿"			-- Translate UTF-8 code into CP character
				end
				table.insert(tblLine,strChar)					-- Accumulate output char by char
			until intChar >= #strText
			strText = table.concat(tblLine)
		end
		return strText
	end -- function StrUTF8_ANSI

	function fh.StrUTF_CP(strText)			-- Legacy
		return fh.StrUTF8_ANSI(strText)
	end -- function StrUTF_CP

	function fh.StrUTF_CP1252(strText)		-- Legacy
		return fh.StrUTF8_ANSI(strText)
	end -- function StrUTF_CP1252

	-- Encode CP1252/ANSI or UTF-8 characters into ANSI --
	function fh.StrEncode_ANSI(strText)
		if stringx.encoding() == "ANSI" then
			return strText or ""
		else
			return fh.StrUTF8_ANSI(strText)
		end
	end -- function StrEncode_ANSI

	-- Set ISO-8859-1 "[\127-Ÿ]" encodings: http://en.wikipedia.org/wiki/ISO/IEC_8859-1
	local tblISO8859 = { }
	tblISO8859["\127"]=""  -- DEL
	tblISO8859["€"] = "EUR"	
	tblISO8859["\129"]=""  -- Undefined
	tblISO8859["‚"] = "¸"
	tblISO8859["ƒ"] = "f"
	tblISO8859["„"] = "¸¸"
	tblISO8859["…"] = "..."
	tblISO8859["†"] = "+"
	tblISO8859["‡"] = "±"
	tblISO8859["ˆ"] = "^"
	tblISO8859["‰"] = "%"
	tblISO8859["Š"] = "S"
	tblISO8859["‹"] = "<"
	tblISO8859["Œ"] = "OE"
	tblISO8859["\141"]=""  -- Undefined
	tblISO8859["Ž"] = "Z"
	tblISO8859["\143"]=""  -- Undefined
	tblISO8859["\144"]=""  -- Undefined
	tblISO8859["‘"] = "'"
	tblISO8859["’"] = "'"
	tblISO8859["“"] = '"'
	tblISO8859["”"] = '"'
	tblISO8859["•"] = "º"
	tblISO8859["–"] = "-"
	tblISO8859["—"] = "-"
	tblISO8859["\152"]="~" -- Small Tilde
	tblISO8859["™"] = "TM"
	tblISO8859["š"] = "s"
	tblISO8859["›"] = ">"
	tblISO8859["œ"] = "oe"
	tblISO8859["\157"]=""  -- Undefined
	tblISO8859["ž"] = "z"
	tblISO8859["Ÿ"] = "Y"

	-- Encode CP1252/ANSI characters into ISO-8859-1 codes --
	function fh.StrANSI_ISO(strText)
		return strEncode(strText,"[\127-Ÿ]",tblISO8859)
	end -- function StrANSI_ISO

	function fh.StrCP_ISO(strText)			-- Legacy
		return fh.StrANSI_ISO(strText)
	end -- function StrCP_ISO

	function fh.StrCP1252_ISO(strText)		-- Legacy
		return fh.StrANSI_ISO(strText)
	end -- function StrCP1252_ISO

	function fh.StrUTF8_ISO(strText)
		return fh.StrANSI_ISO(fh.StrUTF8_ANSI(strText))
	end -- function StrUTF8_ISO

	-- Encode CP1252/ANSI or UTF-8 ASCII characters into ISO-8859-1 codes --
	function fh.StrEncode_ISO(strText)
		if stringx.encoding() == "ANSI" then
			return fh.StrANSI_ISO(strText)
		else
			return fh.StrUTF8_ISO(strText)
		end
	end -- function StrEncode_ISO

	-- Convert UTF-8 bytes to a UTF-16 word or pair --
	local tblByte = {}
	local tblLead = { 0x80; 0xC0; 0xE0; 0xF0; 0xF8; 0xFC; }

	function fh.StrUtf8toUtf16(strChar)

		-- Convert any UTF-8 multibytes to UTF-16 --
		local function strUtf8()
			if #tblByte > 0 then
				local intUtf16 = 0
				for intIndex, intByte in ipairs (tblByte) do	-- Convert UTF-8 bytes to UNICODE U+0080 to U+10FFFF
					if intIndex == 1 then
						intUtf16 = intByte - tblLead[#tblByte]
					else
						intUtf16 = intUtf16 * 0x40 + intByte - 0x80
					end
				end
				if intUtf16 > 0xFFFF then							-- U+10000 to U+10FFFF Supplementary Planes -- V2.6
					tblByte = {}
					intUtf16 = intUtf16 - 0x10000
					local intLow10 = 0xDC00 + ( intUtf16 % 0x400 )				-- Low 16-bit Surrogate
					local intTop10 = 0xD800 + math.floor( intUtf16 / 0x400 )	-- High 16-bit Surrogate
					local intChar1 = intTop10 % 0x100
					local intChar2 = math.floor( intTop10 / 0x100 )
					local intChar3 = intLow10 % 0x100
					local intChar4 = math.floor( intLow10 / 0x100 )
					return string.char(intChar1,intChar2,intChar3,intChar4)	-- Surrogate 16-bit Pair
				end
				if intUtf16 < 0xD800								-- U+0080 to U+FFFF (except U+D800 to U+DFFF) -- V2.6
				or intUtf16 > 0xDFFF then							-- Basic Multilingual Plane
					tblByte = {}
					local intChar1 = intUtf16 % 0x100
					local intChar2 = math.floor( intUtf16 / 0x100 )
					return string.char(intChar1,intChar2)		-- BPL 16-bit
				end
				local strUtf8 = ""									-- U+D800 to U+DFFF Reserved Code Points -- V2.6
				for intIndex, intByte in ipairs (tblByte) do
					strUtf8 = strUtf8..string.format("%.2X ",intByte)
				end
				local strUtf16 = string.format("%.4X ",intUtf16)
				fhMessageBox("\n UTF-16 Reserved Code Point U+D800 to U+DFFF \n UTF-16 = "..strUtf16.."  UTF-8 = "..strUtf8.."\n Character will be replaced by a question mark. \n","MB_OK","MB_ICONEXCLAMATION")
				tblByte = {}
				return "?\0"
			end
			return ""
		end -- local function strUtf8

		local intUtf8 = string.byte(strChar)
		if intUtf8 < 0x80 then										-- U+0000 to U+007F (ASCII)
			return strUtf8()..strChar.."\0"						-- Previous UTF-8 multibytes + current ASCII char
		end
		if intUtf8 >= 0xC0 then									-- Next UTF-8 multibyte start
			local strUtf16 = strUtf8()
			table.insert(tblByte,intUtf8)
			return strUtf16											-- Previous UTF-8 multibytes
		end
		table.insert(tblByte,intUtf8)
		return ""
	end -- function StrUtf8toUtf16

	-- Encode UTF-8 bytes into UTF-16 words --
	function fh.StrUTF8_UTF16(strText)
		tblByte = {}													-- (0xFF) flushes last UTF-8 character
		return ( ((strText or "")..string.char(0xFF)):gsub("(.)",fh.StrUtf8toUtf16) )	-- V3.4
	end -- function StrUTF8_UTF16

	-- Encode CP1252/ANSI or UTF-8 characters into UTF-16 words --
	function fh.StrEncode_UTF16(strText)
		if stringx.encoding() == "ANSI" then
			strText = fh.StrANSI_UTF8(strText)
		end
		return fh.StrUTF8_UTF16(strText)
	end -- function StrEncode_UTF16

	local intTop10 = 0

	-- Convert a UTF-16 word or pair to UTF-8 bytes --
	function fh.StrUtf16toUtf8(strChar1,strChar2)
		local intUtf16 = string.byte(strChar2) * 0x100 + string.byte(strChar1)
		if intUtf16 < 0x80 then									-- U+0000 to U+007F (ASCII) 
			return string.char(intUtf16)
		end
		if intUtf16 < 0x800 then									-- U+0080 to U+07FF
			local intByte1 = intUtf16 % 0x40
			intUtf16 = math.floor( intUtf16 / 0x40 )
			local intByte2 = intUtf16
			return string.char( intByte2 + 0xC0, intByte1 + 0x80 )
		end
		if intUtf16 < 0xD800										-- U+0800 to U+FFFF
		or intUtf16 > 0xDFFF then
			local intByte1 = intUtf16 % 0x40
			intUtf16 = math.floor( intUtf16 / 0x40 )
			local intByte2 = intUtf16 % 0x40
			intUtf16 = math.floor( intUtf16 / 0x40 )
			local intByte3 = intUtf16
			return string.char( intByte3 + 0xE0, intByte2 + 0x80, intByte1 + 0x80 )
		end
		if intUtf16 < 0xDC00 then									-- U+10000 to U+10FFFF High 16-bit Surrogate Supplementary Planes -- V2.6
			intTop10 = ( intUtf16 - 0xD800 ) * 0x400 + 0x10000
			return ""
		end
		intUtf16 = intUtf16 - 0xDC00 + intTop10				-- U+10000 to U+10FFFF Low 16-bit Surrogate Supplementary Planes -- V2.6
		local intByte1 = intUtf16 % 0x40
		intUtf16 = math.floor( intUtf16 / 0x40 )
		local intByte2 = intUtf16 % 0x40
		intUtf16 = math.floor( intUtf16 / 0x40 )
		local intByte3 = intUtf16 % 0x40
		intUtf16 = math.floor( intUtf16 / 0x40 )
		local intByte4 = intUtf16
		return string.char( intByte4 + 0xF0, intByte3 + 0x80, intByte2 + 0x80, intByte1 + 0x80 )
	end -- function StrUtf16toUtf8

	-- Encode UTF-16 words into UTF-8 bytes --
	function fh.StrUTF16_UTF8(strText)
		return ( (strText or ""):gsub("(.)(.)",fh.StrUtf16toUtf8) )	-- V3.4
	end -- function StrUTF16_UTF8

	-- Encode UTF-16 words into ANSI characters --
	function fh.StrUTF16_ANSI(strText)
		return fh.StrUTF8_ANSI(fh.StrUTF16_UTF8(strText))
	end -- function StrUTF16_ANSI

	-- Read UTF-16/UTF-8/ANSI file converted to chosen encoding via line iterator --
	local strUtf16 = "^.%z"
	if fhVersion > 6 then											-- Cater for Lua 5.1 %z or Lua 5.3 \0
			strUtf16 = "^.\0"
	end

	function fh.FileLines(strFileName,strEncoding)			-- Derived from http://lua-users.org/wiki/EnhancedFileLines
		local bomUtf16= "^"..string.char(0xFF,0xFE)			-- "ÿþ"
		local bomUtf8 = "^"..string.char(0xEF,0xBB,0xBF)	-- ""
		local fncConv = tostring									-- Function to convert input to current encoding
		local intHead = 1											-- Index to start of current text line
		local intLump = 1024
		local fHandle = general.OpenFile(strFileName,"rb")
		local strText = fHandle:read(1024) or ""				-- Read first lump from file and cater for empty file
		local intBOM = 0
		strEncoding = strEncoding or string.encoding()
		if strText:match(bomUtf16)
		or strText:match(strUtf16) then
			strText,intBOM = strText:gsub(bomUtf16,"") 		-- Strip UTF-16 BOM
			if strEncoding == "ANSI" then						-- Define UTF-16 conversion to current encoding
				fncConv = fh.StrUTF16_ANSI
			else
				fncConv = fh.StrUTF16_UTF8
			end
		elseif strText:match(bomUtf8) then
			strText,intBOM = strText:gsub(bomUtf8,"")			-- Strip UTF-8 BOM
			if strEncoding == "ANSI" then 						-- Define UTF-8 conversion to current encoding
				fncConv = fh.StrUTF8_ANSI
			end
		else
			if strEncoding == "UTF-8" and #strText > 0 then	-- Define ANSI conversion to current encoding and cater for empty file
				fncConv = fh.StrANSI_UTF8
			end
		end
		strText = fncConv(strText)								-- Convert first lump of text

		return function()											-- Iterator function
			local intTail,strTail									-- Index to end of current text line, and terminating characters
			while true do
				intTail, strTail = strText:match("()([\r\n].)",intHead)
				if intTail or not fHandle then
					if intHead > 1 then intLump = 0 end
					break												-- End of line or end of file
				elseif fHandle then
					local strLump = fHandle:read(1024)			-- Read next lump from file
					if strLump then									-- Strip old text and add converted lump
						strText = strText:sub(intHead)..fncConv(strLump)
						intHead = 1
						intLump = 1024
					else
						assert(fHandle:close())					-- End of file
						fHandle = nil
					end
				end
			end
			if not intTail then
				intTail = #strText									-- Last fragment of file
			elseif strTail == "\r\n" then
				intTail = intTail + 1								-- Adjust tail for both \r & \n
			end
			local strLine = strText:sub(intHead,intTail)		-- Extract line from text
			intHead = intTail + 1
			if #strLine > 0 then									-- Return pruned line, tail chars, lump bytes read
				local strBody, strTail = strLine:match("^(.-)([\r\n]+)$")
				return strBody, strTail, intLump
			end    
		end
	end -- function FileLines

	-- Set "[€-ÿ]" ASCII encodings same as Unidecode below
	local tblASCII = { }
	tblASCII["€"] = "=E"
	tblASCII["\129"]="" -- Undefined
	tblASCII["‚"] = ","
	tblASCII["ƒ"] = "f"
	tblASCII["„"] = ",,"
	tblASCII["…"] = "..."
	tblASCII["†"] = "|+"
	tblASCII["‡"] = "|++"
	tblASCII["ˆ"] = "^"
	tblASCII["‰"] = "%0"
	tblASCII["Š"] = "S"
	tblASCII["‹"] = "<"
	tblASCII["Œ"] = "OE"
	tblASCII["\141"]="" -- Undefined
	tblASCII["Ž"] = "Z"
	tblASCII["\143"]="" -- Undefined
	tblASCII["\144"]="" -- Undefined
	tblASCII["‘"] = "'"
	tblASCII["’"] = "'"
	tblASCII["“"] = "\""
	tblASCII["”"] = "\""
	tblASCII["•"] = "*"
	tblASCII["–"] = "-"
	tblASCII["—"] = "--"
	tblASCII["\152"]="~" -- Small Tilde
	tblASCII["™"] = "TM"
	tblASCII["š"] = "s"
	tblASCII["›"] = ">"
	tblASCII["œ"] = "oe"
	tblASCII["\157"]="" -- Undefined
	tblASCII["ž"] = "z"
	tblASCII["Ÿ"] = "Y"
	tblASCII["\160"]=" " -- "&nbsp;" No Break Space
	tblASCII["¡"] = "!"  -- "&iexcl;"
	tblASCII["¢"] = "=c" -- "&cent;"
	tblASCII["£"] = "=L" -- "&pound;"
	tblASCII["¤"] = "=$" -- "&curren;"
	tblASCII["¥"] = "=Y" -- "&yen;"
	tblASCII["¦"] = "|"
	tblASCII["§"] = "=SS"
	tblASCII["¨"] = "\""
	tblASCII["©"] = "(C)"
	tblASCII["ª"] = "a"
	tblASCII["«"] = "<<"
	tblASCII["¬"] = "-"
	tblASCII["­"] = "-"  -- "&shy;" Soft Hyphen
	tblASCII["®"] = "(R)"
	tblASCII["¯"] = "-"
	tblASCII["°"] = "=o"
	tblASCII["±"] = "+-"
	tblASCII["²"] = "2"
	tblASCII["³"] = "3"
	tblASCII["´"] = "'"
	tblASCII["µ"] = "=u"
	tblASCII["¶"] = "=p"
	tblASCII["·"] = "*"
	tblASCII["¸"] = ","
	tblASCII["¹"] = "1"
	tblASCII["º"] = "o"
	tblASCII["»"] = ">>"
	tblASCII["¼"] = "1/4"
	tblASCII["½"] = "1/2"
	tblASCII["¾"] = "3/4"
	tblASCII["¿"] = "?"
	tblASCII["À"] = "A"
	tblASCII["Á"] = "A"
	tblASCII["Â"] = "A"
	tblASCII["Ã"] = "A"
	tblASCII["Ä"] = "A"
	tblASCII["Å"] = "A"
	tblASCII["Æ"] = "AE"
	tblASCII["Ç"] = "C"
	tblASCII["È"] = "E"
	tblASCII["É"] = "E"
	tblASCII["Ê"] = "E"
	tblASCII["Ë"] = "E"
	tblASCII["Ì"] = "I"
	tblASCII["Í"] = "I"
	tblASCII["Î"] = "I"
	tblASCII["Ï"] = "I"
	tblASCII["Ð"] = "D"
	tblASCII["Ñ"] = "N"
	tblASCII["Ò"] = "O"
	tblASCII["Ó"] = "O"
	tblASCII["Ô"] = "O"
	tblASCII["Õ"] = "O"
	tblASCII["Ö"] = "O"
	tblASCII["×"] = "*"
	tblASCII["Ø"] = "O"
	tblASCII["Ù"] = "U"
	tblASCII["Ú"] = "U"
	tblASCII["Û"] = "U"
	tblASCII["Ü"] = "U"
	tblASCII["Ý"] = "Y"
	tblASCII["Þ"] = "TH"
	tblASCII["ß"] = "ss"
	tblASCII["à"] = "a"
	tblASCII["á"] = "a"
	tblASCII["â"] = "a"
	tblASCII["ã"] = "a"
	tblASCII["ä"] = "a"
	tblASCII["å"] = "a"
	tblASCII["æ"] = "ae"
	tblASCII["ç"] = "c"
	tblASCII["è"] = "e"
	tblASCII["é"] = "e"
	tblASCII["ê"] = "e"
	tblASCII["ë"] = "e"
	tblASCII["ì"] = "i"
	tblASCII["í"] = "i"
	tblASCII["î"] = "i"
	tblASCII["ï"] = "i"
	tblASCII["ð"] = "d"
	tblASCII["ñ"] = "n"
	tblASCII["ò"] = "o"
	tblASCII["ó"] = "o"
	tblASCII["ô"] = "o"
	tblASCII["õ"] = "o"
	tblASCII["ö"] = "o"
	tblASCII["÷"] = "/"
	tblASCII["ø"] = "o"
	tblASCII["ù"] = "u"
	tblASCII["ú"] = "u"
	tblASCII["û"] = "u"
	tblASCII["ü"] = "u"
	tblASCII["ý"] = "y"
	tblASCII["þ"] = "th"
	tblASCII["ÿ"] = "y"

	-- Encode CP1252/ANSI characters into ASCII codes [\000-\127] --
	function fh.StrANSI_ASCII(strText)
		return strEncode(strText,"[€-ÿ]",tblASCII)
	end -- function StrANSI_ASCII

	--[=[
		Unidecode converts each codepoint into a few ASCII characters.
		Lookup table indexed by codepoint [0x0000]-[0xFFFF] gives an ASCII string.
		i.e. strASCII = Unidecode[intByte2][intByte1] or "=?" allowing for partially populated table.
		See http://search.cpan.org/dist/Text-Unidecode/ and follow Browse to:
		See http://cpansearch.perl.org/src/SBURKE/Text-Unidecode-1.22/lib/Text/Unidecode/
		where each x??.pm gives 256 ASCII conversions.
		Start with the first few European accented characters, and add the others later.
	--]=]

	local Unidecode = { }

	function fh.StrUnidecode(strChar1,strChar2)				-- Decode UTF-16 byte pair into ASCII characters
		return Unidecode[string.byte(strChar2)][string.byte(strChar1)] or "=?"
	end  -- function StrUnidecode

	-- Encode UTF-8 characters into ASCII codes [\000-\126] --
	function fh.StrUTF8_ASCII(strText)
		strText = fh.StrUTF8_UTF16(strText)						-- Convert to UTF-16 Unicode and then to ASCII
		return ( strText:gsub("(.)(.)",fh.StrUnidecode) )
	end -- function StrUTF8_ASCII

	-- Encode CP1252/ANSI or UTF-8 into ASCII codes [\000-\126] --
	function fh.StrEncode_ASCII(strText)
		if stringx.encoding() == "ANSI" then
			return fh.StrANSI_ASCII(strText)
		else
			return fh.StrUTF8_ASCII(strText)
		end
	end -- function StrEncode_ASCII

	-- Set markup language break tag --
	function fh.SetBreakTag(br_New)
		if not (br_New or ""):match(br_Lua) then				-- Ensure new break tag is "<br>" or "<br >" or "<br/>" or "<br />"
			br_New = "<br />"
		end
		br_Tag = br_New
	end -- function SetBreakTag

	for intByte = 0x00, 0xFF do Unidecode[intByte] = { } end

	Unidecode[0x00] =
	{[0]="\00";"\01";"\02";"\03";"\04";"\05";"\06";"\a";"\b";"\t";"\n";"\v";"\f";"\r";"\14";"\15";"\16";"\17";"\18";"\19";"\20";"\21";"\22";"\23";"\24";"\25";"\26";"\27";"\28";"\29";"\30";"\31";
		" ";"!";'"';"#";"$";"%";"&";"'";"(";")";"*";"+";",";"-";".";"/";"0";"1";"2";"3";"4";"5";"6";"7";"8";"9";":";";";"<";"=";">";"?";							-- 0x20 to 0x3F
		"@";"A";"B";"C";"D";"E";"F";"G";"H";"I";"J";"K";"L";"M";"N";"O";"P";"Q";"R";"S";"T";"U";"V";"W";"X";"Y";"Z";"[";"\\";"]";"^";"_";							-- 0x40 to 0x5F
		"`";"a";"b";"c";"d";"e";"f";"g";"h";"i";"j";"k";"l";"m";"n";"o";"p";"q";"r";"s";"t";"u";"v";"w";"x";"y";"z";"{";"|";"}";"~";"\127";							-- 0x60 to 0x7F
		""; ""; ""; ""; ""; ""; ""; ""; ""; ""; ""; ""; ""; ""; ""; ""; ""; ""; ""; ""; ""; ""; ""; ""; ""; ""; ""; ""; ""; ""; ""; "";								-- 0x80 to 0x9F
		" ";"!";"=c";"=L";"=$";"=Y";"|";"=SS";'"';"(C)";"a";"<<";"-";"-";"(R)";"-";"=o";"+-";"2";"3";"'";"=u";"=P";"*";",";"1";"o";">>";"1/4";"1/2";"3/4";"?";	-- 0xA0 to 0xBF
		"A";"A";"A";"A";"A";"A";"AE";"C";"E";"E";"E";"E";"I";"I";"I";"I";"D";"N";"O";"O";"O";"O";"O";"*";"O";"U";"U";"U";"U";"Y";"TH";"ss"; 						-- 0xC0 to 0xDF
		"a";"a";"a";"a";"a";"a";"ae";"c";"e";"e";"e";"e";"i";"i";"i";"i";"d";"n";"o";"o";"o";"o";"o";"/";"o";"u";"u";"u";"u";"y";"th";"y";							-- 0xE0 to 0xFF
	}
	Unidecode[0x01] =
	{[0]="A";"a";"A";"a";"A";"a";"C";"c";"C";"c";"C";"c";"C";"c";"D";"d";"D";"d";"E";"e";"E";"e";"E";"e";"E";"e";"E";"e";"G";"g";"G";"g";							-- 0x00 to 0x1F
		"G";"g";"G";"g";"H";"h";"H";"h";"I";"i";"I";"i";"I";"i";"I";"i";"I";"i";"IJ";"ij";"J";"j";"K";"k";"k";"L";"l";"L";"l";"L";"l";"L";							-- 0x20 to 0x3F
		"l";"L";"l";"N";"n";"N";"n";"N";"n";"'n";"ng";"NG";"O";"o";"O";"o";"O";"o";"OE";"oe";"R";"r";"R";"r";"R";"r";"S";"s";"S";"s";"S";"s";						-- 0x40 to 0x5F
		"S";"s";"T";"t";"T";"t";"T";"t";"U";"u";"U";"u";"U";"u";"U";"u";"U";"u";"U";"u";"W";"w";"Y";"y";"Y";"Z";"z";"Z";"z";"Z";"z";"s";							-- 0x60 to 0x7F
		"b";"B";"B";"b";"6";"6";"O";"C";"c";"D";"D";"D";"d";"d";"3";"@";"E";"F";"f";"G";"G";"hv";"I";"I";"K";"k";"l";"l";"W";"N";"n";"O";							-- 0x80 to 0x9F
		"O";"o";"OI";"oi";"P";"p";"YR";"2";"2";"SH";"sh";"t";"T";"t";"T";"U";"u";"Y";"V";"Y";"y";"Z";"z";"ZH";"ZH";"zh";"zh";"2";"5";"5";"ts";"w";				-- 0xA0 to 0xBF
		"|";"||";"|=";"!";"DZ";"Dz";"dz";"LJ";"Lj";"lj";"NJ";"Nj";"nj";"A";"a";"I";"i";"O";"o";"U";"u";"U";"u";"U";"u";"U";"u";"U";"u";"@";"A";"a";				-- 0xC0 to 0xDF
		"A";"a";"AE";"ae";"G";"g";"G";"g";"K";"k";"O";"o";"O";"o";"ZH";"zh";"j";"DZ";"Dz";"dz";"G";"g";"HV";"W";"N";"n";"A";"a";"AE";"ae";"O";"o";				-- 0xE0 to 0xFF
	}
	Unidecode[0x02] =
	{[0]="A";"a";"A";"a";"E";"e";"E";"e";"I";"i";"I";"i";"O";"o";"O";"o";"R";"r";"R";"r";"U";"u";"U";"u";"S";"s";"T";"t";"Y";"y";"H";"h";							-- 0x00 to 0x1F
		"N";"d";"OU";"ou";"Z";"z";"A";"a";"E";"e";"O";"o";"O";"o";"O";"o";"O";"o";"Y";"y";"l";"n";"t";"j";"db";"qp";"A";"C";"c";"L";"T";"s";						-- 0x20 to 0x3F
		"z";"[?]";"[?]";"B";"U";"^";"E";"e";"J";"j";"q";"q";"R";"r";"Y";"y";"a";"a";"a";"b";"o";"c";"d";"d";"e";"@";"@";"e";"e";"e";"e";"j";						-- 0x40 to 0x5F
		"g";"g";"g";"g";"u";"Y";"h";"h";"i";"i";"I";"l";"l";"l";"lZ";"W";"W";"m";"n";"n";"n";"o";"OE";"O";"F";"r";"r";"r";"r";"r";"r";"r";							-- 0x60 to 0x7F
		"R";"R";"s";"S";"j";"S";"S";"t";"t";"u";"U";"v";"^";"w";"y";"Y";"z";"z";"Z";"Z";"?";"?";"?";"C";"@";"B";"E";"G";"H";"j";"k";"L";							-- 0x80 to 0x9F
		"q";"?";"?";"dz";"dZ";"dz";"ts";"tS";"tC";"fN";"ls";"lz";"WW";"]]";"h";"h";"h";"h";"j";"r";"r";"r";"r";"w";"y";"'";'"';"`";"'";"`";"`";"'";				-- 0xA0 to 0xBF
		"?";"?";"<";">";"^";"V";"^";"V";"'";"-";"/";"\\";",";"_";"\\";"/";":";".";"`";"'";"^";"V";"+";"-";"V";".";"@";",";"~";'"';"R";"X";							-- 0xC0 to 0xDF
		"G";"l";"s";"x";"?";"";"";"";"";"";"";"";"V";"=";'"';"[?]";"[?]";"[?]";"[?]";"[?]";"[?]";"[?]";"[?]";"[?]";"[?]";"[?]";"[?]";"[?]";"[?]";"[?]";"[?]";	-- 0xE0 to 0xFF
	}
	Unidecode[0x03] =
	{
	}
	Unidecode[0x04] =
	{
	}
	Unidecode[0x20] =
	{[0]=" ";" ";" ";" ";" ";" ";" ";" ";" ";" ";" ";" ";"";"";"";"";"-";"-";"-";"-";"--";"--";"||";"_";"'";"'";",";"'";'"';'"';",,";'"';																-- 0x00 to 0x1F
		"|+";"|++";"*";"*>";".";"..";"...";".";"\n";"\n\n";"";"";"";"";"";" ";"%0";"%00";"'";"''";"'''";"`";"``";"```";"^";"<";">";"*";"!!";"!?";"-";"_";											-- 0x20 to 0x3F
		"-";"^";"***";"--";"/";"-[";"]-";"[?]";"?!";"!?";"7";"PP";"(]";"[)";"[?]";"[?]";"[?]";"[?]";"[?]";"[?]";"[?]";"[?]";"[?]";"[?]";"[?]";"[?]";"[?]";"[?]";"[?]";"[?]";"[?]";"[?]";	-- 0x40 to 0x5F
		"[?]";"[?]";"[?]";"[?]";"[?]";"[?]";"[?]";"[?]";"[?]";"[?]";"";"";"";"";"";"";"0";"";"";"";"4";"5";"6";"7";"8";"9";"+";"-";"=";"(";")";"n";													-- 0x60 to 0x7F
		"0";"1";"2";"3";"4";"5";"6";"7";"8";"9";"+";"-";"=";"(";")";"[?]";"[?]";"[?]";"[?]";"[?]";"[?]";"[?]";"[?]";"[?]";"[?]";"[?]";"[?]";"[?]";"[?]";"[?]";"[?]";"[?]";						-- 0x80 to 0x9F
		"ECU";"CL";"Cr";"FF";"L";"mil";"N";"Pts";"Rs";"W";"NS";"D";"=E";"K";"T";"Dr";"[?]";"[?]";"[?]";"[?]";"[?]";"[?]";"[?]";"[?]";"[?]";"[?]";"[?]";"[?]";"[?]";"[?]";"[?]";"[?]";		-- 0xA0 to 0xBF
		"[?]";"[?]";"[?]";"[?]";"[?]";"[?]";"[?]";"[?]";"[?]";"[?]";"[?]";"[?]";"[?]";"[?]";"[?]";"[?]";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";											-- 0xC0 to 0xDF
		"";"";"";"";"[?]";"[?]";"[?]";"[?]";"[?]";"[?]";"[?]";"[?]";"[?]";"[?]";"[?]";"[?]";"[?]";"[?]";"[?]";"[?]";"[?]";"[?]";"[?]";"[?]";"[?]";"[?]";"[?]";"[?]";"[?]";"[?]";"[?]";		-- 0xE0 to 0xFF
	}
	Unidecode[0x21] =
	{[34]="TM";
	}

	return fh

end -- local function encoder_v3

local encoder = encoder_v3()										-- To access FH encoder chars module

--[[
@Module:			+fh+progbar_v3
@Author:			Mike Tate
@Version:			3.1
@LastUpdated:		23 Jan 2026
@Description:		Progress Bar library module.
@V3.1:				Use NATIVEPARENT amd CENTERPARENT.
@V3.0:				Function Prototype Closure version.
@V1.0:				Initial version.
]]

local function progbar_v3()

	local fh = {}														-- Local environment table

	require "iuplua"													-- To access GUI window builder

	iup.SetGlobal("CUSTOMQUITMESSAGE","YES")					-- Needed for IUP 3.28

	local tblBars = {}												-- Table for optional external attributes
	local strBack = "255 255 255"									-- Background colour default is white
	local strBody = "0 0 0"											-- Body text colour default is black
	local strFont = nil												-- Font dialogue default is current font
	local strStop = "255 0 0"										-- Stop button colour default is red
	local intPosX = iup.CENTERPARENT								-- Show window default position is central	-- V3.1
	local intPosY = iup.CENTERPARENT
	local intMax, intVal, intPercent, intStart, intDelta, intScale, strClock, isBarStop
	local lblText, barGauge, lblDelta, btnStop, dlgGauge

	local function doFocus()										-- Bring the Progress Bar window into Focus
		dlgGauge.BringFront="YES"									-- If used too often, inhibits other windows scroll bars, etc
	end -- local function doFocus

	local function doUpdate()										-- Update the Progress Gauge and the Delta % with clock
		barGauge.Value = intVal
		lblDelta.Title = string.format("%4d %%      %s ",math.floor(intPercent),strClock)
	end -- local function doUpdate

	local function doReset()										-- Reset all dialogue variables and Update display
		intVal		= 0													-- Current value of Progress Bar
		intPercent= 0.01												-- Percentage of progress
		intStart	= os.time()										-- Start time of progress
		intDelta	= 0													-- Delta time of progress
		intScale	= math.ceil( intMax / 1000 )					-- Scale of percentage per second of progress (initial guess is corrected in Step function)
		strClock	= "00 : 00 : 00"									-- Clock delta time display
		isBarStop	= false											-- Stop button pressed signal
		doUpdate()
		doFocus()
	end -- local function doReset

	function fh.Start(strTitle,intMaximum)						-- Create & start Progress Bar window
		if not dlgGauge then
			strTitle	= strTitle or ""								-- Dialogue and button title
			intMax		= intMaximum or 100							-- Maximun range of Progress Bar, default is 100
			local strSize = tostring( math.max( 100, string.len(" Stop "..strTitle) * 8 ) ).."x30"			-- Adjust Stop button size to Title
			lblText	= iup.label	{ Title=" "; Expand="YES"; Alignment="ACENTER"; Tip="Progress Message"; }
			barGauge	= iup.progressbar { RasterSize="400x30"; Value=0; Max=intMax; Tip="Progress Bar"; }
			lblDelta	= iup.label	{ Title=" "; Expand="YES"; Alignment="ACENTER"; Tip="Percentage and Elapsed Time"; }
			btnStop	= iup.button	{ Title=" Stop "..strTitle; RasterSize=strSize; FgColor=strStop; Tip="Stop Progress Button"; action=function() isBarStop = true end; }	-- Signal Stop button pressed	return iup.CLOSE -- Often caused main GUI to close !!!
			dlgGauge	= iup.dialog	{ Title=strTitle.." Progress "; Font=strFont; FgColor=strBody; Background=strBack; DialogFrame="YES";	-- Remove Windows minimize/maximize menu
								iup.vbox{ Alignment="ACENTER"; Gap="10"; Margin="10x10";
									lblText;
									barGauge;
									lblDelta;
									btnStop;
								};
								move_cb	= function(self,x,y) tblBars.X = x tblBars.Y = y end;
								close_cb	= btnStop.action;		-- Windows Close button = Stop button
							}
			if type(tblBars.GUI) == "table"
			and type(tblBars.GUI.ShowDialogue) == "function" then
				dlgGauge.move_cb = nil								-- Use GUI library to show & move window
				tblBars.GUI.ShowDialogue("Bars",dlgGauge,btnStop,"showxy")
			else
				if fhGetAppVersion() > 6 then 					-- Window centres on FH parent	-- V3.1
					iup.SetAttribute(dlgGauge,"NATIVEPARENT",fhGetContextInfo("CI_PARENT_HWND"))
				end
				dlgGauge:showxy(intPosX,intPosY)					-- Show the Progress Bar window
			end
			doReset()													-- Reset the Progress Bar display
		end
	end -- function Start

	function fh.Message(strText)									-- Show the Progress Bar message
		if dlgGauge then lblText.Title = strText end
	end -- function Message

	function fh.Step(intStep)										-- Step the Progress Bar forward
		if dlgGauge then
			intVal = intVal + ( intStep or 1 )					-- Default step is 1
			local intNew = math.ceil( intVal / intMax * 100 * intScale ) / intScale
			if intPercent ~= intNew then							-- Update progress once per percent or per second, whichever is smaller
				intPercent = math.max( 0.1, intNew )				-- Ensure percentage is greater than zero
				if intVal > intMax then intVal = intMax intPercent = 100 end		-- Ensure values do not exceed maximum
				intNew = os.difftime(os.time(),intStart)
				if intDelta < intNew then							-- Update clock of elapsed time
					intDelta = intNew
					intScale = math.ceil( intDelta / intPercent )	-- Scale of seconds per percentage step
					local intHour = math.floor( intDelta / 3600 )
					local intMins = math.floor( intDelta / 60 - intHour * 60 )
					local intSecs = intDelta - intMins * 60 - intHour * 3600
					strClock = string.format("%02d : %02d : %02d",intHour,intMins,intSecs)
				end
				doUpdate()											-- Update the Progress Bar display
			end
			iup.LoopStep()
		end
	end -- function Step

	function fh.Focus()												-- Bring the Progress Bar window to front
		if dlgGauge then doFocus() end
	end -- function Focus

	function fh.Reset()												-- Reset the Progress Bar display
		if dlgGauge then doReset() end
	end -- function Reset

	function fh.Stop()												-- Check if Stop button pressed
		iup.LoopStep()
		return isBarStop
	end -- function Stop

	function fh.Close()												-- Close the Progress Bar window
		isBarStop = false
		if dlgGauge then dlgGauge:destroy() dlgGauge = nil end
	end -- function Close

	function fh.Setup(tblSetup)									-- Setup optional table of external attributes
		if tblSetup then
			tblBars = tblSetup
			strBack = tblBars.Back or strBack						-- Background colour
			strBody = tblBars.Body or strBody						-- Body text colour
			strFont = tblBars.Font or strFont						-- Font dialogue
			strStop = tblBars.Stop or strStop						-- Stop button colour
			intPosX = tblBars.X or intPosX						-- Window position
			intPosY = tblBars.Y or intPosY
		end
	end -- function Setup

	return fh

end -- local function progbar_v3

local progbar = progbar_v3()										-- To access FH progress bars module

--[[
@Module:			+fh+iup_gui_v3
@Author:			Mike Tate
@Version:			4.6
@LastUpdated:		18 Feb 2026
@Description:		Graphical User Interface Library Module
@V4.6:				Improve handling of centred window RasterSize in fh.ShowDialogue(...);
@V4.5:				Adjust CheckVersionInStore() for dedicated button use;
@V4.4:				Introduce use of NATIVEPARENT and CENTERPARENT to centre on parent window by default; Ensure not off screen; Monitors with -ve X;
@V4.3:				Added memo options to CheckVersionInStore;
@V4.2:				Skip if standalone GEDCOM in fh.SaveSettings() and getDataFiles();
@V4.1:				CheckVersionInStore() save & retrieve latest version in file; Remove old wiki Help features;
@V4.0:				Cater for full UTF-8 filenames;
@V3.9:				ShowDialogue() popup closure fhSleep() added; CheckVersionInStore() at monthly intervals;
@V3.8:				Function Prototype Closure version.
@V3.7:				AssignAttributes(tblControls) now allows any string attribute to invoke a function.
@V3.6:				anyMemoDialogue() sets TopMost attribute.
@V3.5:				Replace IsNormalWindow(iupDialog) with SetWindowCoord(tblName) and update CheckWindowPosition(tblName) to prevent negative values freezing main dialog.
@V3.4:				Use general.MakeFolder() to ensure key folders exist, add Get/PutRegKey(), check Registry IE Shell Version in HelpDialogue(), better error handling in LoadSettings().
@V3.3:				LoadFolder() and SaveFolder() use global folder as default for local folder to improve synch across PC.
@V3.2:				Load & Save settings now use a single clipboard so Local PC settings are preserved across synchronised PC.
@V3.1:				IUP 3.11.2 iup.GetGlobal("VERSION") to top, HelpDialogue conditional ExpandChildren="YES/NO", RefreshDialogue uses NaturalSize, SetUtf8Mode(), Load/SaveFolder(), etc
@V3.0:				ShowDialogue "dialog" mode for Memo, new DestroyDialogue, NewHelpDialogue tblAttr for Font, AssignAttributes intSkip, CustomDialogue iup.CENTERPARENT+, IUP Workaround, BalloonToggle, Initialise test Plugin file exists.
@V2.0:				Support for Plugin Data scope, new FontDialogue, RefreshDialogue, AssignAttributes, httpRequest handler, keep "dialog" mode.
@V1.0:				Initial version.
]]

local function iup_gui_v3()

	local fh = {}																			-- Local environment table

	require "iuplua"																		-- To access GUI window builder
	require "iupluacontrols"															-- To access GUI window controls
	require "lfs"																			-- To access LUA filing system
	require "iupluaole"																	-- To access OLE subsystem
	require "luacom"																		-- To access COM subsystem

	iup.SetGlobal("CUSTOMQUITMESSAGE","YES")										-- Needed for IUP 3.28

	local iupVersion = iup.GetGlobal("VERSION")										-- Obtain IUP module version

	-- "iuplua" Omitted Constants Workaround --

	iup.TOP    = iup.LEFT
	iup.BOTTOM = iup.RIGHT
	iup.RED    = iup.RGB(1,0,0)
	iup.GREEN  = iup.RGB(0,1,0)
	iup.BLUE   = iup.RGB(0,0,1)
	iup.BLACK  = iup.RGB(0,0,0)
	iup.WHITE  = iup.RGB(1,1,1)
	iup.YELLOW = iup.RGB(1,1,0)

	-- Shared Interface Attributes & Functions --

	fh.Version	= " "																	-- Plugin Version
	fh.History	= fh.Version															-- Version History

	fh.Red			= "255 0 0"															-- Color attributes (must exclude leading zeros & spaces to allow value comparisons)
	fh.Maroon		= "128 0 0"
	fh.Amber		= "250 160 0"
	fh.Orange		= "255 165 0"
	fh.Yellow		= "255 255 0"
	fh.Olive		= "128 128 0"
	fh.Lime		= "0 255 0"
	fh.Green		= "0 128 0"
	fh.Cyan		= "0 255 255"
	fh.Teal		= "0 128 128"
	fh.Blue		= "0 0 255"
	fh.Navy		= "0 0 128"
	fh.Magenta	= "255 0 255"
	fh.Purple		= "128 0 128"
	fh.Black		= "0 0 0"
	fh.Gray		= "128 128 128"
	fh.Silver		= "192 192 192"
	fh.Smoke		= "240 240 240"
	fh.White		= "255 255 255"
	fh.Risk		= fh.Red																-- Risk colour for hazardous controls such as Close/Delete buttons
	fh.Warn		= fh.Magenta															-- Warn colour for caution controls and warnings
	fh.Safe		= fh.Green															-- Safe colour for active controls such as most buttons
	fh.Info		= fh.Black															-- Info colour for text controls such as labels/tabs
	fh.Head		= fh.Black															-- Head colour for headings
	fh.Body		= fh.Black															-- Body colour for body text
	fh.Back		= fh.White															-- Background colour for all windows

	fh.Gap			= "8"																	-- Layout attributes Gap was "10"
	fh.Border		= "8x8"																-- 	was BigMargin="10x10"
	fh.Margin		= "1x1"																--	was MinMargin
	fh.Balloon	= "NO"																	-- Tooltip balloon mode

	fh.FontSet	=	0																	-- Legacy GUI font set assigned by FontAssignment but used globally
	fh.FontHead	= ""
	fh.FontBody	= ""

	local GUI = { }																		-- Sub-table for GUI Dialogue attributes to allow any "Name"

	--[[
	GUI.Name			table of dialogue attributes, where Name is Font, Main, Memo, Bars, etc
	GUI.Name.CoordX	x co-ordinate	( Loaded & Saved by default )
	GUI.Name.CoordY	y co-ordinate	( Loaded & Saved by default )
	GUI.Name.Dialog	dialogue handle
	GUI.Name.Focus	focus button handle
	GUI.Name.Frame	dialogframe mode, "normal" = dialogframe="NO" else "YES", "showxy" = showxy(), "popup" or "keep" = popup(), default is "normal & showxy"
	GUI.Name.Height	height
	GUI.Name.Raster	rastersize		( Loaded & Saved by default )
	GUI.Name.Width	width
	GUI.Name.Back		ProgressBar background colour
	GUI.Name.Body		ProgressBar body text colour
	GUI.Name.Font		ProgressBar font style
	GUI.Name.Stop		ProgressBar Stop button colour
	GUI.Name.GUI		Module table usable by other modules e.g. progbar.Setup
	--]]

	-- tblScrn[1] = origin x, tblScrn[2] = origin y, tblScrn[3] = width, tblScrn[4] = height
	local tblScrn = stringx.splitnumbers(iup.GetGlobal("VIRTUALSCREEN"))		-- Used by CustomDialogue() and CheckWindowPosition() and ShowDialogue() below
	local intMinX = tblScrn[1]
	local intMinY = tblScrn[2]															-- V4.4
	local intMaxW = tblScrn[3]
	local intMaxH = tblScrn[4]

	function fh.BalloonToggle()														-- Toggle tooltips Balloon mode
		local tblToggle = { YES="NO"; NO="YES"; }
		fh.Balloon = tblToggle[fh.Balloon]
		fh.SaveSettings()
	end -- function BalloonToggle

	iup.SetGlobal("UTF8MODE","NO")
	iup.SetGlobal("UTF8MODE_FILE","NO") 												-- V4.0
	function fh.SetUtf8Mode()															-- Set IUP into UTF-8 mode
		if iupVersion == "3.5" or stringx.encoding() == "ANSI" then return false end
		iup.SetGlobal("UTF8MODE","YES")
		iup.SetGlobal("UTF8MODE_FILE","YES")											-- V4.0
		return true
	end -- function SetUtf8Mode

	local function tblOfNames(...)													-- Get table of dialogue Names including "Font","Main" by default	-- V4.4
		local arg = {...}
		local tblNames = {"Font";"Main";}
		for intName, strName in ipairs(arg) do
			if type(strName) == "string"
			and strName ~= "Font"
			and strName ~= "Main" then
				table.insert(tblNames,strName)
			end
		end
		return tblNames
	end -- local function tblOfNames

	local function tblNameFor(strName)												-- Get table of parameters for chosen dialogue Name
		strName = tostring(strName)
		if not GUI[strName] then														-- Need new table with default minimum & raster size, and X & Y co-ordinates
			GUI[strName] = { }
			local tblName = GUI[strName]
			tblName.Raster = "x"
			tblName.CoordX = iup.CENTERPARENT
			tblName.CoordY = iup.CENTERPARENT
		end
		return GUI[strName]
	end -- local function tblNameFor

	local function intDimension(intMin,intVal,intMax)								-- Return a number bounded by intMin and intMax
		if not intVal then return 0 end												-- Except if no value then return 0
		intVal = tonumber(intVal) or (intMin+intMax)/2
		return math.max(intMin,math.min(intVal,intMax))
	end -- local function intDimension

	function fh.CustomDialogue(strName,strRas,intX,intY)							-- GUI custom window raster size, and X & Y co-ordinates
		-- strRas  nil = old size, "x" or "0x0" = min size, "999x999" = new size
		-- intX/Y  nil = central, "99" = co-ordinate position
		local tblName = tblNameFor(strName)
		local tblSize = {}
		local intWide = 0
		local intHigh = 0
		strRas = strRas or tblName.Raster
		if strRas then																	-- Ensure raster size is between minimum and screen size
			tblSize = stringx.splitnumbers(strRas)
			intWide = intDimension(intWide,tblSize[1],intMaxW)
			intHigh = intDimension(intHigh,tblSize[2],intMaxH)
			strRas = tostring(intWide.."x"..intHigh)
		end
		if intX and intX < iup.CENTERPARENT then
			intX = intDimension(intMinX,intX,intMaxW-intWide)						-- Ensure X co-ordinate positions window on screen	-- V4.4
		end
		if intY and intY < iup.CENTERPARENT then
			intY = intDimension(intMinY,intY,intMaxH-intHigh)						-- Ensure Y co-ordinate positions window on screen	-- V4.4
		end
		tblName.Raster  = strRas or "x"
		tblName.CoordX  = tonumber(intX) or iup.CENTERPARENT						-- V4.4
		tblName.CoordY  = tonumber(intY) or iup.CENTERPARENT						-- V4.4
	end -- function CustomDialogue

	function fh.DefaultDialogue(...)													-- GUI default window minimum & raster size, and X & Y co-ordinates
		for intName, strName in ipairs(tblOfNames(...)) do
			fh.CustomDialogue(strName)
		end
	end -- function DefaultDialogue

	function fh.DialogueAttributes(strName)											-- Provide named Dialogue Attributes
		local tblName = tblNameFor(strName)											-- tblName.Dialog = dialog handle, so any other attributes could be retrieved
		local tblSize = stringx.splitnumbers(tblName.Raster or "x")				-- Split Raster Size into width=tblSize[1] and height=tblSize[2]
		tblName.Width = tblSize[1]
		tblName.Height= tblSize[2]
		tblName.Back = fh.Back															-- Following only needed for NewProgressBar
		tblName.Body = fh.Body
		tblName.Font = fh.FontBody
		tblName.Stop = fh.Risk
		tblName.GUI  = fh																-- Module table
		return tblName
	end -- function DialogueAttributes

	local strDefaultScope = "Project"													-- Default scope for Load/Save data is per Project/User/Machine as set by PluginDataScope()

	local tblClipProj = { }
	local tblClipUser = { }																-- Clipboards of sticky data for each Plugin Data scope -- V3.2
	local tblClipMach = { }

	local function doLoadData(strParam,strDefault,strScope)						-- Load sticky data for Plugin Data scope
		strScope = tostring(strScope or strDefaultScope):lower()
		local tblClipData = tblClipProj
		if     strScope:match("user") then tblClipData = tblClipUser
		elseif strScope:match("mach") then tblClipData = tblClipMach
		end
		return tblClipData[strParam] or strDefault
	end -- local function doLoadData

	function fh.LoadGlobal(strParam,strDefault,strScope)							-- Load Global Parameter for all PC
		return doLoadData(strParam,strDefault,strScope)
	end -- function LoadGlobal

	function fh.LoadLocal(strParam,strDefault,strScope) 							-- Load Local Parameter for this PC
		return doLoadData(fh.ComputerName.."-"..strParam,strDefault,strScope)
	end -- function LoadLocal

	local function doLoadFolder(strFolder)											-- Use relative paths to let Paths change -- V3.3
		strFolder = strFolder:gsub("^FhDataPath",function() return fh.FhDataPath end)	-- Full path to .fh_data folder
		strFolder = strFolder:gsub("^PublicPath",function() return fh.PublicPath end)	-- Full path to Public folder
		strFolder = strFolder:gsub("^FhProjPath",function() return fh.FhProjPath end)	-- Full path to project folder
		return strFolder
	end -- local function doLoadFolder

	function fh.LoadFolder(strParam,strDefault,strScope)							-- Load Folder Parameter for this PC -- V3.3
		local strFolder = doLoadFolder(fh.LoadLocal(strParam,"",strScope))
		if not general.FlgFolderExists(strFolder) then								-- If no local folder try global folder
			strFolder = doLoadFolder(fh.LoadGlobal(strParam,strDefault,strScope))
		end
		return strFolder
	end -- function LoadFolder

	function fh.LoadDialogue(...)														-- Load Dialogue Parameters for "Font","Main" by default
		for intName, strName in ipairs(tblOfNames(...)) do
			local tblName = tblNameFor(strName)
			tblName.Raster = tostring(fh.LoadLocal(strName.."R",tblName.Raster))
			tblName.CoordX = tonumber(fh.LoadLocal(strName.."X",tblName.CoordX))
			tblName.CoordY = tonumber(fh.LoadLocal(strName.."Y",tblName.CoordY))
			fh.CheckWindowPosition(tblName)
		end
	end -- function LoadDialogue

	function fh.LoadSettings(...)														-- Load Sticky Settings from File
		for strFileName, tblClipData in pairs ({ ProjectFile=tblClipProj; PerUserFile=tblClipUser; MachineFile=tblClipMach; }) do
			strFileName = fh[strFileName]
			if general.FlgFileExists(strFileName) then								-- Load Settings File in table lines with key & val fields
				local tblField = {}
				local strClip = general.StrLoadFromFile(strFileName)				-- V4.0
				for strLine in strClip:gmatch("[^\r\n]+") do						-- V4.0
					if #tblField == 0
					and strLine:match("^return {")									-- Unless entire Sticky Data table was saved
					and type(table.load) == "function" then
						local tblClip, strErr = table.load(strFileName)			-- Load Settings File table
						if strErr then error(strErr.."\n\nMay need to Delete the following Plugin Data .dat file:\n\n"..strFileName.."\n\nError detected.") end
						for i,j in pairs (tblClip) do
							tblClipData[i] = tblClip[i]
						end
						break
					end
					tblField = stringx.split(strLine,"=")
					if tblField[1] then tblClipData[tblField[1]] = tblField[2] end
				end
			else
				for i,j in pairs (tblClipData) do
					tblClipData[i] = nil												-- Restore defaults and clear any junk		-- V4.0
				end
			end
		end
		fh.Safe    = tostring(fh.LoadGlobal("SafeColor",fh.Safe))
		fh.Warn    = tostring(fh.LoadGlobal("WarnColor",fh.Warn))
		fh.Risk    = tostring(fh.LoadGlobal("RiskColor",fh.Risk))
		fh.Head    = tostring(fh.LoadGlobal("HeadColor",fh.Head))
		fh.Body    = tostring(fh.LoadGlobal("BodyColor",fh.Body))
		fh.FontHead= tostring(fh.LoadGlobal("FontHead" ,fh.FontHead))
		fh.FontBody= tostring(fh.LoadGlobal("FontBody" ,fh.FontBody))
		fh.History = tostring(fh.LoadGlobal("History"  ,fh.History))
		fh.Balloon = tostring(fh.LoadGlobal("Balloon"  ,fh.Balloon, "Machine"))
		fh.LoadDialogue(...)
	end -- function LoadSettings

	local function doSaveData(strParam,anyValue,strScope)							-- Save sticky data for Plugin Data scope
		strScope = tostring(strScope or strDefaultScope):lower()
		local tblClipData = tblClipProj
		if     strScope:match("user") then tblClipData = tblClipUser
		elseif strScope:match("mach") then tblClipData = tblClipMach
		end
		tblClipData[strParam] = anyValue
	end -- local function doSaveData

	function fh.SaveGlobal(strParam,anyValue,strScope)							-- Save Global Parameter for all PC
		doSaveData(strParam,anyValue,strScope)
	end -- function SaveGlobal

	function fh.SaveLocal(strParam,anyValue,strScope)								-- Save Local Parameter for this PC
		doSaveData(fh.ComputerName.."-"..strParam,anyValue,strScope)
	end -- function SaveLocal

	function fh.SaveFolder(strParam,strFolder,strScope)							-- Save Folder Parameter for this PC
		strFolder = stringx.replace(strFolder,fh.FhDataPath,"FhDataPath")		-- Full path to .fh_data folder
		strFolder = stringx.replace(strFolder,fh.PublicPath,"PublicPath")		-- Full path to Public folder
		strFolder = stringx.replace(strFolder,fh.FhProjPath,"FhProjPath")		-- Full path to project folder
		fh.SaveGlobal(strParam,strFolder,strScope)									-- V3.3
		fh.SaveLocal(strParam,strFolder,strScope)									-- Uses relative paths to let Paths change
	end -- function SaveFolder

	function fh.SaveDialogue(...)														-- Save Dialogue Parameters for "Font","Main" by default
		for intName, strName in ipairs(tblOfNames(...)) do
			local tblName = tblNameFor(strName)
			fh.SaveLocal(strName.."R",tblName.Raster)
			fh.SaveLocal(strName.."X",tblName.CoordX)
			fh.SaveLocal(strName.."Y",tblName.CoordY)
		end
	end -- function SaveDialogue

	function fh.SaveSettings(...)														-- Save Sticky Settings to File
		fh.SaveDialogue(...)
		fh.SaveGlobal("SafeColor",fh.Safe)
		fh.SaveGlobal("WarnColor",fh.Warn)
		fh.SaveGlobal("RiskColor",fh.Risk)
		fh.SaveGlobal("HeadColor",fh.Head)
		fh.SaveGlobal("BodyColor",fh.Body)
		fh.SaveGlobal("FontHead" ,fh.FontHead)
		fh.SaveGlobal("FontBody" ,fh.FontBody)
		fh.SaveGlobal("History"  ,fh.History)
		fh.SaveGlobal("Balloon"  ,fh.Balloon, "Machine")
		for strFileName, tblClipData in pairs ({ ProjectFile=tblClipProj; PerUserFile=tblClipUser; MachineFile=tblClipMach; }) do
			for i,j in pairs (tblClipData) do											-- Check if table has any entries
				strFileName = fh[strFileName]
				if #strFileName > 0 then												-- Skip for standalone GEDCOM -- V4.2
					if type(table.save) == "function" then							-- Save entire Settings File table per Project/User/Machine
						table.save(tblClipData,strFileName)
					else
						local tblClip = {}
						for strKey,strVal in pairs(tblClipData) do					-- Else save Settings File lines with key & val fields		-- V4.0
							table.insert(tblClip,strKey.."="..strVal.."\n")		-- V4.0
						end
						local strClip = table.concat(tblClip,"\n")					-- V4.0
						if not general.SaveStringToFile(strClip,strFileName) then
							error("\nSettings file not saved successfully.\n\nMay need to Delete the following Plugin Data .dat file:\n\n"..strFileName.."\n\nError detected.")
						end	
					end
				end
				break
			end
		end
	end -- function SaveSettings

	function fh.CheckWindowPosition(tblName)										-- Ensure dialogue window coordinates are on Screen
		local tblSize = stringx.splitnumbers(tblName.Raster or "600x400","x")	-- Get window dimensions from the previous use of plugin -- V4.4
		local intWinW = tblSize[1]
		local intWinH = tblSize[2]
		if tonumber(tblName.CoordX) == nil
		or tonumber(tblName.CoordY) == nil
		or tonumber(tblName.CoordX) < intMinX										-- V4.4 -- V3.5
		or tonumber(tblName.CoordY) < intMinY										-- V4.4 -- V3.5
		or tonumber(tblName.CoordX) + intWinW > intMaxW							-- V4.4
		or tonumber(tblName.CoordY) + intWinH > intMaxH then						-- V4.4
			tblName.CoordX = iup.CENTERPARENT											-- V4.4
			tblName.CoordY = iup.CENTERPARENT											-- V4.4
		end
	end -- function CheckWindowPosition

	function fh.SetWindowCoord(tblName)												-- Set the Window coordinates if not Maximised or Minimised -- V3.5
		-- tblPosn[1] = origin x, tblPosn[2] = origin y, tblPosn[3] = width, tblPosn[4] = height
		local tblPosn = stringx.splitnumbers(tblName.Dialog.ScreenPosition)
		local intPosX = tblPosn[1] or -1
		local intPosY = tblPosn[2] or -1
		if intPosX < 0 and intPosY < 0 then											-- If origin is negative (-8, -8 = Maximised, -3200, -3200 = Minimised)
			return false																	-- then is Maximised or Minimised
		end
		tblName.CoordX = intPosX														-- Otherwise set the Window coordinates
		tblName.CoordY = intPosY
		return true
	end -- function SetWindowCoord

	function fh.ShowDialogue(strName,iupDialog,btnFocus,strFrame)				-- Set standard frame attributes and display dialogue window
		local tblName = tblNameFor(strName)
		iupDialog = iupDialog or tblName.Dialog										-- Retrieve previous parameters if needed
		btnFocus  = btnFocus  or tblName.Focus
		strFrame  = strFrame  or tblName.Frame
		strFrame  = strFrame  or "show norm"											-- Default frame mode is dialog:showxy(X,Y) with DialogFrame="NO" ("normal" to vary size, otherwise fixed size)
		strFrame  = strFrame:lower()													-- Other modes are "show", "popup" & "keep" with DialogFrame="YES", or with "normal" for DialogFrame="NO" ("show" for active windows, "popup"/"keep" for modal windows)
		if strFrame:gsub("%s-%a-map%a*[%s%p]*","") == "" then						-- May be prefixed with "map" mode to just map dialogue initially, also may be suffixed with "dialog" to inhibit iup.MainLoop() to allow progress messages
			strFrame = "map show norm"													-- If only "map" mode then default to "map show norm"
		end
		if type(iupDialog) == "userdata" then
			tblName.Dialog = iupDialog
			tblName.Focus  = btnFocus													-- Preserve parameters
			tblName.Frame  = strFrame
			iupDialog.Background = fh.Back											-- Background colour
			iupDialog.Shrink = "YES"													-- Sometimes needed to shrink controls to raster size
			if type(btnFocus) == "userdata" then										-- Set button as focus for Esc and Enter keys
				iupDialog.StartFocus   = iupDialog.StartFocus   or btnFocus
				iupDialog.DefaultEsc   = iupDialog.DefaultEsc   or btnFocus
				iupDialog.DefaultEnter = iupDialog.DefaultEnter or btnFocus
			end
			if tblName.CoordX == iup.CENTERPARENT
			or tblName.CoordY == iup.CENTERPARENT then								-- When centred on parent refresh this window size	-- V4.4 -- V4.6
				fh.RefreshDialogue(strName)
			else
				iupDialog.MinSize = "x"													-- Minimum size (default "x" becomes nil)
				iupDialog.RasterSize = tblName.Raster or "x"						-- Raster size  (default "x" becomes nil)
			end
			iupDialog.MaxSize = intMaxW.."x"..intMaxH								-- Maximum size is virtual screen size
			if strFrame:match("norm") then											-- DialogFrame mode is "NO" by default for variable size window
				if strFrame:match("pop") or strFrame:match("keep") then
					iupDialog.MinBox = "NO"												-- For "popup" and "keep" hide Minimize and Maximize icons
					iupDialog.MaxBox = "NO"
				else 
					strFrame = strFrame.." show"										-- If not "popup" nor "keep" then use "showxy" mode
				end
			else
				iupDialog.DialogFrame = "YES"											-- Define DialogFrame mode for fixed size window
			end
			iupDialog.close_cb  = iupDialog.close_cb  or function() return iup.CLOSE end	-- Define default window X close, move, and resize actions
			iupDialog.move_cb   = iupDialog.move_cb   or function(self) if iup.MainLoopLevel() > 0 then fh.SetWindowCoord(tblName) end end			-- V3.5 -- V4.4
			iupDialog.resize_cb = iupDialog.resize_cb or function(self) if iup.MainLoopLevel() > 0 then tblName.Raster=self.RasterSize end end	-- V3.5 -- V4.4 -- V4.6
			fh.RefreshDialogue(strName)												-- Refresh to set Natural Size as Minimum Size
			if strName == "Main" then
				if fhGetAppVersion() > 6 then 										-- Main window centres on FH parent	-- V4.4
					iup.SetAttribute(iupDialog,"NATIVEPARENT",fhGetContextInfo("CI_PARENT_HWND"))
				end
			else
				local tblMain = tblNameFor("Main")									-- Others popup centrally in Main 	-- V4.4
				local iupMain = tblMain.Dialog
				if iupMain then															-- Centre based on size of windows	-- V1.4
					local arrName = stringx.splitnumbers(tblName.Raster or "0x0")
					local arrMain = stringx.splitnumbers(tblMain.Raster or arrName[1].."x"..arrName[2])
					tblName.CoordX = iupMain.X + math.floor( (arrMain[1] - arrName[1]) / 2 )
					tblName.CoordY = iupMain.Y + math.floor( (arrMain[2] - arrName[2]) / 2 )
				elseif fhGetAppVersion() > 6 then 									-- This window centres on FH parent	-- V4.4
					iup.SetAttribute(iupDialog,"NATIVEPARENT",fhGetContextInfo("CI_PARENT_HWND"))
				end
			end
			if strFrame:match("map") then												-- Only dialogue mapping is required
				iupDialog:map()
				tblName.Frame = strFrame:gsub("%s-%a-map%a*[%s%p]*","")			-- Remove "map" from frame mode ready for subsequent call
				return
			end
			if iup.MainLoopLevel() == 0												-- Called from outside Main GUI, so must use showxy() and not popup()
			or strFrame:match("dialog")
			or strFrame:match("sho") then												-- Use showxy() to dispay dialogue window for "showxy" or "dialog" mode
				iupDialog:showxy(tblName.CoordX,tblName.CoordY)
				if not strFrame:match("dialog")										-- Inhibit MainLoop if "dialog" mode	-- V4.1
				and iup.MainLoopLevel() == 0 then iup.MainLoop() end
			else
				iupDialog:popup(tblName.CoordX,tblName.CoordY)						-- Use popup() to display dialogue window for "popup" or "keep" modes
				fhSleep(200,150)															-- Sometimes needed to prevent MainLoop() closure!	-- V3.9
			end
			if not strFrame:match("dialog") and strFrame:match("pop") then
				tblName.Dialog = nil													-- When popup closed, clear key parameters, but not for "keep" mode
				tblName.Raster = nil
				tblName.CoordX = nil -- iup.CENTERPARENT
				tblName.CoordY = nil -- iup.CENTERPARENT
			elseif tblName.CoordX ~= iup.CENTERPARENT								-- V4.4
			   and tblName.CoordY ~= iup.CENTERPARENT then
				fh.SetWindowCoord(tblName)												-- Set Window coordinate pixel values -- V3.5
			end
		end
	end -- function ShowDialogue

	function fh.DestroyDialogue(strName)												-- Destroy existing dialogue
		local tblName = tblNameFor(strName)
		if tblName then
			local iupDialog = tblName.Dialog
			if type(iupDialog) == "userdata" then
				iupDialog:destroy()
				tblName.Dialog = nil													-- Prevent future misuse of handle -- 22 Jul 2014
			end
		end
	end -- function DestroyDialogue

	local function strDialogueArgs(strArgA,strArgB,comp)							-- Compare two argument pairs and return matching pair
		local tblArgA = stringx.splitnumbers(strArgA)
		local tblArgB = stringx.splitnumbers(strArgB)
		local strArgX = tostring(comp(tblArgA[1] or 100,tblArgB[1] or 100))
		local strArgY = tostring(comp(tblArgA[2] or 100,tblArgB[2] or 100))
		return strArgX.."x"..strArgY
	end -- local function strDialogueArgs

	function fh.RefreshDialogue(strName)												-- Refresh dialogue window size after Font change, etc
		local tblName = tblNameFor(strName)
		local iupDialog = tblName.Dialog												-- Retrieve the dialogue handle
		if type(iupDialog) == "userdata" then
			iupDialog.Size = iup.NULL
			iupDialog.MinSize = iup.NULL												-- V3.1
			iup.Refresh(iupDialog)														-- Refresh window to Natural Size and set as Minimum Size
			if not iupDialog.RasterSize then
				iupDialog:map()
				iup.Refresh(iupDialog)
			end
			local strSize = iupDialog.NaturalSize or iupDialog.RasterSize				-- IUP 3.5 NaturalSize = nil, IUP 3.11 needs NaturalSize					-- V3.1
			iupDialog.MinSize = strDialogueArgs(iupDialog.MaxSize,strSize,math.min)	-- Set Minimum Size to smaller of Maximm Size or Natural/Raster Size	-- V3.1
			iupDialog.RasterSize = strDialogueArgs(tblName.Raster,strSize,math.max)	-- Set Current Size to larger of Current Size or Natural/Raster Size	-- V3.1
			iup.Refresh(iupDialog)
			tblName.Raster = iupDialog.RasterSize
			if iupDialog.Visible == "YES" then										-- Ensure visible dialogue origin is on screen
				tblName.CoordX = math.max(tblName.CoordX,10)
				tblName.CoordY = math.max(tblName.CoordY,10)						-- Set both coordinates to larger of current value or 10 pixels
				if iupDialog.Modal then													--	V3.8
					if iupDialog.Modal == "NO" then
						iupDialog.ZOrder = "BOTTOM"									-- Ensure dialogue is subservient to any popup
						iupDialog:showxy(tblName.CoordX,tblName.CoordY)			-- Use showxy() to reposition main window
					else
						iupDialog:popup(tblName.CoordX,tblName.CoordY)				-- Use popup() to reposition modal window
					end
				end
			else
				iupDialog.BringFront="YES"
			end
		end
	end -- function RefreshDialogue

	function fh.AssignAttributes(tblControls)										-- Assign the attributes of all controls supplied
		local anyFunction = nil
		for iupName, tblAttr in pairs ( tblControls or {} ) do
			if type(iupName) == "userdata" and type(tblAttr) == "table" then	-- Loop through each iup control
				local intSkip = 0														-- Skip counter for attributes same for all controls
				for intAttr, anyName in ipairs ( tblControls[1] or {} ) do		-- Loop through each iup attribute
					local strName = nil
					local strAttr = nil
					local strType = type(anyName)
					if strType == "string" then										-- Attribute is different for each control in tblControls
						strName = anyName
						strAttr = tblAttr[intAttr-intSkip]
					elseif strType == "table" then									-- Attribute is same for all controls as per tblControls[1] 
						intSkip = intSkip + 1
						strName = anyName[1]
						strAttr = anyName[2]
					elseif strType == "function" then
						intSkip = intSkip + 1
						anyFunction = anyName
						break
					end
					if type(strName) == "string" and ( type(strAttr) == "string" or type(strAttr) == "function" ) then
						local anyRawGet = rawget(fh,strAttr)							-- Use rawget() to stop require("pl.strict") complaining
						if type(anyRawGet) == "string" then
							strAttr = anyRawGet											-- Use internal module attribute such as Head or FontBody
						elseif type(iupName[strName]) == "string"
						   and type(strAttr) == "function" then						-- Allow string attributes to invoke a function	-- V3.7
							strAttr = strAttr()
						end
						iupName[strName] = strAttr										-- Assign attribute to control
					end
				end
			end
		end
		if anyFunction then anyFunction() end										-- Perform any control assignment function
	end -- function AssignAttributes

	-- Font Dialogue Attributes and Functions --

	fh.FontBody = iup.GetGlobal("DEFAULTFONT")										-- Set default font for Body and Head text
	fh.FontHead = fh.FontBody:gsub(", B?o?l?d?",", Bold ")

	function fh.FontDialogue(tblAttr,strName)										-- GUI Font Face & Style Dialogue
		tblAttr = tblAttr or {}
		strName = strName or "Main"
		local isFontChosen = false
		local btnFontHead = iup.button { Title="Choose Headings Font and default Colour"; }
		local btnFontBody = iup.button { Title="Choose Body text Font and default Colour"; }
		local btnCol_Safe = iup.button { Title=" Safe Colour "; }
		local btnCol_Warn = iup.button { Title=" Warning Colour "; }
		local btnCol_Risk = iup.button { Title=" Risky Colour "; }
		local btnDefault  = iup.button { Title=" Default Fonts "; }
		local btnMinimum  = iup.button { Title=" Minimum Size "; }
		local btnDestroy  = iup.button { Title=" Close Dialogue "; }
		local frmSetFonts = iup.frame  { Title=" Set Window Fonts & Colours ";
									iup.vbox { Alignment="ACENTER"; Margin=fh.Margin; Homogeneous="YES";
										btnFontHead;
										btnFontBody;
										iup.hbox { btnCol_Safe; btnCol_Warn; btnCol_Risk; Homogeneous="YES"; };
										iup.hbox { btnDefault ; btnMinimum ; btnDestroy ; Homogeneous="YES"; };
									} -- iup.vbox end
								} -- iup.frame end

		-- Create dialogue and turn off resize, maximize, minimize, and menubox except Close button
		local dialogFont  = iup.dialog { Title=" Set Window Fonts & Colours "; Gap=fh.Gap; Margin=fh.Border; frmSetFonts; }

		local tblButtons = { }

		local function setDialogues()													-- Refresh the Main dialogue	-- V4.4
			fh.AssignAttributes(tblAttr)												-- Assign parent dialogue attributes
			fh.RefreshDialogue(strName)												-- Refresh parent window size & position and bring infront of other window
			fh.RefreshDialogue("Font")													-- Refresh Font window size & position and bring infront of parent window
		end -- local function setDialogues

		local function getFont(strColor)												-- Set font button function
			local strTitle = " Choose font style & default colour for "..strColor:gsub("Head","Heading").." text "
			local strValue = "Font"..strColor											-- The font codes below are not recognised by iupFontDlg and result in empty font face!
			local strFont  = rawget(fh,strValue):gsub(" Black,",","):gsub(" Light, Bold",","):gsub(" Extra Bold,",","):gsub(" Semibold,",",")
			local iupFontDlg = iup.fontdlg { Title=strTitle; Color=rawget(fh,strColor); Value=strFont; }
			iupFontDlg:popup()															-- Popup predefined font dialogue
			if iupFontDlg.Status == "1" then
				if iupFontDlg.Value:match("^,") then									-- Font face missing so revert to original font
					iupFontDlg.Value = rawget(fh,strValue)
				end
				fh[strColor] = iupFontDlg.Color										-- Set Head or Body color attribute
				fh[strValue] = iupFontDlg.Value										-- Set FontHead or FontBody font style
				fh.AssignAttributes(tblButtons)										-- Assign the button & frame attributes
				setDialogues()
				isFontChosen = true
			end
		end -- local function getFont

		local function getColor(strColor)												-- Set colour button function
			local strTitle = " Choose colour for "..strColor:gsub("Warn","Warning"):gsub("Risk","Risky").." button & message text "
			local iupColorDlg = iup.colordlg { Title=strTitle; Value=rawget(fh,strColor); ShowColorTable="YES"; }
			iupColorDlg.DialogFrame="YES"
			iupColorDlg:popup()															-- Popup predefined color dialogue fixed size window
			if iupColorDlg.Status == "1" then
				fh[strColor] = iupColorDlg.Value										-- Set Safe or Warn or Risk color attribute
				fh.AssignAttributes(tblButtons)										-- Assign the button & frame attributes
				setDialogues()
				isFontChosen = true
			end
		end -- local function getColor

		local function setDefault()													-- Action for Default Fonts button
			fh.Safe = fh.Green
			fh.Warn = fh.Magenta
			fh.Risk = fh.Red																-- Set default colours
			fh.Body = fh.Black
			fh.Head = fh.Black
			fh.FontBody = iup.GetGlobal("DEFAULTFONT")								-- Set default fonts for Body and Head text
			fh.FontHead = fh.FontBody:gsub(", B?o?l?d?",", Bold")
			fh.AssignAttributes(tblButtons)											-- Assign the button & frame attributes
			setDialogues()
			isFontChosen = true
		end -- local function setDefault

		local function setMinimum()													-- Action for Minimum Size button
			local tblName = tblNameFor(strName)
			local iupDialog = tblName.Dialog											-- Retrieve the parent dialogue handle
			if type(iupDialog) == "userdata" then
				tblName.Raster = "10x10"												-- Refresh parent window to Minimum Size & adjust position
				fh.RefreshDialogue(strName)
			end
			local tblFont = tblNameFor("Font")
			tblFont.Raster = "10x10"													-- Refresh Font window to Minimum Size & adjust position
			fh.RefreshDialogue("Font")
		end -- local function setMinimum

		tblButtons  =  {  {  "Font" ; "FgColor" ; "Tip" ; "action" ; {"TipBalloon";"Balloon";} ; {"Expand";"YES";} ; };
			[btnFontHead] = { "FontHead"; "Head"; "Choose the Heading text Font Face, Style, Size, Effects, and default Colour"; function() getFont("Head") end; };
			[btnFontBody] = { "FontBody"; "Body"; "Choose the Body text Font Face, Style, Size, Effects, and default Colour"   ; function() getFont("Body") end; };
			[btnCol_Safe] = { "FontBody"; "Safe"; "Choose the colour for Safe operations"   ; function() getColor("Safe") end; };
			[btnCol_Warn] = { "FontBody"; "Warn"; "Choose the colour for Warning operations"; function() getColor("Warn") end; };
			[btnCol_Risk] = { "FontBody"; "Risk"; "Choose the colour for Risky operations"  ; function() getColor("Risk") end; };
			[btnDefault ] = { "FontBody"; "Safe"; "Restore default Fonts and Colours"; function() setDefault() end; };
			[btnMinimum ] = { "FontBody"; "Safe"; "Reduce window to its minimum size"; function() setMinimum() end; };
			[btnDestroy ] = { "FontBody"; "Risk"; "Close this dialogue "; function() return iup.CLOSE end; };
			[frmSetFonts] = { "FontHead"; "Head"; };
			} 

		fh.AssignAttributes(tblButtons)												-- Assign the button & frame attributes
		fh.ShowDialogue("Font",dialogFont,btnDestroy,"keep normal")				-- Popup the Set Window Fonts dialogue: "keep normal"  : vary size & posn, and remember size & posn
	--	fh.ShowDialogue("Font",dialogFont,btnDestroy,"popup normal")			-- Popup the Set Window Fonts dialogue: "popup normal" : vary size & posn, but redisplayed centred
	--	fh.ShowDialogue("Font",dialogFont,btnDestroy,"keep")						-- Popup the Set Window Fonts dialogue: "keep" : fixed size, vary posn, and only remember posn
	--	fh.ShowDialogue("Font",dialogFont,btnDestroy,"popup")						-- Popup the Set Window Fonts dialogue: "popup": fixed size, vary posn, but redisplayed centred
		dialogFont:destroy()
		return isFontChosen

	end -- function FontDialogue

	local function anyMemoControl(anyName,fgColor)									-- Compose any control Title and FgColor
		local strName = tostring(anyName)												-- anyName may be a string, and fgColor is default FgColor
		local tipText = nil
		if type(anyName) == "table" then												-- anyName may be a table = { Title string ; FgColor string ; ToolTip string (optional); }
			strName = anyName[1]
			fgColor = anyName[2]:match("%d* %d* %d*") or fgColor
			tipText = anyName[3]
		end
		return strName, fgColor, tipText
	end -- local function anyMemoControl

	local function anyMemoDialogue(strHead,anyHead,strMemo,anyMemo,...)		-- Display framed memo dialogue with buttons
		local arg = {...}																-- Fix for Lua 5.2+
		local intButt = 0																-- Returned value if "X Close" button is used
		local tblButt = { [0]="X Close"; }											-- Button names lookup table
		local strHead, fgcHead, tipHead = anyMemoControl(anyHead or "",strHead)
		local strMemo, fgcMemo, tipMemo = anyMemoControl(anyMemo or "",strMemo)
		-- Create the GUI labels and buttons
		local lblMemo = iup.label { Title=strMemo; FgColor=fgcMemo; Tip=tipMemo; TipBalloon=fh.Balloon; Alignment="ACENTER"; Padding=fh.Margin; Expand="YES"; WordWrap="YES"; }
		local lblLine = iup.label { Separator="HORIZONTAL"; }
		local iupHbox = iup.hbox  { Homogeneous="YES"; }
		local btnButt = iup.button { }
		local strTop  = "YES"															-- Make dialogue TopMost -- V3.6
		local strMode = "popup"
		if arg[1] == "Keep Dialogue" then												-- Keep dialogue open for a progress message
			strMode = "keep dialogue"
			lblLine = iup.label { }
			if not arg[2] then strTop = "NO" end										-- User chooses TopMost -- V3.6
		else
			if #arg == 0 then arg[1] = "OK" end 										-- If no buttons listed then default to an "OK" button
			for intArg, anyButt in ipairs(arg) do
				local strButt, fgcButt, tipButt = anyMemoControl(anyButt,fh.Safe)
				tblButt[intArg] = strButt
				btnButt = iup.button { Title=strButt; FgColor=fgcButt; Tip=tipButt; TipBalloon=fh.Balloon; Expand="NO"; MinSize="80"; Padding=fh.Margin; action=function() intButt=intArg return iup.CLOSE end; }
				iup.Append( iupHbox, btnButt )
			end
		end
		-- Create dialogue and turn off resize, maximize, minimize, and menubox except Close button
		local iupMemo = iup.dialog { Title=fh.Plugin..fh.Version..strHead; TopMost=strTop;	-- TopMost added -- V3.6
								iup.vbox { Alignment="ACENTER"; Gap=fh.Gap; Margin=fh.Margin;
									iup.frame { Title=strHead; FgColor=fgcHead; Font=fh.FontHead;
										iup.vbox { Alignment="ACENTER"; Font=fh.FontBody; lblMemo; lblLine; iupHbox; };
									};
								};
							}
		fh.ShowDialogue("Memo",iupMemo,btnButt,strMode)							-- Show popup Memo dialogue window with righthand button in focus (if any)
		if strMode == "keep dialogue" then return lblMemo, iupMemo end			-- Return label & dialogue controls so message can be changed and dialogue destroyed
		iupMemo:destroy()
		return intButt, tblButt[intButt]												-- Return button number & title that was pressed
	end -- local function anyMemoDialogue

	function fh.MemoDialogue(anyMemo,...)											-- Multi-Button GUI like iup.Alarm and fhMessageBox, with "Memo" in frame
		return anyMemoDialogue(fh.Head,"Memo",fh.Body,anyMemo,...)
	end -- function MemoDialogue

	function fh.WarnDialogue(anyHead,anyMemo,...)									-- Multi-Button GUI like iup.Alarm and fhMessageBox, with heading in frame
		return anyMemoDialogue(fh.Warn,anyHead,fh.Warn,anyMemo,...)
	end -- function WarnDialogue

	function fh.GetRegKey(strKey)														-- Read Windows Registry Key Value
		local luaShell = luacom.CreateObject("WScript.Shell")
		local anyValue = nil
		if pcall( function() anyValue = luaShell:RegRead(strKey) end ) then
			return anyValue																-- Return Key Value if found
		end
		return nil
	end -- function GetRegKey

	function fh.PutRegKey(strKey,anyValue,strType)									-- Write Windows Registry Key Value
		local luaShell = luacom.CreateObject("WScript.Shell")
		local strAns = nil
		if pcall( function() strAns = luaShell:RegWrite(strKey,anyValue,strType) end ) then
			return true
		end
		return nil
	end -- function PutRegKey

	local function httpRequest(strRequest)											-- Luacom http request protected by pcall() below
		local http = luacom.CreateObject("winhttp.winhttprequest.5.1")
		http:Open("GET",strRequest,false)
		http:Send()
		return http.Responsebody
	end -- local function httpRequest

	function fh.VersionInStore(strPlugin)											-- Obtain the Version in Plugin Store by Name only	-- V4.5
		local strVersion = "0"
		if strPlugin then
			local strFile = fh.MachinePath.."\\VersionInStore "..strPlugin..".dat"
			general.DeleteFile(strFile)
			local lblMemo, iupMemo = fh.MemoDialogue("Checking for updated version in the Family Historian 'Plugin Store'.","Keep Dialogue")
			local strRequest ="http://www.family-historian.co.uk/lnk/checkpluginversion.php?name="..strPlugin
			local isOK, strReturn = pcall(httpRequest,strRequest)
			iupMemo:destroy()
			if not isOK then																-- Problem with Internet access
				fhMessageBox(strReturn.."\n The Internet appears to be inaccessible. ","MB_OK","MB_ICONEXCLAMATION")
			elseif strReturn ~= nil then
				strVersion = strReturn:match("([%d%.]*),%d*")						-- Version digits & dots then comma and Id digits 
			end
		end
		return strVersion or "0"
	end -- function VersionInStore

	local function intVersion(strVersion)											-- Convert version string to comparable integer
		local intVersion = 0
		local arrNumbers = {}
		strVersion:gsub("(%d+)", function(strDigits) table.insert(arrNumbers,strDigits) end)	-- V4.1
		for i=1,5 do
			intVersion = intVersion * 100 + tonumber(arrNumbers[i] or 0)
		end
		return intVersion
	end -- local function intVersion

	function fh.CheckVersionInStore()													-- Check if later Version available in Plugin Store	-- V4.5
		local strNewVer = fh.VersionInStore(fh.Plugin:gsub(" %- .*",""))
		local strOldVer = fh.Version
		if intVersion(strNewVer) > intVersion(strOldVer:match("%D*([%d%.]*)")) then
			fh.MemoDialogue("Later Version "..strNewVer.." of this Plugin is available from the 'Plugin Store'.")
		else
			fh.MemoDialogue("No later Version of this Plugin is available from the 'Plugin Store'.")
		end
	end -- function CheckVersionInStore

	function fh.PluginDataScope(strScope)											-- Set default Plugin Data scope to per-Project, or per-User, or per-Machine
		strScope = tostring(strScope):lower()
		if strScope:match("mach") then												-- Per-Machine
			strDefaultScope = "Machine"
		elseif strScope:match("user") then											-- Per-User
			strDefaultScope = "User"
		end																					-- Per-Project is default
	end -- function PluginDataScope

	local function getPluginDataFileName(strScope)									-- Get plugin data filename for chosen scope
		local isOK, strDataFile = pcall(fhGetPluginDataFileName,strScope)
		if not isOK then strDataFile = fhGetPluginDataFileName() end			-- Before V5.0.8 parameter is disallowed and default = CURRENT_PROJECT
		return strDataFile
	end -- local function getPluginDataFileName

	local function getDataFiles(strScope)											-- Compose the Plugin Data file & path & root names
		local strPluginName = fh.Plugin
		local strPluginPlain = stringx.plain(strPluginName)
		local strDataRoot = ""															-- Plugin data file root name -- V4.2
		local strDataPath = ""															-- Plugin data folder path name
		local strDataFile = getPluginDataFileName(strScope)						-- Allow plugins with variant filenames to use same plugin data files
		strDataFile = strDataFile:gsub("\\"..strPluginPlain:gsub(" ","_"):lower(),"\\"..strPluginName)
		strDataFile = strDataFile:gsub("\\"..strPluginPlain..".+%.[D,d][A,a][T,t]$","\\"..strPluginName..".dat")
		if #strDataFile > 0 then														-- Standalone GEDCOM path is ""
			strDataPath = strDataFile:gsub("\\"..strPluginPlain.."%.[D,d][A,a][T,t]$","")
			strDataRoot = strDataPath.."\\"..strPluginName
			general.MakeFolder(strDataPath)											-- V3.4
		end
		return strDataFile, strDataPath, strDataRoot
	end -- local function getDataFiles

	function fh.Initialise(strVersion,strPlugin)									-- Initialise the GUI module with optional Version & Plugin name

		local strAppData = fhGetContextInfo("CI_APP_DATA_FOLDER")
		fh.Plugin = fhGetContextInfo("CI_PLUGIN_NAME")								-- Plugin Name from file
		fh.Version = strVersion or " "												-- Plugin Version
		if fh.Version == " " then
			local strTitle = "\n@Title is missing"
			local strAuthor = "\n@Author is missing"
			local strVersion = "\n@Version is missing"
			local strPlugin = strAppData.."\\Plugins\\"..fh.Plugin..".fh_lua"
			if general.FlgFileExists(strPlugin) then
				for strLine in io.lines(strPlugin) do								-- Read each line from the Plugin file
					strPlugin = strLine:match("^@Title:[\t-\r ]*(.*)")
					if strPlugin then
						strPlugin = strPlugin:gsub("&&","&")
	--?					if fh.Plugin:match("^"..strPlugin:gsub("(%W)","%%%1")) then
						if fh.Plugin:match("^"..stringx.plain(strPlugin)) then
							fh.Plugin = strPlugin										-- Prefer Title to Filename if it matches
							strTitle = nil
						else
							strTitle = "\n@Title differs from Filename"				-- Report abnormality
						end
					end
					if strLine:match("^@Author:%s*(.*)") then						-- Check @Author exists
						strAuthor = nil
					end 
					fh.Version = strLine:gsub("^@Version:%D*([%d%.]*)%D*"," %1 ")
					if fh.Version ~= strLine then										-- Obtain the @Version from Plugin file
						strVersion = nil
						break
					end
				end
				if strTitle or strAuthor or strVersion then							-- Report any header abnormalities
					fhMessageBox("\nScript Header: "..fh.Plugin..(strTitle or "")..(strAuthor or "")..(strVersion or ""),"MB_OK","MB_ICONEXCLAMATION")
				end
			else
				fhMessageBox("\nPlugin has not been saved!","MB_OK","MB_ICONEXCLAMATION")
			end
		end
		fh.History = fh.Version															-- Version History
		fh.Plugin  = strPlugin or fh.Plugin											-- Plugin Name from argument or default from file

		fh.DefaultDialogue()															-- Default "Font","Main" dialogues

		fh.MachineFile,fh.MachinePath,fh.MachineRoot = getDataFiles("LOCAL_MACHINE")		-- Plugin data names per machine
		fh.PerUserFile,fh.PerUserPath,fh.PerUserRoot = getDataFiles("CURRENT_USER")		-- Plugin data names per user
		fh.ProjectFile,fh.ProjectPath,fh.ProjectRoot = getDataFiles("CURRENT_PROJECT")	-- Plugin data names per project

		fh.FhDataPath = fhGetContextInfo("CI_PROJECT_DATA_FOLDER")							-- Paths used by Load/SaveFolder for relative folders		-- V4.0
		fh.PublicPath = fhGetContextInfo("CI_PROJECT_PUBLIC_FOLDER")						-- Public data folder path name		-- V4.0
		if fh.FhDataPath == "" then
			fh.FhDataPath = fh.ProjectPath:gsub("\\Plugin Data$","")
		end
		if fh.PublicPath == "" then
			fh.PublicPath = fh.ProjectPath
			fh.FhProjPath = fh.PublicPath:gsub("^(.+)\\.-\\Plugin Data$","%1")
		else
			general.MakeFolder(fh.PublicPath)											-- V3.4
			fh.FhProjPath = fh.PublicPath:gsub("^(.+)\\.-\\Public$","%1")
		end
		fh.CalicoPie = strAppData:gsub("\\Calico Pie\\.*","\\Calico Pie")		-- Program Data Calico Pie path name

		fh.ComputerName = os.getenv("COMPUTERNAME")									-- Local PC Computer Name

	end -- function Initialise

	fh.Initialise()																		-- Initialise module with default values

	return fh

end -- local function iup_gui_v3

local iup_gui = iup_gui_v3()															-- To access FH IUP GUI build module

require "imlua"																			-- To access digital imaging library to convert Media image frames
require "imlua_process"

-- Preset Global Data Definitions --
function PresetGlobalData()
	iup_gui.Gap = "2"
	iup_gui.SetUtf8Mode()																-- UTF8 mode needed -- V3.3
	StrPublic = iup_gui.PublicPath
	StrFolder = StrPublic															-- Folder for Website/CD-DVD HTML pages
end -- function PresetGlobalData

-- Reset Sticky Settings to Default Values --
function ResetDefaultSettings()
	iup_gui.CustomDialogue("Main","0x0")												-- Custom "Main" dialogue minimum size & centralisation
	iup_gui.CustomDialogue("Font","0x0")												-- Custom "Font" dialogue minimum size & centralisation
	iup_gui.DefaultDialogue("Bars","Memo")											-- GUI window rastersize and X & Y co-ordinates for "Main","Font","Bars","Memo" dialogues
	StrHomeHTML	= "index.html"														-- Home page HTML filename		-- V3.0
	StrStyleCSS	= "custom/mystyle.css" 												-- Custom style CSS filepath	-- V3.0
	IntPages		=	1																	-- Hyperlinks open in same Page
	IntChars		=	1																	-- Hyperlinks never abbreviated
	IntTabSep		=	1																	-- Column Tab Separator disabled
	StrBorder		= "ON" 																-- Table & cell borders			-- V3.3
	IntPopup		=	1																	-- Image Popups use default Lytebox v4.0
	StrAlso		= "OFF"																-- 'See also' section removed	-- V3.2
	StrMini		= "OFF"																-- Minitrees align in centre	-- V3.2
	StrToPs		= "OFF"																-- Table of Pictures disabled
	StrToRs		= "OFF"																-- Table of Reports disabled
	StrToDs		= "OFF"																-- Table of Downloads disabled
	StrMenu		= "OFF"																-- Links in Menu Bar disabled
	StrFilter		= "OFF"																-- Filter Search box disabled	-- V2.5
	IntLength		= 30																	-- Length of Surnames in 1st column		-- V3.0
	IntNames		=	1																	-- Index of Names for Primary Names only
	IntStyle		=	1																	-- Index of Names added names in italics
	StrIdRiD		= "ON" 																-- Record Identity		-- V3.2
	StrIdPRN		= "OFF"																-- Perm Record No		-- V3.2
	StrIdCiD		= "OFF"																-- Custom Identity		-- V3.2
	StrIdARI		= "OFF"																-- Auto Record Id		-- V3.2
	StrIdUID		= "OFF"																-- Unique Identity		-- V3.2
	StrIdFSI		= "OFF"																-- Family Search Id		-- V3.2
	IntGenDex		=	4																	-- GenDex excludes Individuals with Private/Living flags
	IntTabPosn	=	0																	-- Initial tab position undefined
end -- function ResetDefaultSettings

-- Load Sticky Settings from File --
function LoadSettings()
	iup_gui.LoadSettings("Bars")														-- Includes "Main","Font" dialogues and "FontSet" & "History"
	iup_gui.Balloon = "NO"																-- V3.0 for Crossover/PlayOnLinux/Mac
	StrFolder	= tostring(iup_gui.LoadFolder("Folder",StrFolder))
	IntPages	= tonumber(iup_gui.LoadGlobal("Pages" ,IntPages ))
	IntChars	= tonumber(iup_gui.LoadGlobal("Chars" ,IntChars ))
	IntTabSep	= tonumber(iup_gui.LoadGlobal("TabSep",IntTabSep))
	StrBorder	= tostring(iup_gui.LoadGlobal("Border",StrBorder))				-- V3.3
	IntPopup	= tonumber(iup_gui.LoadGlobal("Popup" ,IntPopup ))
	StrAlso	= tostring(iup_gui.LoadGlobal("Also"  ,StrAlso  ))				-- V3.2
	StrMini	= tostring(iup_gui.LoadGlobal("Mini"  ,StrMini  ))				-- V3.2
	StrToPs	= tostring(iup_gui.LoadGlobal("ToPs"  ,StrToPs  ))
	StrToRs	= tostring(iup_gui.LoadGlobal("ToRs"  ,StrToRs  ))
	StrToDs	= tostring(iup_gui.LoadGlobal("ToDs"  ,StrToDs  ))
	StrMenu	= tostring(iup_gui.LoadGlobal("Menu"  ,StrMenu  ))
	StrFilter	= tostring(iup_gui.LoadGlobal("Filter",StrFilter))				-- V2.5 
	IntLength	= tonumber(iup_gui.LoadGlobal("Length",IntLength))				-- V3.0
	IntNames	= tonumber(iup_gui.LoadGlobal("Index" ,IntNames ))				-- Legacy "Index" setting
	IntNames	= tonumber(iup_gui.LoadGlobal("Names" ,IntNames ))
	IntStyle	= tonumber(iup_gui.LoadGlobal("Style" ,IntStyle ))
	IntIdent	= tonumber(iup_gui.LoadGlobal("Ident" ,IntIdent ))
	StrIdRiD	= tostring(iup_gui.LoadGlobal("IdRiD" ,StrIdRiD ))				-- V3.2
	StrIdPRN	= tostring(iup_gui.LoadGlobal("IdPRN" ,StrIdPRN ))				-- V3.2
	StrIdCiD	= tostring(iup_gui.LoadGlobal("IdCiD" ,StrIdCiD ))				-- V3.2
	StrIdARI	= tostring(iup_gui.LoadGlobal("IdARI" ,StrIdARI ))				-- V3.2
	StrIdUID	= tostring(iup_gui.LoadGlobal("IdUID" ,StrIdUID ))				-- V3.2
	StrIdFSI	= tostring(iup_gui.LoadGlobal("IdFSI" ,StrIdFSI ))				-- V3.2
	IntGenDex	= tonumber(iup_gui.LoadGlobal("GenDex",IntGenDex))
	IntTabPosn = tonumber(iup_gui.LoadGlobal("TabPosn",IntTabPosn))
	if IntIdent == 2 or IntIdent == 6 then StrIdRiD = "ON" end					-- V3.2 -- Legacy conversion
	if IntIdent == 3 or IntIdent == 6 then StrIdPRN = "ON" end					-- V3.2
	if IntIdent == 4 or IntIdent == 6 then StrIdCiD = "ON" end					-- V3.2
	if IntIdent == 5 or IntIdent == 6 then StrIdARI = "ON" end					-- V3.2
	if IntIdent == 6 then  StrIdUID = "ON" StrIdFSI = "ON" end					-- V3.2
	IntIdent = nil
	SaveSettings()																		-- Save sticky data settings
	g_trans_misc = { Output_Language = ""; }										-- Create global Language Pack translation table -- V3.2
	if fhGetAppVersion() > 6 then
		local strLang = iup_gui.GetRegKey("HKCU\\SOFTWARE\\Calico Pie\\Family Historian\\2.0\\Preferences\\Output Language Id")
		if #strLang > 2 then
			local strPack = fhGetContextInfo("CI_APP_DATA_FOLDER").."\\Lang\\"..strLang.."\\lang_trans_misc.fh_lua"
			dofile(strPack)
			g_trans_misc.Output_Language = " for Output Language "..strLang
		else
			g_trans_misc.Output_Language = " for English"
		end
	end
end -- function LoadSettings

-- Translate text to current output language --									-- V3.2
function StrTranslate(strText)
	-- strText	~ Text to translate
	return g_trans_misc["~HTML:"..strText] or g_trans_misc[strText] or StrOther(strText) or strText
end -- function StrTranslate

function StrOther(strText)		-- Try translating capitalised text, e.g. For 'father' try 'Father' and convert any translation to lower case
	-- strText	~ Text to capitalise and translate
	local strOther = g_trans_misc[strText:sub(1,1):upper()..strText:sub(2,-1)]
	if strOther then strOther = strOther:lower() end
	return strOther
end -- function StrOther

-- Save Sticky Settings to File --
function SaveSettings()
	iup_gui.SaveFolder("Folder",StrFolder)
	iup_gui.SaveGlobal("Pages" ,IntPages )
	iup_gui.SaveGlobal("Chars" ,IntChars )
	iup_gui.SaveGlobal("TabSep",IntTabSep)
	iup_gui.SaveGlobal("Border",StrBorder)											-- V3.3
	iup_gui.SaveGlobal("Popup" ,IntPopup )
	iup_gui.SaveGlobal("Also"  ,StrAlso  )											-- V3.2
	iup_gui.SaveGlobal("Mini"  ,StrMini  )											-- V3.2
	iup_gui.SaveGlobal("ToPs"  ,StrToPs  )
	iup_gui.SaveGlobal("ToRs"  ,StrToRs  )
	iup_gui.SaveGlobal("ToDs"  ,StrToDs  )
	iup_gui.SaveGlobal("Menu"  ,StrMenu  )
	iup_gui.SaveGlobal("Filter",StrFilter)											-- V2.5 
	iup_gui.SaveGlobal("Length",IntLength)											-- V3.0
	iup_gui.SaveGlobal("Names" ,IntNames )
	iup_gui.SaveGlobal("Style" ,IntStyle )
	iup_gui.SaveGlobal("Ident" ,IntIdent )
	iup_gui.SaveGlobal("IdRiD" ,StrIdRiD )											-- V3.2
	iup_gui.SaveGlobal("IdPRN" ,StrIdPRN )											-- V3.2
	iup_gui.SaveGlobal("IdCiD" ,StrIdCiD )											-- V3.2
	iup_gui.SaveGlobal("IdARI" ,StrIdARI )											-- V3.2
	iup_gui.SaveGlobal("IdUID" ,StrIdUID )											-- V3.2
	iup_gui.SaveGlobal("IdFSI" ,StrIdFSI )											-- V3.2
	iup_gui.SaveGlobal("TabPosn",IntTabPosn)
	iup_gui.SaveSettings("Bars")														-- Includes "Main","Font" dialogues and "FontSet" & "History"
end -- function SaveSettings

-- Decode hex encoded text/data --													-- V3.3
function StrDecodedText(strText,strFile)
	-- strText	~ Encoded zip file content
	-- strFile	~ Expected unpacked file
	local strAppDir = iup_gui.MachinePath.."\\"
	local arrFile = {}
	for strByte in strText:gmatch("%x%x") do
		table.insert(arrFile,string.char(tonumber(strByte,16)))
	end
	local zipFile = strAppDir..iup_gui.Plugin..".zip"
	local zip = assert(io.open(zipFile,"wb"))										-- Create the zip file
	zip:write(table.concat(arrFile))
	assert(zip:close())
	local shell = luacom.CreateObject("Shell.Application") 						-- Create com object to work with files and folders
	local path = shell:NameSpace(zipFile)											-- Get the zip file
	local file = path:items()
	local dest = shell:NameSpace(strAppDir)											-- Get the destination folder
	local items = dest:items().count
	dest:CopyHere(file) 																-- Unpack the zip file to the folder
	if strFile and general.FlgFileExists(strFile) then return end
	strFile = strAppDir..iup_gui.Plugin..".tmp"
	if general.FlgFileExists(strFile) then
		local fileTmp = assert(io.open(strFile,"rb"))
		local strText = fileTmp:read("*a")
		assert(fileTmp:close())
		general.DeleteFile(strFile)
		return strText
	end
	fhMessageBox("\nUnpack Zip File Failure\n")
	return ""
end -- function StrDecodedText

-- Update only if file changed --														-- V3.3
function IntUpdateFile(strText,strFile)
	-- strText	~ Decoded content
	-- strFile	~ Filename & path
	if general.FlgFileExists(strFile) then
		local strRead = general.StrLoadFromFile(strFile)
		if strText == strRead then return 0 end
	end
	general.SaveStringToFile(strText,strFile)
	return 1
end -- function IntUpdateFile

-- Decode hex encoded text and write to file --									-- V3.3
function WriteDecodedFile(strText,strFile)
	-- strText	~ Encoded content
	-- strFile	~ Filename & path
	strText = StrDecodedText(strText)
	return IntUpdateFile(strText,strFile)
end -- function WriteDecodedFile

-- Delete only if file exists --														-- V3.3
function IntDeleteFile(strFile)
	if general.FlgFileExists(strFile) then
		general.DeleteFile(strFile)
		return 1
	end
	return 0
end -- function IntDeleteFile

-- Load icon files to ProgramData --													-- V2.8 -- V3.0
function DownloadIcons()
	local tblList = { doc_icon; etc_icon; pdf_icon; txt_icon; }
	for _, dicList in ipairs (tblList) do
		local strFile = iup_gui.MachinePath.."\\"..dicList.File
		if not general.FlgFileExists(strFile) then									-- Decode missing icon file from embedded code
			StrDecodedText(dicList.Code,strFile)
		end
	end
end -- function DownloadIcons

-- Convert file type to icon filename --											-- V2.8
function StrIconName(strType)
	-- strType	~ Type of icon file to choose if it exists
	local strFile = etc_icon.File
	local strIcon = strFile:gsub("_etc_","_"..strType:sub(1,3):lower().."_")
	if not general.FlgFileExists(iup_gui.MachinePath.."\\"..strIcon) then
		strIcon = strFile
	end
	return strIcon
end -- function StrIconName

-- Convert all URL & Hypertext in every required HTML Web/CD/DVD page --

function IntImproveHTML(strFolder,intPages,intChars,strTabSep)
	-- strFolder	~ Website HTML folder
	-- intPages	~ Open URL pages option
	-- intChars	~ Abbrevciate URL option
	-- strTabSep	~ Tab separator option

	-- Convert any URL into Hyperlinks and translate any Text placeholders --

	local tblPages	= { ''; ' target="_blank"'; }									-- Target page options
	local tblChars	= { 999; 30; 50; 70; 90; }										-- URL length options
	local tblAnchor	= {}																-- Table of Anchor parameters
	tblAnchor.Style	= ' class="fhextlink"'											-- Set class style anchor attribute as used by FH
	tblAnchor.Pages	= tblPages[intPages]											-- Set target page anchor attribute for GUI option
	tblAnchor.Chars	= tonumber(tblChars[intChars])								-- Set abbreviated URL char length for GUI option
	tblAnchor.Match	= '[A-Za-z0-9#&/:;=@_%%%+%-%.%?]+[^\t-\r !-/:-@%[\\%]^_`%]{-~]'	-- Set pattern for unquoted URL
						-- [A-Za-z0-9#&/:;=@_%%%+%-%.%?] allows URL to contain alphanumeric characters A-Z a-z 0-9 and symbols # & / : ; = @ _ % + - . ?
						-- [^\t-\r !-/:-@%[\\%]^_`%]{-~] prevents last character from being tabs/spaces or punctuation symbols # & / : ; = @ _ % + - . ? , " ' < > ! £ $ ^ * ( ) { } [ ] ~ | \ ¬ ` 
						-- For details see http://en.wikipedia.org/wiki/Uniform_resource_locator and http://en.wikipedia.org/wiki/URI_scheme

	strTabSep = strTabSep:gsub('[\t-\r ]+','')										-- Adjust column table separator
	strTabSep = strTabSep:gsub('{TAB}','\t')
	strTabSep = strTabSep:match('(%W+)$')
	local tblLine = {}																	-- V2.5 -- Accumulated lines when reverting to original when strTabSep is nil

	-- Parse any Anchor tag into its component parts and adjust class & target attributes, and link text length

	local function strParse(strAnchor,tblAnchor)
		-- strAnchor	~ HTML anchor tag
		-- tblAnchor	~ Default anchor mode
		local strStyle = tblAnchor.Style
		local strPages = tblAnchor.Pages
		local strMatch = tblAnchor.Match
		local strAttr, strLink = strAnchor:match('<a(%s.-)>(.-)</a>')			-- Split anchor tag into attributes and link text parts
		-- Parse attributes with value in "double-quotes"  or enclosed in 'single-quotes'      or without any quotes at all               or use default value
		local strHref   = strAttr:match('(%shref=".-")')   or strAttr:match("(%shref='.-')")   or strAttr:match('(%shref='..strMatch..')') or ' href="http://www.null.com"'
		local strClass  = strAttr:match('(%sclass=".-")')  or strAttr:match("(%sclass='.-')")  or strAttr:match('(%sclass='..strMatch..')') or strStyle
		local strTarget = strAttr:match('(%starget=".-")') or strAttr:match("(%starget='.-')") or strAttr:match('(%starget='..strMatch..')') or strPages
		strAttr   = strAttr:replace(strHref,''):replace(strClass,''):replace(strTarget,''):gsub('^[\t-\r ]+',' '):gsub('[\t-\r ]+$','')
		strHref   = strHref:gsub('%shref=([^\'"].-[^\'"])$',' href="%1"')		-- Add missing quotes to href=URL
		strClass  = strClass:gsub('%sclass=([^\'"].-[^\'"])$',' class="%1"')	-- Add missing quotes to class=style
		strTarget = strTarget:gsub('%starget=([^\'"].-[^\'"])$',' target="%1"')-- Add missing quotes to target=page
		if strHref:match('href=%pmailto:') then
			strTarget = ''																-- Remove target attribute from mailto protocol scheme
		elseif strTarget == tblPages[1]
			 or strTarget == tblPages[2] then
			strTarget = strPages														-- Set target attribute for all other protocol schemes
		end
		local intChars = tblAnchor.Chars												-- Abbreviate long URL link text to chosen character length
		local strTail  = '...'	
		local strURL   = strHref:match('%shref=%p(.-)%p$')						-- Extract URL from href="URL"
		local intLink  = strLink:len() - strTail:len()
		if strURL == strLink															-- Abbreviations apply only if URL matches link text
		or ( strURL:sub(1,intLink) == strLink:sub(1,intLink) and strLink:match(strTail..'$') ) then	-- or URL matches abbreviated link text
			if strURL:len() > intChars then
				strLink = strURL:sub(1,intChars)..strTail							-- Apply abbreviated link text
			else
				strLink = strURL															-- Cancel abbreviated link text
			end
		end
		return '<a'..strClass..strHref..strTarget..strAttr..'>'..strLink..'</a>'	-- Compose entire anchor
	end -- local function strParse

	-- Convert all URL protocol schemes, plus class & target attributes, and link text length

	local function strHyper(strSource,tblAnchor)
		-- strSource	~ Original URL text
		-- tblAnchor	~ Default anchor mode
		local strString = strSource
		if strString:match('^<a href=".+" title=".+">$') then
			strString = strString:gsub(' target="_blank"','')													-- Adjust non-image Media hyperlinks -- V2.8
			strString = strString:gsub(' title="',tblAnchor.Pages..' title="')
		elseif strString:matches('://')
		or strString:matches('mailto:')
		or strString:matches('www.')
		or strString:matches('&lt;a href=') then																-- Recognise user <a href="url">link</a> format and convert to valid XHTML
			strString = strString:gsub('&lt;a%s(.-href=.-)&gt;(.-)&lt;/a&gt;','<a %1>%2</a>')			-- Convert URL from FH text field where < = &lt; and > = &gt;
			local strPrefix,strAnchor,strSuffix = strString:match('(.-)(<a%s[^<>]-href=.-</a>)(.*)')	-- Split text line into text prefix, anchor tag, and text suffix
			if strAnchor then																						-- Existing URL hyperlink anchor tag found
				strAnchor = strParse(strAnchor,tblAnchor)														-- Parse anchor into its component parts and reassemble
				strString = strHyper(strPrefix,tblAnchor)..strAnchor..strHyper(strSuffix,tblAnchor)		-- Recursively call strHyper for prefix and suffix
			else
				local strMatch = tblAnchor.Match
				strString = strString:gsub('(&[lg]t;)','<<%1>>')												-- Protect symbols < &lt; and > &gt;
				for i, strScheme in ipairs( { '(.)(http://'; '(.)(https://'; '(.)(ftp://'; '([^/])(www%.'; '(.)(mailto:'; } ) do
					strString = strString:gsub(strScheme..strMatch..')','%1<a href="%2">%2</a>')			-- Repeat for each URL protocol scheme and www. without a scheme
				end
				strString = strString:gsub('<<(&[lg]t;)>>','%1')												-- Unprotect symbols < &lt; and > &gt;
				if strString ~= strSource then strString = strHyper(strString,tblAnchor) end				-- Prevent indefinite recursion loop
			end
			strString = strString:gsub(' href=(%p)www%.',' href=%1http://www.') 							-- Add the http:// scheme to href="www.	-- V3.1 Remove redundant % from www%. replacement text 
		end
		return strString
	end -- local function strHyper

	-- Convert magic {{MEDIA:filepath|caption}} into a non-image file hyperlink and icon --			-- V2.8

	local function strMedia(strPre,strMed,strSuf)
		-- strPre	~ Prefix before MEDIA
		-- strMed	~ MEDIA non-image details
		-- strSuf	~ nSuffix after MEDIA
		local strPref = "_"
		if general.FlgFolderExists(strFolder.."\\media") then						-- Prefer \_media\ unless \media\ sub-folder exists
			strPref = ""
		end
		local strSource, strTarget
		local strFile, strText = strMed:match("^([^|]+)|?(.-)$")
		local strPath, strName = general.SplitFilename(strFile)
		strText = strText:gsub("\\n","<br />")
		if strText == "" then strText = strName end									-- Use file Name if no caption text
		local strTitle = strText:gsub("<br />"," ")
		if strFile:match("^Media\\") then
			strSource = iup_gui.FhDataPath.."\\"..strFile							-- Relative file path needs absolute source
		else
			strSource = strFile															-- Absolute file path needs relative URL path
			strFile = "media\\"..strName								 				-- Add media sub-folder to file Name	-- V3.2
		end
		strFile = (strPref..strFile):lower( ):gsub("%s","_")						-- Convert into URL file path format	-- V3.2
		strTarget = strFolder.."\\"..strFile											-- Optional underscore folder prefix	-- V3.2
		general.CopyFile(strSource,strTarget)										-- Source file exists but Target file may not	-- V3.3
		strFile = encoder.StrUTF8_URI(strFile)										-- or StrUTF8_XML ? -- V3.3
		strFile = strFile:gsub("%%5C","/")
		local strBef = '\n<p>'
		local strAft = '</p>'
		if strPre:match('^<p class="FhDat2">') then									-- Set XHTML tags for context
			strBef = '\n<div class="fhimgwrap">'
			strAft = '\n</div>'
		elseif strPre:match('^<t[rd]') then
			strBef = '\n</tr>\n<tr><td></td>\n<td><div class="fhimgwrap">'
			strAft = '\n</div></td>'
		elseif strPre:match('^<p><span class') then									-- Note in FH V7	-- V3.2
			strBef = '\n<div>'
			strAft = '\n</div>'
			if strSuf:match('</li>$') then
				strSuf = strSuf:gsub('</li>$','')
				strAft = strAft..'\n</li>'
			elseif strSuf:match('</dd>$') then
				strSuf = strSuf:gsub('</dd>$','')
				strAft = strAft..'\n</dd>'
			end
		elseif strPre:match('^<dd><p>') then											-- Sources list FH V7	-- V3.2
			if strSuf:match('</dd>$') then
				strBef = '\n<dd>'
				strAft = '\n</dd>'
			else
				strBef = '\n<div>'
				strAft = '\n</div>'
			end
		elseif strPre:match('^<p>') then												-- Sources list FH V7	-- V3.3
			if strSuf:match('</dd>$') then
				strBef = '\n<div>'
				strAft = '\n</div></dd>'
			else
				strBef = '\n<div>'
				strAft = '\n</div>'
			end
		end
		local strLine = strPre..strSuf												-- Prune empty components
		strLine = strLine:gsub('<p class="FhDat2"> -</p>',"")						-- Record Note
		strLine = strLine:gsub('<td class="FhDat3" colspan="2"> -</td>',"")	-- Fact Note
		strLine = strLine:gsub('<p><span class=".-"></span></p>',"")			-- Note in FH V7	-- V3.2
		strLine = strLine:gsub('</td><td> -, ',"</td><td>")						-- Author
		strLine = strLine:gsub(' %( -%)%.',"")										-- Publication Info
		strLine = strLine:gsub('Custom Id: -%.',"")									-- Custom Id
		strLine = strLine:gsub('<td>Text From Source: -</td>',"")				-- Text From Source
		strLine = strLine:gsub('%.%.</td>',".</td>"):gsub('<td> -%.</td>',"")	-- Source Note
		strLine = strLine:gsub('<p></p></dd>',"")									-- Sources List FH V7	-- V3.3
		if strLine == "" then strBef = strBef:gsub('^\n',"") end
		local strIcon = StrIconName(strFile:match("%.(%l+)$") or "etc")
		general.CopyFile(iup_gui.MachinePath.."\\"..strIcon,StrFolder.."\\"..strIcon)	-- Copy icon file from ProgramData to Web page folder -- V3.3
		return strLine..strBef..'\n<a href="'..strFile..'"'..tblAnchor.Pages..' title="'..strTitle..'">\n<img src="'..strIcon..'" alt="media" />\n</a>\n<p>'..strText..'</p>'..strAft
	end -- local function strMedia

	-- Convert any data line with separators into fixed format table of rows and columns	-- V2.4

	local function strTabulate(tblFile,strSep,int1,int2,strHead,strBody,strTail)	-- V3.3
		-- tblFile	~ Table of converted lines
		-- strSep		~ Tab separator
		-- int1/int2	~ Char positions where line components start
		-- strHead	~ Head tags
		-- strBody	~ Body text to tabulate
		-- strTail	~ Tail tags 
		if int1 and int2 and strHead and strBody and strTail then
			local tblTxt = {}															-- Text per table cell row & column
			local intRow = 0																-- Table cell row index
			local intCol = 0																-- Table cell column index
			local intMax = 0																-- Maximum column index
			local intSum = 0																-- Sum of lengths of biggest text per column
			local strBrk = strSep:replace("+","")									-- Form column break symbol	-- V3.3
			local intBody = 0
			strBody,intBody = strBody:gsub("<br />&nbsp;$","")					-- Strip trailing &nbsp;		-- V3.3
			if intBody > 0 then
				strTail = "<p>&nbsp;</p>\n"..strTail									-- and prefix it to tail		-- V3.3
			end
			strBody = strBody:gsub("[\t ]+"," ")										-- Remove multi white space	-- V3.3
			for strRow in (strBody..'<br />'):gmatch('(.-)<br />') do			-- Extract each row of text from tabulated body
				intRow = intRow + 1
				intCol = 0
				tblTxt[intRow] = {}
				local strFont,strSpan = strRow:match('(<span class=".-">).+(</span>)')	-- Detect span class font control	-- V3.3
				strFont = strFont or ""
				strSpan = strSpan or "" 
				for strCol in (strRow..strBrk):gmatch('(.-)'..strSep) do			-- Extract each column of text from rows
					intCol = intCol + 1
					strCol = strCol:gsub('<span class=".-">(.-)','%1')
					strCol = strCol:gsub('(.-)</span>','%1')
					tblTxt[intRow][intCol] = strFont..strCol..strSpan				-- Save each text cell per row & column	-- V3.3
					intMax = math.max(intCol,intMax)
				end
			end
			if #tblTxt[1] > #tblTxt[2] then											-- 1st row with more cells than 2nd row	-- V3.3
				for intCol = #tblTxt[1], #tblTxt[2], -1 do
					if tblTxt[1][intCol]:match("^%s-$") then						--	Trim empty cells from end of 1st row	-- V3.3
						tblTxt[1][intCol] = nil
					else
						break
					end
				end
			end
			tblTxt.Big = {}																-- Length of biggest text per column
			for intRow, tblRow in ipairs(tblTxt) do
				for intCol, strCol in ipairs(tblRow) do
					if tblRow[intCol+1] or intCol == intMax then					-- Ignore last column in each row, unless rightmost column in table
						strCol = strCol:gsub('<span class=".-">(.-)</span>','%1')-- Strip down to the actual text	-- V3.3
						local intLen = math.max(1,#strCol)							-- Length of text, but at least 1	Use utf8.len(strCol) ?
						local intBig = tblTxt.Big[intCol] or 0
						if intLen > intBig then
							tblTxt.Big[intCol] = intLen								-- Save biggest length per column
							intSum = intSum - intBig + intLen							-- Sum all biggest lengths
						end
					end
				end
			end
			table.insert(tblFile,'<!-- table head -->')
			if #strHead > 0 then table.insert(tblFile,strHead) end				-- Preserve head tag if any

			local intWidth = 100 / math.ceil( 50 / intSum )						-- V2.4 -- If narrow table, then reduce % width of window
			local strWidth = 'width:'..tostring(intWidth)..'%;'
			for intCol, intWidth in ipairs ( tblTxt.Big ) do
				intWidth = ( intWidth / intSum * 100 )								-- V3.3 -- Calculate % width of column
				strWidth = strWidth..' td.col'..intCol..' {width:'..intWidth..'%}'		 -- Set style class widths for column:  td.col9 {width:99%}
			end
			table.insert(tblFile,' <table class="bord" summary="Table" style="'..strWidth..'">')	-- V2.4 -- Insert opening <table...> tag with style class & widths

			local strStyle = ' border-collapse: collapse; padding: 4px; '		-- V3.3 -- Create table border style settings
			if StrBorder == "ON" then
				strStyle = strStyle..'border: 1px solid; border-color: grey; '
			end
			table.insert(tblFile,' <style>.bord,.bord tr,.bord td { '..strStyle..' }</style>')	-- V3.3 -- Insert table border style class settings

			for intRow, tblRow in ipairs(tblTxt) do
				table.insert(tblFile,'  <tr>')										-- Insert opening <tr> tag per row
				for intCol, strCol in ipairs(tblRow) do
					if tblRow[intCol+1] then											-- V2.4 Insert <td...> tag per col with style class and id
						table.insert(tblFile,'   <td class="col'..intCol..'" id="'..strBrk..'">'..strCol..'</td>')
					else
						if intCol == 1 and strCol:match("^%s-$") then
							strCol = "&nbsp;"											-- If 1st and only column is empty use No Break Space
						end
						local intSpan = #tblTxt.Big - intCol + 1					-- Allow last column in row to span later columns	-- V3.3
						table.insert(tblFile,'   <td colspan="'..intSpan..'" id="">'..strCol..'</td>')
					end
				end
				table.insert(tblFile,'  </tr>')										-- Insert closing </tr> tag per row
			end
			table.insert(tblFile,' </table>')											-- Insert closing </table> tag
			if strTail == '</td>' then
				table.insert(tblFile,strTail)											-- Preserve tail tag
				strLine = '<!-- table tail -->'
			else
				table.insert(tblFile,'<!-- table tail -->')
				strLine = strTail.." "													-- Preserve tail tag
			end
		end
		return strLine
	end -- local function strTabulate

	local function strTableOld(strLine,tblFile,strSep)							-- Handle table conversion for FH V6-	-- V3.3
		-- strLine	~ Line of text
		-- tblFile	~ Table of converted lines
		-- strSep		~ Tab separator
		if strSep then																	-- V2.5 -- Table separator is defined
			strSep = strSep:gsub("…","+")
			strFind = '^(<td.->)(.-)(</td>)$'
			if strLine:match('<br />') and strLine:match(strSep)												-- Convert table separated text
			and not ( strSep == "," and strLine:match('^<td class="FhDat%d" colspan="%d">') ) then		-- unless separator is comma and line in main section
				strLine = strTabulate(tblFile,strSep,strLine:find(strFind))									-- Find component parts of table
			end
		else																				-- V2.5 -- Option "None" reverts table to original line
			if strLine == '<!-- table head -->' then
				tblLine = {}
				table.insert(tblLine," ")												-- Opening <!-- table head --> starts accumulation of lines
				strLine = nil
			elseif #tblLine > 0 then
				if strLine:match('^<td.->$') then
					tblLine[1] = strLine
					strLine = nil
				elseif strLine:match('^ +<td c%l+="%w+" id=".-">.*</td>$') then	-- Found <td class/colspan="..." id="sep">column text</td>	-- V3.3
					local strType,strSep,strText = strLine:match('^ +<td (c%l+)="%w+" id="(.-)">(.*)</td>$')
					table.insert(tblLine,strText..strSep)							-- Accumulate the column text & separator -- V3.3
					if strType == "colspan" then table.insert(tblLine,'<br />') end	-- Last column uses colspan so add break tag <br />
					strLine = nil
				elseif strLine == '</td>' then
					table.insert(tblLine,strLine)
					strLine = nil
				elseif strLine == '<!-- table tail -->' then						-- Closing <!-- table tail --> ends accumulation of lines
					strLine = table.concat(tblLine):gsub("<br /></td>$","</td>")-- Reconstruct the original line
					tblLine = {}
				elseif strLine:match("^ +<") then
					strLine = nil															-- Otherwise remove line
				end
			end
		end
		return strLine
	end -- local function strTableOld

	local function strTableNew(strLine,tblFile,strSep)							-- Handle table conversion for FH V7+	-- V3.3
		-- strLine	~ Line of text
		-- tblFile	~ Table of converted lines
		-- strSep		~ Tab separator
		if strSep then																	-- V2.5 -- Table separator is defined
			strSep = strSep:gsub("…","+")
			strFind = '^(.-)<p>(.-)</p>([^'..strSep..']+)$'
			if strLine:match('<br />') and strLine:match(strSep) then			-- Convert table separated text
				strLine = strTabulate(tblFile,strSep,strLine:find(strFind))		-- Find component parts of table
			end
		else																				-- V2.5 -- Option "None" reverts table to original line
			if strLine == '<!-- table head -->' then
				tblLine = {}
				table.insert(tblLine,"<p>")											-- Opening <!-- table head --> starts accumulation of lines
				strLine = nil
			elseif #tblLine > 0 then
				if strLine:match('^ +<td c%l+="%w+" id=".-">.*</td>$') then		-- Found <td class/colspan="..." id="sep">column text</td>
					local strType,strSep,strText = strLine:match('^ +<td (c%l+)="%w+" id="(.-)">(.*)</td>$')
					table.insert(tblLine,strText..strSep)							-- Accumulate the column text & separator -- V3.3
					if strType == "colspan" then table.insert(tblLine,'<br />') end		-- Last column uses colspan so add break tag <br />
					strLine = nil
				elseif strLine == '<!-- table tail -->' then
					strLine = table.concat(tblLine):gsub("<br />$","</p>")		-- Reconstruct original text but with <br /> line breaks
					tblLine = {}
				elseif strLine:match("^ +<") then
					strLine = nil															-- Otherwise remove line
				end
			end
		end
		return strLine
	end -- local function strTableNew

	-- Process my Locations Database only if 'myloc.html' exists

	local function strMyLoc(strString,tblAnchor,strFolder,strFile)

		local strTarget = tblAnchor.Pages
		local strClass  = tblAnchor.Style

		-- Insert hyperlink <a href='myloc.html'>Locations</a> into standard menubar			e.g. before	<li><span class="fhmenuend">
		strString = strString:gsub('<li><span class="fhmenuend">',"<li><span><a href='myloc.html'>Locations</a></span></li>\n<li><span class='fhmenuend'>")

		if strFile:match('^fam%d+%.html$') or strFile:match('^ind%d+%.html$') then
			-- Convert source location entry into locations database hyperlink					e.g. ~ Database Address ~.  Custom Id: 9999.<	allowing for illegally embedded anchor
			strString = strString:gsub('~ (.-)<a (.-)</a>(.-) ~%.  Custom Id: ([0-9]-)%.<','Locations Database Record <a'..strClass..' href="myloc.html#locsid%4"'..strTarget..'>%1 %3</a> <a %2</a><')
			strString = strString:gsub('~ (.-) ~%.  Custom Id: ([0-9]-)%.<','Locations Database Record <a'..strClass..' href="myloc.html#locsid%2"'..strTarget..'>%1</a><')
		end

		if strFile == StrHomeHTML then												-- V3.0
			-- Change home page ToC hyperlink for Locations database								e.g. from "toc[0-9]-.html" to "myloc.html" -- V3.0
			strString = strString:gsub('^<li><a href="toc[0-9]-.html">Locations(.-)</a></li>$','<li><a href="myloc.html">Locations%1</a></li>')
		end

		if strFile == 'myloc.html' then
			-- Convert <title> to 'Locations Database'												e.g. <title>~ Database Address ~</title>
			strString = strString:gsub('<title>~ .- ~</title>','<title>Locations Database</title>')
			-- Insert 'Locations Database' heading after menubar section before content		e.g. before	<div class="fhcontent ...">
			strString = strString:gsub('<div class="fhcontent (.-)">',"<p class='FhPageTitleCentred'>Locations Database</p>\n<div class='fhcontent %1'>")
			-- Convert >RecordId~ to hyperlink anchor targets										e.g. <h1 class="FhHdg1">[9999] Database Address</h1>
			strString = strString:gsub('<h1 class="FhHdg1">%[([0-9]-)%] (.-)</h1>',"\n<a name='locsid%1' id='locsid%1'></a>\n<h1 class='FhHdg1'>%2</h1>")
			local arrStyleCSS = StrStyleCSS:split("/")								-- V3.0
			local strCustom  = strFolder..'\\'..( arrStyleCSS[1] or "custom" )
			local strMyStyle = strCustom..'\\'..( arrStyleCSS[2] or "mystyle.css" )
			if strString == '<body>' and general.FlgFolderExists(strCustom) then	-- V3.0
				local strFile = 'myimage.jpg'											-- Define 'myimage.jpg' background image file
				local strSource = StrPublic..'\\'..strFile
				local strTarget = strCustom..'\\'..strFile
				general.CopyFile(strSource,strTarget)								-- Copy entire 'myimage.jpg' background image -- V3.3
				if not general.FlgFileExists(strMyStyle) then						-- Define custom CSS style sheet -- V3.0
					local str_mystyle_css = [=[
					body, p, td, li, ul, table      {font-family: Arial, sans-serif; }        /* Select text font family */
					.FhSiteTitle        { font-family: Arial, Helvetica, sans-serif; }
					.FhPageTitle        { font-family: Arial, Helvetica, sans-serif; }
					.FhTOC              { font-family: Arial, Helvetica, sans-serif; }
					.FhHeader           { font-family: Arial, Helvetica, sans-serif; }
					.FhMiniTitle        { font-family: Arial, Helvetica, sans-serif; }
					.FhMiniEntry        { font-family: Arial, Helvetica, sans-serif; }
					.FhHdg1             { font-family: Arial, Helvetica, sans-serif; }
					.FhHdg2             { font-family: Arial, Helvetica, sans-serif; }
					.FhLbl2             { font-family: Arial, Helvetica, sans-serif; }
					.FhDat2             { font-family: Arial, Helvetica, sans-serif; }
					.FhHdg3             { font-family: Arial, Helvetica, sans-serif; }
					.FhLbl3             { font-family: Arial, Helvetica, sans-serif; }
					.FhDat3             { font-family: Arial, Helvetica, sans-serif; }
					.FhCaption          { font-family: Arial, Helvetica, sans-serif; }
					.bodylink           { font-family: Arial, Helvetica, sans-serif; }
					body                { background: url("myimage.jpg") #D8D0BC ; }          /* Background image file or colour */
					.FhSiteTitle        { font-size: 22pt; font-weight: bold; color: green; } /* Title font size, weight & colour */
					.FhPageTitle        { font-size: 20pt; font-weight: bold; color: green; }
					.FhPageTitleCentred { font-size: 20pt; font-weight: bold; color: green; }
					.FhHdg1             { font-size: 16pt; font-weight: bold; color: green; }
					.FhHdg2             { font-size: 12pt; font-weight: bold; color: green; }
					.FhHdg3             { font-size: 10pt; font-weight: bold; color: green; }
					.FhWelcome   form   { text-align: center; }                               /* Needed to centre 'Close Window' button */
					.FhIndexList ul li  { margin-left:10em; }                                 /* Adjust Index of Names surname column */
					]=]
					general.SaveStringToFile(str_mystyle_css,strMyStyle)			-- Create custom CSS style sheet
				end
			end
		end

		return strString
	end -- local function strMyLoc

	-- Determine if my Locations Database needs processing

	local function isMyToC(strFolder,strFile)
		-- If Home page HTML file has '<li><a href="toc[0-9]-.html">Locations...</a></li>' then rename "toc[0-9]-.html" to "myloc.html" and set isMyLoc = true
		local isMyLoc = false
		if strFile == StrHomeHTML then												-- V3.0
			local strLoad = general.StrLoadFromFile(strFolder..'\\'..StrHomeHTML)
			for strLine in strLoad:gmatch("(.-)\r?\n") do							-- Search the Home page file -- V3.3
				local strToC = strLine:match('^<li><a href="(toc[0-9]-.html)">Locations.-</a></li>$')	-- toc[0-9]-	-- V3.0
				if strToC then
					local isOK, strErr = os.rename(strFolder..'\\'..strToC,strFolder..'\\myloc.html')
					isMyLoc = true
					break
				end
			end
		end
		if strFile == 'myloc.html' then isMyLoc = true end
		return isMyLoc
	end -- local function isMyToC

	-- Determine if file is HTML that needs converting
 
	local function isHTML(strFile)
		-- strFile	~ Filename
		return
			strFile == StrHomeHTML 			or											-- Home Welcome page	-- V3.0
			strFile == '_contact.html'		or											-- Contact Details page
			strFile == '_statistics.html'	or											-- Statistics page
			strFile == '_nameindex.html'		or										-- Index of Names page
			strFile:match('^fam%d+%.html$')	or										-- 'fam99.html' Family pages
			strFile:match('^ind%d+%.html$')	or										-- 'ind99.html' Individual pages 
			strFile:match('^toc%d+%.html$')	or										-- 'toc99.html' ToC pages
			strFile == 'myloc.html'														-- 'myloc.html' my Locations Database page
	end -- local function isHTML

	-- Search each HTML file and convert any URL

	progbar.Setup(iup_gui.DialogueAttributes("Bars"))								-- Pass parameters into new Progress Bar prototype
	local intLine = 0																	-- Count of lines with converted URL
	local intFile = 0																	-- Count of suitable HTML files
	local isMyLoc = false
	local datDate = fhNewDate()
	datDate:SetSimpleDate(fhCallBuiltInFunction('Today'))							-- Obtain date for {{DATE:***}}
	DownloadIcons()																		-- Load media icons into ProgramData for {{MEDIA:file|text}} -- V2.8
	local arrFile = general.GetFolderContents(strFolder)
	for _, dicFile in ipairs (arrFile) do											-- V3.3
		local strFile = dicFile.name
		if isMyToC(strFolder,strFile) then isMyLoc = true end						-- Is my Locations Database present?
		if isHTML(strFile) then intFile = intFile + 1 end							-- Count suitable HTML files
	end
	if intFile > 100 then
		progbar.Start("Converting URL",intFile)										-- Start progress bar
	end
	intFile = 0
	for _, dicFile in ipairs (arrFile) do											-- V3.3
		local strFile = dicFile.name
		if isHTML(strFile) then															-- Suitable HTML file found
			intFile = intFile + 1
			if intFile % 23 == 0 then
				progbar.Message("Updating HTML page "..strFile)					-- Reduce rate of messages	-- V3.2
				progbar.Step(23)
				collectgarbage("step",0)												-- Improves run time in loops!	-- V3.2
			end
			strPath = strFolder..'\\'..strFile
			local tblFile = {}															-- Table of lines in file
			local int_Beg = false														-- Index to candidate table lines	-- V3.3
			local isTable = false														-- Converted table indicator			-- V3.3
			local flgSave = false														-- Flag if file needs saving 
			local flgLine = false														-- Flag if line needs converting -- V2.4 ( false/true in <head> or nil/<body> in <body> )
			local strLoad = general.StrLoadFromFile(strPath)
			for strLine in strLoad:gmatch("(.-)\r?\n") do							-- Read each HTML file line by line -- V3.3
				if strLine == '<title>~' then flgLine = ( strFile == 'myloc.html' ) end	-- V2.4 -- Convert <head> <title>~ in myloc.html
				if strLine == '<body>' then flgLine = strLine end					-- V2.4 -- Convert <body> lines otherwise
				if flgLine == '<body>' then											-- V2.4 :-
					if strLine:match('^<div class="FhIndexList">')					-- Exclude <body> Index List in _nameindex.html
					or strLine:match('^<a href=".+_full%.jpg" ')					-- Exclude <body> popup image title -- V2.8
					or strLine:match('<n?o?script') then flgLine = nil end		-- Exclude <body> java script, etc
				end
				if flgLine then															-- In *.html <body> or myloc.html <head>
					local strLink = strHyper(strLine,tblAnchor)						-- Convert anchor hyperlinks
					if strLink:match('{{%u%u%u-:.+}}') then							-- Convert magic DATE & FILE & MEDIA codes -- V2.8
						strLink = strLink:gsub('{{DATE:(.-)}}', function(strQual) return datDate:GetDisplayText(strQual) end )
						strLink = strLink:gsub('{{FILE:NAME}}', encoder.StrANSI_XML(strFile) )
						strLink = strLink:gsub('{{FILE:PATH}}', encoder.StrANSI_XML(strPath) )
						repeat
							local strPrev = strLink
							strLink = strLink:gsub('^(.-){{MEDIA:(.-)}}(.+)$', strMedia )	-- V2.8
						until strPrev == strLink
					end
					if strFile == StrHomeHTML then									-- Optionally insert 'Close Window' button after <div class="FhWelcome"> and mystyle.css needs .FhWelcome form { text-align: center; } -- V3.0
						strLink = strLink:gsub('^<div class="FhWelcome"><p>(.-){{CLOSE}}(.-)</p>$',"<div class='FhWelcome'><p>%1 %2</p>\n<form action='javascript:void(0)'>\n<input type='button' value='"..StrTranslate("Close Window").."' onclick='javascript:window.close()'/>\n</form>")
					end
					if isMyLoc then
						strLink = strMyLoc(strLink,tblAnchor,strFolder,strFile)	-- Convert my Locations Database
						if strLine:match('~</title>') then flgLine = false end	-- V2.4 
					end	
					if		 strLink == "<!-- table head -->" then isTable = true	-- V3.3
					elseif	 strLink == "<!-- table tail -->" then isTable = false
					elseif strTabSep then
						if isTable then													-- Convert hidden tables -- V3.3
							strLink = strLink:gsub("^<!%-%- (.+) %-%->(.-)$","%1%2")
							strLink = strLink:gsub("</?p>$","")
							local strSep = strLink:match('<td c.+" id="(.+)">')
							if strSep then
								strLink = strLink:gsub("(<td .->.+)"..strSep.."$","%1</td>")
							end
						else

						end
						local strSep = strTabSep:gsub("…","+")
						local arrLink = {}
						if strLink:match("<br />") then								-- Split <br /> separated FH V6 lines into paragraphs	-- V3.3
							local strHead,strBody = strLink:match('^(<.->)(.+)$')
							local strBody,strTail = strLink:match('(.+)([</%l>]-)$')
							table.insert(arrLink,strHead)								-- Cater for <tag> prefix
							for strPara in (strBody.."<br />"):gmatch("(.-)<br />") do
								table.insert(arrLink,"<p>"..strPara.."</p>")		-- Add <p> paragraph </p> tags
							end
							table.insert(arrLink,strTail)								-- Cater for <tag> suffix
						else
							table.insert(arrLink,strLink)								-- Else keep original line
						end
						for _, strLink in ipairs (arrLink) do
							if not int_Beg												-- Candidate start of a table	-- V3.3
							and strLink:match("<p>.*"..strSep..".*"..strSep..".*"..strSep..".*</p>$") then
								int_Beg = #tblFile + 1									-- Table conversion candidate	-- V3.3
							elseif not strLink:match("^<p>.*"..strSep..".*</p>[</%l>]-$")
								and strLink ~= "<p>&nbsp;</p>" and strLink ~= "<p></p>" then
								if int_Beg and #tblFile - int_Beg > 2 then			-- Table conversion is possible	-- V3.3
									local strList = ""
									repeat
										strList = strList..table.remove(tblFile,int_Beg)	-- Concatenate the paragraphs	-- V3.3
									until #tblFile < int_Beg
									strLink = strTableNew(strList..strLink,tblFile,strTabSep)
								end
								int_Beg = false
							end
						end
					else

					end

--[=[
					if fhGetAppVersion() > 6 and strFolder:match("Packages") then								-- FH V7 Package table conversion	-- V3.3
						if strTabSep then
							local strSep = strTabSep:gsub("…","+")
							if not int_Beg																				-- Candidate start of a table	-- V3.3
							and strLink:match("<p>.*"..strSep..".*"..strSep..".*"..strSep..".*</p>$") then
								int_Beg = #tblFile + 1																	-- Table conversion candidate	-- V3.3
--!							elseif not strLink:match("^<p>.*"..strSep..".*</p><?/?%l->?$")
							elseif not strLink:match("^<p>.*"..strSep..".*</p>[</%l>]-$")
								and strLink ~= "<p>&nbsp;</p>" then
								if int_Beg then																			-- Table conversion is possible	-- V3.3
									local strList = ""
									repeat
										strList = strList..table.remove(tblFile,int_Beg)							-- Concatenate the paragraphs	-- V3.3
									until #tblFile < int_Beg
									strList = strList:gsub("</p><p>","<br />")
									if strList:match('<br />') and strList:match(strSep) then					-- Convert paragraphs with separator to table
										strLink = strTableNew(strList..strLink,tblFile,strTabSep)
									else
										table.insert(tblFile,strList)													-- Save concatenated paragraphs	-- V3.3
									end
								end
								int_Beg = false
							end
						else
							strLink = strTableNew(strLink,tblFile,strTabSep)										-- Revert table to concatenated paragraphs -- V3.3
						end
					else 
						strLink = strTableOld(strLink,tblFile,strTabSep)											-- V2.5 -- FH V6 Convert tabulated columns (can return nil to remove line)
					end
--]=]
					if strLine ~= strLink then											-- Converted/removed line detected
						strLine = strLink
						if strLine then intLine = intLine + 1 end					-- V2.5 -- Count converted lines but not removed lines
						flgSave = true
					end
				elseif flgLine == nil then												-- V2.4 -- Excluding some <body> tags
					if strLine:match('^</div>')										-- Resume after </div> at end of List
					or strLine:match('^<img src="img')								-- Resume after popup image
					or strLine:match('</n?o?script>') then flgLine = '<body>' end	-- Resume after java script, etc
				else
					if strLine:match("<!DOCTYPE html PUBLIC") then					-- V2.4 -- No need to save if no other lines change
						if tblAnchor.Pages:match("target=") then					-- Workaround for target="_blank"
							strLine = strLine:gsub("Strict","Transitional"):gsub("strict","transitional")-- Alter DOCTYPE XHTML to Transitional
						else
							strLine = strLine:gsub("Transitional","Strict"):gsub("transitional","strict")-- Restore DOCTYPE XHTML to Strict
						end
					end
				end
				table.insert(tblFile,strLine)
			end
			if flgSave then																-- Only save changed HTML files
				general.SaveStringToFile(table.concat(tblFile,'\n'),strPath)
			end
		end
		if progbar.Stop() then break end
	end
	progbar.Close()																		-- Close the Progress Bar
	return intLine
end -- function IntImproveHTML

-- Convert all non-image Media links into Icon JPG links --						-- V2.8

local relFile = "~._FILE"
if fhGetAppVersion() > 6 then relFile = "~.FILE" end								-- FH V7 -- V3.1

function IntMediaIcons()

	local function isNonImageType(strFile)											-- Check if Media has popular image file type or not	-- V3.0
		-- strFile	~ File path
		local dicType = { jpg=1; jpeg=1; png=1; gif=1; tif=1; tiff=1; bmp=1; }
		local _,_,strType = general.SplitFilename(strFile)
		return ( dicType[strType:lower()] ~= 1 )
	end -- local function isNonImageType

	local function isInReports(ptrObje)												-- Check if Media is included in any Reports 	-- V3.0
		-- ptrObje	~ Pointer to media
		local isInReports = false
		local ptrNote = fhGetItemPtr(ptrObje,"~.NOTE2")
		while ptrNote:IsNotNull() do 
			local strExcl = fhGetValueAsText(fhGetItemPtr(ptrNote,"~._EXCL"))
			if not strExcl:match("Reports") then isInReports = true end
			ptrNote:MoveNext("SAME_TAG")
		end
		return isInReports or 	(fhGetAppVersion() > 6)								-- FH V7 _EXCL difficult to find	-- V3.1
	end -- local function isInReports

	local intFile = 0																	-- Count of non-image Media files
	local ptrObje = fhNewItemPtr()
	local intObje = 0																	-- Count of Media Object records	-- V3.0
	progbar.Setup(iup_gui.DialogueAttributes("Bars"))								-- Pass parameters into new Progress Bar prototype
	ptrObje:MoveToFirstRecord("OBJE")
	while ptrObje:IsNotNull() do
		intObje = intObje + 1															-- Count the Media Object records
		ptrObje:MoveNext()
	end
	if intObje > 100 then
		progbar.Start("Preparing non-image Media icons",intObje)					-- Start progress bar	-- V3.0
	end
	DownloadIcons()																		-- Load icons into ProgramData folder
	ptrObje:MoveToFirstRecord("OBJE")													-- Search every Media record
	while ptrObje:IsNotNull() do
		local ptrFile = fhGetItemPtr(ptrObje,relFile)								-- FH V7 "~.FILE" or FH V6 "~._FILE" -- V3.1
		while ptrFile:IsNotNull() do
			local strFile = fhGetValueAsText(ptrFile)								-- If relative Media path then make absolute
			local getFile = strFile:gsub("^Media\\",function() return iup_gui.FhDataPath.."\\Media\\" end) -- V3.2 -- V3.3
			if #getFile > 0 and general.FlgFileExists(getFile)
			and isNonImageType(getFile) and isInReports(ptrObje) then			-- File exists with non-image extension	-- V3.0
				local getImage, intErr = im.FileImageLoad(getFile)				-- Try to load image from Media file
				if intErr and intErr ~= im.ERR_NONE then							-- If errors then got non-image file
					local isOK = false
					local ptrForm = fhGetItemPtr(ptrObje,"~.FORM")										-- FH V6 OBJE.FORM		-- V3.1
					if fhGetAppVersion() > 6 then ptrForm = fhGetItemPtr(ptrFile,"~.FORM") end	-- FH V7 OBJE.FILE.FORM	-- V3.1
					local strForm = fhGetValueAsText(ptrForm)
					local ptrChan = fhGetItemPtr(ptrObje,"~.CHAN")
					if ptrChan:IsNull() then ptrChan = fhCreateItem("CHAN",ptrObje,true) end
					local ptrNote = fhCreateItem("NOTE2",ptrChan,true)			-- FH V7 Last Change Note instance per File -- V3.1
					if ptrNote:IsNotNull() then										-- Save old Format & File in new Last Change Note
						isOK = fhSetValueAsText(ptrNote,"{{FORM}}"..strForm.."{{FILE}}"..strFile)
						isOK = fhSetValueAsText(ptrForm,"jpg")						-- Substitute ProgramData icon file
						isOK = fhSetValueAsText(ptrFile,iup_gui.MachinePath.."\\"..StrIconName(strForm))
						intFile = intFile + 1
					end
					progbar.Message(" Record Id: "..fhGetRecordId(ptrObje))		-- V3.0
				else
					getImage:Destroy()													-- Otherwise it was an image file so remove image buffer
				end
				fhSleep(5,5)																-- Avoid not responding state -- V3.0
			end
			ptrFile:MoveNext("SAME_TAG")
		end
		ptrObje:MoveNext()
		progbar.Step(1)																	-- V3.0
		if progbar.Stop() then break end
	end
	progbar.Close()																		-- Close the Progress Bar -- V3.0
	return intFile
end -- function IntMediaIcons

-- Convert all image Popups in every required HTML Web/CD/DVD page --

function IntImprovePopup(strFolder,strPopup)
	-- strFolder	~ Website HTML folder
	-- strPopup	~ Popup version option

	-- Update Media records with non-image file and copy to webpage folder --	-- V2.8

	local arrMedia = {}

	local function intNonImageMedia()
		local strPref = "_"
		if general.FlgFolderExists(strFolder.."\\media") then						-- Prefer \_media\ unless \media\ sub-folder exists
			strPref = ""
		end
		local intObje = 0
		local ptrObje = fhNewItemPtr()
		ptrObje:MoveToFirstRecord("OBJE")												-- Search every Media record
		while ptrObje:IsNotNull() do
			local ptrFile = fhGetItemPtr(ptrObje,relFile)							-- FH V7 "~.FILE" or FH V6 "~._FILE" -- V3.1
			while ptrFile:IsNotNull() do
				local strFile = fhGetValueAsText(ptrFile)
				if strFile:match(iup_gui.MachinePath.."\\improve_%l+_icon%.jpg$") then			-- Found icon image Media
					local ptrForm = fhGetItemPtr(ptrObje,"~.FORM")										-- FH V6 OBJE.FORM		-- V3.1
					if fhGetAppVersion() > 6 then ptrForm = fhGetItemPtr(ptrFile,"~.FORM") end	-- FH V7 OBJE.FILE.FORM	-- V3.1
					local ptrNote = fhGetItemPtr(ptrObje,"~.CHAN.NOTE2")								-- FH V7 Scan Last Change Notes	-- V3.1
					while ptrNote:IsNotNull() do
						local strForm,strFile = fhGetValueAsText(ptrNote):match("^{{FORM}}(.+){{FILE}}(.+)")
						if strForm and strFile then
							local isOK = fhSetValueAsText(ptrForm,strForm)			-- Restore original Format & File
							local isOK = fhSetValueAsText(ptrFile,strFile)			-- FH V7 -- V3.1
							local isOK = fhDeleteItem(ptrNote)
							local strSource, strTarget
							if strFile:match("^Media\\") then
								strSource = iup_gui.FhDataPath.."\\"..strFile		-- Relative file path needs absolute source
							else
								local _, strName = general.SplitFilename(strFile)	-- Absolute file path needs relative URL path
								strSource = strFile
								strFile = "media\\"..strName							-- Add media sub-folder to file Name	-- V3.2
							end
							strFile = (strPref..strFile):lower( ):gsub("%s","_")	-- Convert into URL file path format	-- V3.2
							strTarget = strFolder.."\\"..strFile						-- Optional underscore folder prefix	-- V3.2
							strFile = encoder.StrUTF8_URI(strFile)					-- or StrUTF8_XML ? -- V3.3
							strFile = strFile:gsub("%%5C","/")
							if  general.FlgFileExists(strSource) and
							not general.FlgFileExists(strTarget) then 				-- Source file exists but Target file does not
								if strSource:match("%.url$") then
									strFile = general.StrLoadFromFile(strSource):match("\nURL=(.-)\n")	-- Extract URL from shortcut
								else
									general.CopyFile(strSource,strTarget)			-- V3.3
								end
							end
							local intRid = fhGetRecordId(ptrObje)					-- Save target File path against Rec Id for strAnchor()
							arrMedia[tostring(intRid)] = arrMedia[tostring(intRid)] or strFile	-- Only save 1st non-image File path in FH V7 -- V3.1
							break
						end
						ptrNote:MoveNext("SAME_TAG")									-- FH V7 Search Last Change Note instances	-- V3.1
					end
					intObje = intObje + 1
				end
				ptrFile:MoveNext("SAME_TAG")
			end
			ptrObje:MoveNext()
		end
		return intObje
	end -- local function intNonImageMedia

	-- Convert any anchor tag Popups --

	local function strAnchor(strLine,strPopup,strName)							-- V2.4 entirely rewritten
		-- strLine	~ Current text line
		-- strPopup	~ Popup version option
		-- strName	~ Name of popup id
		local intLine = 0
		if strLine:match('^<[a!]%-- href="') then									-- Found popup anchor/comment tag 
			strLine = strLine:gsub('^<!%-- href=(".+%p) %--> <a title=(".+)','<a href=%1 title=%2')	-- Convert hidden popup to normal
			local strFile = strLine:match('^<a href="([^%.]-)" ')
			if strFile then																-- File name has no file type extension
				local strPath = strFolder..'\\'..strFile..'.'
				for intType, strType in ipairs ( { 'jpg'; 'jpeg'; 'bmp'; 'gif'; 'pcx'; 'png'; 'tga'; 'tif'; 'tiff'; 'wmf'; } ) do
					if general.FlgFileExists(strPath..strType) then				-- Found file with matching type extension
						strLine = strLine:replace('<a href="'..strFile..'" ','<a href="'..strFile..'.'..strType..'" ')
						break
					end
				end
			end
			local strFile, strRid = strLine:match('^<a href="(img(%d+).-_full%.jpg)" ')	-- V3.2
			local strMedia = arrMedia[strRid]
			local int_h1_ = 0															-- Cater for Home Welcome page image prefix	-- V3.0
			strLine, int_h1_ = strLine:gsub('^<a href="_h1_','<a href="img_')
			if strMedia then																-- Convert popup to non-image anchor	-- V2.8
				strLine, intLine = strLine:gsub('^<a href="img.+%.jpg" %l+=.+ title=',function() return '<a href="'..strMedia..'" title=' end)
				general.DeleteFile(strFolder..'\\'..strFile)
			elseif strPopup:match("Lytebox") then									-- Convert popup to lytebox anchor
				strLine, intLine = strLine:gsub('^<a href=("img.+%.%l+") %l+=.+ title=','<a href=%1 rel="lytebox" title=')
			elseif strPopup:match("Custom") then										-- Convert popup to fhpopup anchor
				strLine, intLine = strLine:gsub('^<a href=("img.+%.%l+") %l+=.+ title=','<a href=%1 id='..strName.." onclick='fhpopup("..strName..");return false;' title=")
			else																			-- Hide all except the popup title
				strLine, intLine = strLine:gsub('^<a href=("img.+%p) title=(".+)','<!-- href=%1 --> <a title=%2')
			end
			if int_h1_ > 0 then
				strLine = strLine:gsub(' href="img_',' href="_h1_')				-- Restore the Home Welcome page image prefix	-- V3.0
			end
		else
			local strRid = strLine:match('^<img src="img(%d+)%-')					-- Adjust <img src="img line for non-image Media	-- V2.8
			if arrMedia[strRid] then
				strLine, intLine = strLine:gsub(' alt="picture" ',' alt="media" ')
			end
		end
		return strLine, intLine > 0 
	end -- local function strAnchor

	-- Determine if file is HTML that needs popup conversion
 
	local function isHTML(strFile)
		-- strFile	~ Filename
		return
			strFile == StrHomeHTML 				or										-- Home Welcome page	-- V3.0
			strFile:match('^fam%d+%.html$')	or										-- 'fam99.html' Family pages
			strFile:match('^ind%d+%.html$')	or										-- 'ind99.html' Individual pages 
			strFile:match('^toc%d+%.html$')	or										-- 'toc99.html' ToC pages
			strFile == 'myloc.html'														-- 'myloc.html' my Locations Database page
	end -- local function isHTML

	-- Search each HTML file and convert any Popups --

	local str_fhstyle_css = '<link rel="stylesheet" type="text/css" href="fhstyle.css" />'	-- V2.4 -- Significant <head> lines
	local str_lytebox_css = '<link rel="stylesheet" href="lytebox.css" type="text/css" media="screen" />'
	local str_lytebox_js  = '<script type="text/javascript" src="lytebox.js"></script>'		-- V2.4 
	local str_fhpopup_js  = '<script type="text/javascript" src="fhpopup.js"></script>'		-- V2.4 
	local tblHead = {}																	-- V2.4 -- Table & count of <head> lines needed for fhpopup 
	local intHead = 0
	local intEdit = 0																	-- Count of non-image Media and HTML file changes
	local intFile = 0																	-- Count of suitable HTML files
	local isBarStop
	progbar.Setup(iup_gui.DialogueAttributes("Bars"))								-- Pass parameters into new Progress Bar prototype
	local arrFile = general.GetFolderContents(strFolder)
	for _, dicFile in ipairs (arrFile) do											-- V3.3
		local strFile = dicFile.name
		if isHTML(strFile) then intFile = intFile + 1 end							-- Count suitable HTML files
	end
	if intFile > 100 then
		progbar.Start("Converting Popups",intFile)									-- Start progress bar
	end
	intFile = 0
	intEdit = intNonImageMedia()														-- Count of non-image Media records changed -- V2.8
	for _, dicFile in ipairs (arrFile) do											-- V3.3
		local strFile = dicFile.name
		if isHTML(strFile) then															-- Suitable HTML file found
			intFile = intFile + 1
			if intFile % 23 == 0 then
				progbar.Message("Updating HTML page "..strFile)					-- Reduce rate of messages	-- V3.2
				progbar.Step(23)
				collectgarbage("step",0)												-- Improves run time in loops!	-- V3.2
			end
			strFile = strFolder..'\\'..strFile
			local strLoad = general.StrLoadFromFile(strFile)
			local tblFile = {}															-- Table of lines in file
			local intHref = 0															-- Count of popup per file for href id
			local flgHead = true														-- Flag if line in <head> ( else <body> )
			intHead = 0
			for strLine in strLoad:gmatch("(.-)\r?\n") do							-- Read each HTML file line by line -- V3.3
				if strLine == '</head>' then flgHead = false end
				if flgHead then															-- Adjust lines in <head>
					if strLine:match(str_fhstyle_css) then							-- V3.1 -- FH V7 CSS line not on new line !!!!
						intHead = 1
						if strPopup:match("Lytebox") then								-- V2.4 -- Insert lytebox header lines
							table.insert(tblFile,str_lytebox_js)
							table.insert(tblFile,str_lytebox_css)
						elseif strPopup:match("Custom") then							-- V2.4 -- Insert fhpopup header line
							table.insert(tblFile,str_fhpopup_js)
						end
					end
					if strLine == str_lytebox_css
					or strLine == str_lytebox_js
					or strLine == str_fhpopup_js then									-- V2.4 -- Remove existing lytebox/fhpopup header lines
						strLine = ''
					elseif intHead > #tblHead then									-- V2.4 -- Save <head> line needed for fhpopup
						table.insert(tblHead,"	 openwindow.document.writeln('  "..strLine.."');")
						intHead = intHead + 1
					end
				else
					local strHref, flgLine = strAnchor(strLine,strPopup,'"fh'..intHref..'"',strFile)	-- Convert popup anchor in <body>
					if flgLine then
						strLine = strHref
						intHref = intHref + 1											-- Count popup per file for href id
					end
				end
				if strLine ~= '' then table.insert(tblFile,strLine) end
			end
			if intHref > 0 then															-- V2.4
				local strSave = table.concat(tblFile,'\n')							-- V3.2
				if strLoad ~= strSave then
					intEdit = intEdit + 1												-- Count changed HTML files	-- V3.2
					general.SaveStringToFile(strSave,strFile)						-- Save changed HTML files
				end
			end
		end
		isBarStop = progbar.Stop()
		if isBarStop then break end
	end
	progbar.Close()																		-- Close the Progress Bar
	-- Change the JavaScript and CSS files
	local strLytebox = '\\Family Historian\\Web\\Lytebox'							-- Locate the C:\Program Files\Family Historian\Web\Lytebox path
	local strProgram = os.getenv("PROGRAMFILES")..strLytebox
	if not general.FlgFolderExists(strProgram) then								-- Try alternative Program Files OS Path on 64-bit PC
		strProgram = ( os.getenv("PROGRAMW6432") or os.getenv("PROGRAMFILES") )..strLytebox
	end
	if not general.FlgFolderExists(strProgram) then
		iup_gui.MemoDialogue('Error! Cannot find Lytebox installation folder:\n'..strProgram)
		return -1
	end
	if not isBarStop then																-- V2.4 Delete the Lytebox & fhpopup files -- V3.3
		if not strPopup:match("Lytebox") then
			local arrFile = general.GetFolderContents(strProgram)
			for _, dicFile in ipairs (arrFile) do									-- V3.3
				local strFile = dicFile.name
				if strFile:match('^[%w_]+%.%w+$') then
					intEdit = intEdit + IntDeleteFile(strFolder..'\\'..strFile)
				end
			end
		end
		if not strPopup:match("Custom") then
			intEdit = intEdit + IntDeleteFile(strFolder..'\\fhpopup.js')
		end
		if not strPopup:match("Dojo Zoomer") then
			intEdit = intEdit + IntDeleteFile(strFolder..'\\dojopop.png')
			intEdit = intEdit + IntDeleteFile(strFolder..'\\dojopop.css')
			intEdit = intEdit + IntDeleteFile(strFolder..'\\dojopop.js')
			intEdit = intEdit + IntDeleteFile(strFolder..'\\dojosrc.js')
		end
	end
	if strPopup:match("Lytebox") then 												-- Copy lytebox v4.0 JavaScript & CSS & image files
		local arrFile = general.GetFolderContents(strProgram)
		for _, dicFile in ipairs (arrFile) do										-- V3.3
			local strFile = dicFile.name
			if strFile:match('^[%w_]+%.%w+$') then
				if strPopup:match("4.0") or not strFile:match("lytebox") then	-- Copy entire file contents	-- V3.3
					local strLoad = general.StrLoadFromFile(strProgram..'\\'..strFile)
					intEdit = intEdit + IntUpdateFile(strLoad,strFolder..'\\'..strFile)
				end
			end
		end
		if strPopup:match("5.5") then													-- Create lytebox v5.5 JavaScript & CSS files
			intEdit = intEdit + WriteDecodedFile(Str_lytebox_js,strFolder..'\\lytebox.js')
			intEdit = intEdit + WriteDecodedFile(Str_lytebox_css,strFolder..'\\lytebox.css')	-- Decode text for files	-- V3.3
		end
	elseif strPopup:match("Custom") then												-- V2.4 
		local str_fhpopup = ""
		if strPopup:match("Zoom & Scroll") then										-- Create the fhpopup Custom JavaScript file
			str_fhpopup = Str_fhpopup_custom
		elseif strPopup:match("Large Screen") then									-- Create the fhpopup Screen JavaScript file
			str_fhpopup = Str_fhpopup_screen
		elseif strPopup:match("Dojo Zoomer") then									-- Create the fhpopup Zoomer JavaScript files
			str_fhpopup = Str_fhpopup_zoomer
			intEdit = intEdit + WriteDecodedFile(Str_dojopop_css,strFolder..'\\dojopop.css')	-- Decode text for files	-- V3.3
			intEdit = intEdit + WriteDecodedFile(Str_dojopop_js ,strFolder..'\\dojopop.js')
			intEdit = intEdit + WriteDecodedFile(Str_dojosrc_js ,strFolder..'\\dojosrc.js')
			local strOrigin = iup_gui.MachinePath..'\\improve_dojopop.png'
			local strTarget = strFolder..'\\dojopop.png'
			if not general.FlgFileExists(strOrigin) then
				StrDecodedText(Str_dojopop_png,strOrigin)							-- Decode dojo image file	-- V3.3
			end
			if not general.FlgFileExists(strTarget) then
				general.CopyFile(strOrigin,strTarget)								-- V3.3
				intEdit = intEdit + 1
			end
		end
		str_fhpopup = StrDecodedText(str_fhpopup)									-- Decode text for files	-- V3.3
		str_fhpopup = str_fhpopup:gsub("{HEAD}",table.concat(tblHead,"\n"))	-- Insert the <head> lines from HTML files
		intEdit = intEdit + IntUpdateFile(str_fhpopup,strFolder..'\\fhpopup.js')	-- Create the fhpopup JavaScript file
	end

	return intEdit
end -- function IntImprovePopup

-- Insert GEDmill minitrees into each Individual/Family featured HTML Web/CD/DVD page --	-- V3.2

function IntAddMiniTrees(strFolder)
	-- strFolder	~ Website HTML folder
	local dicSpou = {}																	-- Spouses for each Family
	local dicHref = {}																	-- Minitree href page filename translations (needs in depth efficiency review and cope with same-sex partners, etc)
	local intFile = 0																	-- Count of feature page HTML files
	local intStep = 0
	local strOrig = nil 																-- Original page file text to identify updates
	local strTree = strFolder..'\\_trees'											-- Subfolder to hold minitree gif/png files -- V3.3
	local strGEDmill = ''																-- GEDmill product output working folder
	local strGEDmillProg = "\\Logic Mill\\GEDmill 1.11.0\\GEDmill.exe"
	local strGEDmillPath = ( os.getenv("PROGRAMFILES") or "?" )..strGEDmillProg	-- GEDmill program executable path
	if not general.FlgFileExists(strGEDmillPath) then
		strGEDmillPath = ( os.getenv("PROGRAMW6432") or "?" )..strGEDmillProg
	end

	local strProject = StrPublic:gsub('\\Public$','')								-- Project folder
	local arrFile = general.GetFolderContents(strProject,true)
	for _, dicFile in ipairs (arrFile) do											-- V3.3
		if dicFile.mode == 'directory' and dicFile.name == 'GEDmill_Output' then	-- Find GEDmill_Output folder anywhere in Project
			strGEDmill = dicFile.path..'\\'
			break
		end
	end
	if strGEDmill == '' then								 							-- GEDmill_Output folder missing
		if general.FlgFileExists(strGEDmillPath) then
			if 1 == iup_gui.WarnDialogue("GEDmill_Output folder missing","\n Error!  Cannot find the GEDmill_Output folder of minitrees. \n\n Do you want to run the GEDmill program to produce the family tree diagrams? \n\n"," Yes Run "," No Quit ") then
				general.DoExecute(strGEDmillPath)
			end
		else
			iup_gui.WarnDialogue("GEDmill_Output folder missing","\n Error!  Cannot find the GEDmill_Output folder of minitrees. \n\n You need to install and run the GEDmill program as per the 'Help && Advice' guide. \n\n")
		end
		return -1
	end

	-- Transform GEDmill minitree into FH compatible format and insert into feature page HTML file

	local function addMiniTree(strSource,strFamHref,strPage,strType,intGsub)	-- Insert GEDmill minitree and adjust HTML script
		-- strSource	~ GEDmill indiI%d+.html file holding minitree
		-- strFamHref~ Current family page Href fam%d+.html featured page or ""
		-- strPage	~ Content of ind/fam%d+.html featured page
		-- strType	~ "Individual" or "1stPartner" or "2ndPartner"
		-- intGsub	~ 1 or 1 or 2 = number of headings to gsub
		if not strSource then return strPage end
		strSource = fhConvertUTF8toANSI(strGEDmill..strSource)					-- Ensure source html file exists
		if not general.FlgFileExists(strSource) then return strPage end
		local strTree = general.StrLoadFromFile(strSource):match('\n +<div id="minitree".- </div>')	-- Extract minitree from GEDmill_Output html file
		local dicType = {["Individual"]="";["1stPartner"]="2ndPartner";["2ndPartner"]="1stPartner";}	-- Translate from one strType to the other
		local dicUseHref = {}															-- Href already used per person on page

		local function getNewHref(strOldHref)										-- Lookup appropriate feature page Href
			-- strOldHref	~ Href to translate
			local dicOldHref = dicHref[strOldHref]
			if not dicOldHref then return strOldHref end							-- Keep old Href in case of missing data error 
			local strNewHref = dicOldHref['INDI']									-- Use individual Href if possible
			if not strNewHref then
				for _, strSpouHref in ipairs ( dicOldHref['SPOU'] or {} ) do	-- Use as many different spouse Hrefs as possible for multiple spouse boxes
					strNewHref = strSpouHref or dicOldHref['CHIL'][1] or strOldHref
					if strNewHref ~= strFamHref and strNewHref ~= dicUseHref[strOldHref] then	-- Use this Href if not current family page nor already used by this spouse
						break
					end
				end
				if strNewHref then
					if strNewHref == strFamHref										-- Href to current family page?
					or strNewHref == dicUseHref[strOldHref] then					-- Href already used by spouse?
						strNewHref = '#minitree'..dicType[strType]					-- Link to other minitree
					end
					dicUseHref[strOldHref] = strNewHref								-- Save Href used by this spouse
				else
					strNewHref = '#minitree'..strType									-- Link to same minitree
				end
			end
			return strNewHref
		end -- local function getNewHref

		strTree = strTree:gsub( '\n +', '\n' )										-- Remove leading spaces

		strTree = strTree:gsub( '(indiI%d+%.html)', getNewHref )					-- Replace each "indiI%d+.html" with feature page Href

		strTree = strTree:gsub( 'src="treeI', 'src="_trees/treeI' )				-- Adjust path to minitree .gif/.png image file

		if StrMini == "OFF" then
			strTree = strTree:gsub( '(<div id="minitree[^\n]-px;)">', '%1text-align:center;">' )	-- Add text-align:center
		else
			strTree = strTree:gsub( '(<div id="minitree[^\n]-px;)text%-align:center;">', '%1">' )	-- Remove text-align:center
		end

		if strType == "Individual" then												-- Insert Individual minitree into feature page
			strPage = strPage:gsub( '(<h1 class="FhHdg1">[^\n]-</h1>).-(\n<[dtp]%l- class=.->)', '%1'..strTree:inert()..'%2', intGsub ) -- Cater for <div or <table or <p class
		else
			strTree = strTree:gsub( '(<div id="minitree)"', '%1'..strType..'"', 1 )	-- Give the minitree a unique id and name 
			strTree = strTree:gsub( '"(#?)treeMap"', '"%1treeMap'..strType..'"', 2 )	-- Insert Husband/Wife/Partner: minitree into family page, but not Child 9: or Note from ...:
			strPage = strPage:gsub( '(<h2 class="FhHdg2">[^\n]-</h2>).-(\n<[dtp]%l- class.->)', '%1'..strTree:inert()..'%2', intGsub ) -- Cater for <div or <table or <p class
		end
		local strSee, strRef = strPage:match('<div class="FhSeeAlso">\n(.-)\n<ul>\n(.-\n</ul>)\n</div>')
		if strSee and strRef then														-- Found 'See also' section
			if StrAlso == "OFF" then
				if  not strRef:match( '<li><a href=' )
				and not strSee:match( '<!%-- <p>.-</p> %-->') then				-- Cater for Map Life Facts <li><a href= Map of Locations for link
					strSee = strSee:gsub( '(<p>.-</p>)', '<!-- %1 -->', 1 )		-- Hide <p>See also</p> section
				end
				strRef = strRef:gsub( '(<li>[^<].-</a></li>\n)(<[^l])', '<!-- \n%1 -->\n%2', 1 )	-- Hide See also section list items
			else
				strSee = strSee:gsub( '<!%-- (<p>.-</p>) %-->', '%1', 1 )
				strRef = strRef:gsub( '<!%-- \n(<li>.-</a></li>\n) %-->\n', '%1', 1 )		-- Retain See also section list items
			end
			strPage = strPage:gsub( '(<div class="FhSeeAlso">\n).-\n</ul>(\n</div>)', '%1'..strSee:inert()..'\n<ul>\n'..strRef:inert()..'%2', 1 )
		end
		return strPage
	end -- local function addMiniTree

	local arrFile = general.GetFolderContents(strFolder)
	for _, dicFile in ipairs (arrFile) do											-- V3.3
		local strFile = dicFile.name
		if strFile:match( '^ind%d+.html$' ) then									-- For each ind%d+.html file create new href entry for indiviudal
			local strHref = strFile:gsub( '^ind', 'indiI' )
			dicHref[strHref] = { INDI=strFile }
			intFile = intFile + 1
		elseif strFile:match( '^fam%d+.html$' ) then								-- For each fam%d+.html file create new href entries for HUSB, WIFE & CHIL
			intFile = intFile + 1
			local ptrFam = fhNewItemPtr()
			ptrFam:MoveToRecordById( 'FAM', tonumber(strFile:match( '^fam(%d+)' )) )	-- Lookup Family record with this Record Id
			ptrFam:MoveToFirstChildItem(ptrFam) 
			while ptrFam:IsNotNull() do
				local strTag = fhGetTag(ptrFam)
				if ('HUSB WIFE CHIL'):match( strTag ) then							-- For each HUSB, WIFE, CHIL RecId create href entries
					local intRid = fhGetRecordId( fhGetValueAsLink(ptrFam) )
					local strHref = 'indiI'..tostring(intRid)..'.html'
					if strTag ~= 'CHIL' then											-- Add HUSB/WIFE to spouse list
						dicSpou[strFile] = dicSpou[strFile] or {}
						table.insert( dicSpou[strFile], strHref )					-- Copes with single parents and same-sex partners
						strTag = "SPOU"
					end
					if not ( dicHref[strHref] and dicHref[strHref]['INDI'] ) then	-- No [indiI%d+.html]['INDI'] Href so no ind%d+.html file
						dicHref[strHref] = dicHref[strHref] or {}
						dicHref[strHref][strTag] = dicHref[strHref][strTag] or {}
						table.insert(dicHref[strHref][strTag],strFile)				-- Add SPOU or CHIL Href to person list
					end
				end
				ptrFam:MoveNext()
			end
		end
	end

	progbar.Setup(iup_gui.DialogueAttributes("Bars"))								-- Pass parameters into new Progress Bar prototype
	if intFile > 100 then
		progbar.Start( "Inserting Minitrees", intFile + math.floor(intFile/10) )	-- Start progress bar
		progbar.Message("Managing minitree images (please wait)")
		progbar.Step( math.floor(intFile/20) )
		fhSleep(5,0)
	end
	intFile = 0

	if general.FlgFolderExists( strTree ) then										-- Minitrees _trees subfolder exists -- V3.3
		local arrFile = general.GetFolderContents(strTree)
		for _, dicFile in ipairs (arrFile) do										-- V3.3
			local strFile = dicFile.name
			if strFile:match( '^treeI%d+' ) then
				local intTimeT = general.IntTime(dicFile.modified)				-- Modified date of _trees file -- V3.3
				local dicAttr  = general.FSO:GetFile(strGEDmill..strFile)
				local intTimeG = general.IntTime(dicAttr.DateLastModified or "00/00/00 00:00:00")	-- Modified date of GEDmill file or 0 if different file type -- V3.3
				if intTimeT ~= intTimeG then											-- They differ
					general.FSO:DeleteFile(strTree..'\\treeI*.*')					-- Delete any old minitrees (fails if no files) -- V3.3
					intFile = 0
					break
				end
				intFile = intFile + 1													-- Same dates so avoid copying especially when thousands of minitrees
				if intFile > 99 then break end										-- Halt after checking 100 tree files
			end
		end
	else
		general.MakeFolder( strTree )													-- Create empty _trees subfolder -- V3.3
	end
	progbar.Step( math.floor(intFile/20) )
	fhSleep(5,0)
	if intFile == 0 then
		general.CopyFile( strGEDmill..'treeI*.*', strTree )						-- Copy minitrees from GEDmill_Output to _trees subfolder -- V3.3
	end
	intFile = 0

	local arrFile = general.GetFolderContents(strFolder)
	for _, dicFile in ipairs (arrFile) do											-- V3.3
		local strFile = dicFile.name
		if strFile:match( '^ind%d+.html$' )
		or strFile:match( '^fam%d+.html$' ) then									-- For each feature file update minitrees
			intStep = intStep + 1
			if intStep % 23 == 0 then
				progbar.Message("Updating feature page "..strFile)
				progbar.Step(23)
				collectgarbage("step",0)												-- Improves run time in loops!
			end
			local strPath = strFolder.."\\"..strFile
			local strPage = general.StrLoadFromFile(strPath)
			local strOrig = strPage
			if strFile:match( '^ind' ) then											-- For each ind%d+.html file update individual minitree
				strPage = addMiniTree( strFile:gsub( '^ind(%d)', 'indiI%1' ), "", strPage, "Individual", 1 )
			else
				if dicSpou[strFile] then																			-- For each fam%d+.html file update appropriate individual minitree(s)
					strPage = addMiniTree( dicSpou[strFile][2], strFile, strPage, "2ndPartner", 2 )		-- 2nd Partner or Wife and gsub 2 FhHdg2 entries
					strPage = addMiniTree( dicSpou[strFile][1], strFile, strPage, "1stPartner", 1 )		-- 1st Partner or Husband, gsub 1 FhHdg2 entry
				end
			end
			if strPage ~= strOrig then													-- Page file has changed
				intFile = intFile + 1
				general.SaveStringToFile(strPage,strPath)
			end
			if progbar.Stop() then break end
		end
	end
	progbar.Close()																		-- Close the Progress Bar

	return intFile
end -- function IntAddMiniTrees

-- Remove GEDmill minitrees from each Individual/Family featured HTML Web/CD/DVD page --	-- V3.2

function IntRemMiniTrees(strFolder)
	-- strFolder	~ Website HTML folder
	local intFile = 0																	-- Count of feature page HTML files
	local intStep = 0

	local arrFile = general.GetFolderContents(strFolder)
	for _, dicFile in ipairs (arrFile) do											-- V3.3
		local strFile = dicFile.name
		if strFile:match( '^ind%d+.html$' )
		or strFile:match( '^fam%d+.html$' ) then									-- Count feature page files
			intFile = intFile + 1
		end
	end

	progbar.Setup(iup_gui.DialogueAttributes("Bars"))								-- Pass parameters into new Progress Bar prototype
	if intFile > 100 then
		progbar.Start("Removing Minitrees",intFile)									-- Start progress bar
	end
	intFile = 0

	for _, dicFile in ipairs (arrFile) do											-- V3.3
		local strFile = dicFile.name
		if strFile:match( '^ind%d+.html$' ) 											-- For each feature file remove minitrees
		or strFile:match( '^fam%d+.html$' ) then
			intStep = intStep + 1
			if intStep % 23 == 0 then
				progbar.Message("Updating feature page "..strFile)
				progbar.Step(23)
				collectgarbage("step",0)												-- Improves run time in loops!
			end
			local strTarget = strFolder.."\\"..strFile
			local strPage = general.StrLoadFromFile(strTarget)					-- Reveal 'See also' and remove minitrees
			local strOrig = strPage
			local strSee, strRef = strPage:match('<div class="FhSeeAlso">\n(.-)\n<ul>\n(.-)\n</ul>\n</div>')
			if strSee and strRef then													-- Found 'See also' section to reveal
				strSee = strSee:gsub( '<!%-- (<p>.-</p>) %-->', '%1', 1 )
				strRef = strRef:gsub( '<!%-- \n', '', 1 )
				strRef = strRef:gsub( '\n %-->' , '', 1 )
				strPage = strPage:gsub( '(<div class="FhSeeAlso">\n).-(\n</ul>\n</div>)', '%1'..strSee:inert()..'\n<ul>\n'..strRef:inert()..'%2', 1 )
			end
			-- Remove minitrees and cater for <h1 or <h2 and <div or <table or <p class
			strPage = strPage:gsub( '(<h[12] class="FhHdg[12]">[^\n]-</h[12]>)\n -<div id="minitree.-</div>(\n<[dtp]%l- class.->)', '%1%2', 2 )

			if strOrig ~= strPage then
				general.SaveStringToFile(strPage,strTarget)
				intFile = intFile + 1
			end
		end
		if progbar.Stop() then break end
	end
	progbar.Close()																		-- Close the Progress Bar

	return intFile
end -- function IntRemMiniTrees

-- Create new Table of Pictures/Reports/Downloads pages for chosen Contents items --

function IntImproveTable(strFolder,tglToPs,tglToRs,tglToDs,isMenu)
	-- strFolder	~ Website HTML folder
	-- tglToPs	~ Toggle control for Pictures
	-- tglToRs	~ Toggle control for Reports
	-- tglToDs	~ Toggle control for Downloads
	-- isMenu 	~ Include links in Menu Bar?

	-- Insert HTML line into every table page file --

	local function tableInsert(tblTables,strLine)
		-- tblTables	~ Table translation values
		-- strLine	~ Current text line
		for intTable, tblTable in ipairs(tblTables) do
			local strLine = strLine:replace("<tblTable.name>",tblTable.name)	-- Substitute table page name in title lines 
			table.insert(tblTable.html,strLine)
		end
	end -- local function tableInsert

	-- Does ToC link refer to required Picture/Report/Download file --

	local function isTableLink(tblTable,strLink)
		-- tblTable	~ Table parameters
		-- strLink	~ Table link
		if tblTable.name == StrTranslate("Downloads") then						-- Table of Downloads link cannot be .html file	-- V3.2
			return tblTable.chosen and not strLink:match("^<li><a href=%p%l%l%l[%l%d]+%.html")
		else
			local strFile = strLink:match("^<li><a href=%p(toc%d+%.html)")
			if tblTable.chosen and strFile then
				local strLoad = general.StrLoadFromFile(strFolder.."\\"..strFile)
				for strLine in strLoad:gmatch("(.-)\r?\n") do						-- Read toc99.html until fhcontent fhpage reached	-- V3.3
					if strLine:match("^<div class=%pfhcontent fhpage") then
						if strLine:match("_Picture") then
							return ( tblTable.name == StrTranslate("Pictures") )	-- Picture file for Table of Pictures ?	-- V3.2
						else
							return ( tblTable.name == StrTranslate("Reports") )	-- Report file for Table of Reports ?	-- V3.2
						end
					end
				end
			end
			return false
		end
	end -- local function isTableLink

	local tblIndex = {}																	-- New contents of Home HTML page
	local intEdits = 0																	-- Number of edited HTML pages	-- V3.2
	local tblTables =																	-- Details per table page type	-- V3.2
		{	--		Table Name						Enabled ?			Table Filename and Content	Hyperlinks
			{ name=StrTranslate("Pictures") ; chosen=tglToPs; file="_topindex.html"; html={}; links=0; };
			{ name=StrTranslate("Reports")  ; chosen=tglToRs; file="_torindex.html"; html={}; links=0; };
			{ name=StrTranslate("Downloads"); chosen=tglToDs; file="_todindex.html"; html={}; links=0; };
		}
	local isIncluded = "Head"															-- Identify Home HTML page heading lines in table page files
	local strHomeHTML = strFolder.."\\"..StrHomeHTML
	local strLoad = general.StrLoadFromFile(strHomeHTML)
	for strLine in strLoad:gmatch("(.-)\r?\n") do									-- Read Home page lines & remove comment tags to restore ToC links	-- V3.3
		strLine = strLine:gsub("^<!%-%-See Table of .+<li>(.*)</li>%-%->$","<li>%1</li>")	-- V3.2
		if strLine:match("^<p class=%pFhSiteTitle%p>") then
			isIncluded = nil																-- Exclude the Home page Welcome section from table page files
		elseif strLine:match("^<div class=%pFhTOC%p>$") then
			isIncluded = "ToC"															-- Identify the Home page Table of Contents (ToC) section
		end
		if not strLine:match("^<li><a href='_%l+%.html'>"..StrTranslate("Table of").." .+</a></li>$") then -- Discard the Table of Pictures/Reports/Downloads links at end of ToC -- V3.2
			if isIncluded then
				if strLine:match("^<title>Welcome</title>$") then					-- Adjust page <title> of table page files
					tableInsert(tblTables,"<title><tblTable.name></title>")
				elseif isIncluded == "ToC" then
					if strLine:match("^<p class=%pFhPageTitle%p>Contents</p>$") then	-- Adjust FhPageTitle of table page files
						tableInsert(tblTables,"<p class='FhPageTitle'>"..StrTranslate("Table of").." <tblTable.name></p>")	-- V3.2
					elseif strLine:match("^<li><a href=.+</a></li>$") then		-- Determine which ToC links to include in each table page file
						for intTable, tblTable in ipairs(tblTables) do
							if isTableLink(tblTable,strLine) then
								table.insert(tblTable.html,strLine)					-- Include in table page, but comment out of Home HTML page
								strLine = "<!--See Table of "..tblTable.name..strLine.."-->"
								tblTable.links = tblTable.links + 1
								break														-- Break out of loop once a link has been matched
							end
						end
					elseif not strLine:match("^<li><a class=.+ href=.+</a></li>$") then	-- Exclude external ToC links
						tableInsert(tblTables,strLine)								-- Copy other ToC lines to each table page file
						if strLine:match("^</ul>$") then
							for intTable, tblTable in ipairs(tblTables) do			-- Insert Table of Pictures/Reports/Downloads links at end of Home HTML page ToC
								if tblTable.links > 0 then
									table.insert(tblIndex,"<li><a href='"..tblTable.file.."'>"..StrTranslate("Table of").." "..tblTable.name.."</a></li>") -- V3.2
								end
							end
							isIncluded = "Tail"											-- Identify Home HTML page trailing lines in table page files
						end
					end
				else
					tableInsert(tblTables,strLine)									-- Copy all "Head" and "Tail" lines to each table page file
				end
			end
			table.insert(tblIndex,strLine)											-- Copy all required lines to Home HTML page
		end
	end
	local strLoad = general.StrLoadFromFile(strHomeHTML)							-- V3.2
	local strSave = table.concat(tblIndex,"\n")
	if strLoad ~= strSave then
		general.SaveStringToFile(strSave,strHomeHTML)								-- Update the Home HTML page file	-- V3.2
		intEdits = intEdits + 1
	end
	for intTable, tblTable in ipairs(tblTables) do
		local strTableFile = strFolder.."\\"..tblTable.file
		if tblTable.links > 0 then
			local strLoad = ""
			if general.FlgFileExists(strTableFile) then
				strLoad = general.StrLoadFromFile(strTableFile)					-- V3.2
			end
			local strSave = table.concat(tblTable.html,"\n")
			if strLoad ~= strSave then
				general.SaveStringToFile(strSave,strTableFile)						-- If any links, create table page file	-- V3.2
				intEdits = intEdits + 1
			end
		else
			if general.FlgFileExists(strTableFile) then
				general.DeleteFile(strTableFile)										-- Otherwise, delete old table page file	-- V3.2
				intEdits = intEdits + 1
			end
		end
	end

	-- Search each HTML file and convert its menu bar --

	progbar.Setup(iup_gui.DialogueAttributes("Bars"))
	local isBarStop
	local intHtml = 0
	local arrFile = general.GetFolderContents(strFolder)
	for _, dicFile in ipairs (arrFile) do											-- V3.3
		local strFile = dicFile.name
		if strFile:match("^.+%.html$") then intHtml = intHtml + 1 end			-- Count all HTML files
	end
	local intFile = 0
	for _, dicFile in ipairs (arrFile) do											-- V3.3
		local strFile = dicFile.name
		if strFile:match("^.+%.html$") then											-- HTML file found
			intFile = intFile + 1
			if intFile % 23 == 0 then
				progbar.Message("Updating HTML page "..strFile)					-- Reduce rate of messages	-- V3.2
				progbar.Step(23)
				collectgarbage("step",0)												-- Improves run time in loops!	-- V3.2
			end
			local tblFile = {}															-- Table of lines in file
			local strOldMenu = ""														-- Old menu bar links
			local strNewMenu = ""														-- New menu bar links for comparison
			strFile = strFolder.."\\"..strFile
			local strLoad = general.StrLoadFromFile(strFile)
			for strLine in strLoad:gmatch("(.-)\r?\n") do							-- Read each HTML file line by line -- V3.3
				if strLine:match("^<li><span.*><a href=%p_%l*index%.html%p>.+</a></span></li>$") then	-- V3.2
					strOldMenu = strOldMenu..strLine									-- Accumulate all existing table page menu links
					if strLine:matches("_nameindex.html") then						-- V2.4 -- Ignore all table page menu links except _nameindex.html
						if isMenu then
							for intTable, tblTable in ipairs(tblTables) do			-- Add any table page menu links
								if tblTable.links > 0 then
									local strMenu = "<li><span><a href='"..tblTable.file.."'>"..tblTable.name.."</a></span></li>"
									table.insert(tblFile,strMenu)
									strNewMenu = strNewMenu..strMenu					-- Accumulate all new table page menu links
								end
							end
						end
						strNewMenu = strNewMenu..strLine								-- Append the _nameindex.html page menu link
						table.insert(tblFile,strLine)
					end
				else
					table.insert(tblFile,strLine)										-- Copy all other lines
				end
			end
			if intFile == 1 then
				if strOldMenu == strNewMenu then break end							-- If menu bar unchanged in first file then skip all file updates
				if intHtml > 100 then
					progbar.Start("Converting Menu Bars",intHtml)					-- Otherwise, if more than 100 files, start progress bar
				end
			end
			general.SaveStringToFile(table.concat(tblFile,"\n"),strFile)		-- Save changed HTML files
			intEdits = intEdits + 1
		end
		isBarStop = progbar.Stop()
		if isBarStop then break end
	end
	progbar.Close()																		-- Close the Progress Bar
	return intEdits

end -- function IntImproveTable

-- Add alternate & married names and idents to _nameindex.html and optional Surnames Index to _surnames.html --

function IntImproveIndex(strFolder,isFilter,strNames,strStyle)					-- V2.5 isFilter -- V3.2 remove intIdent
	-- strFolder	~ Website HTML folder
	-- isFilter	~ Search Filter option
	-- strNames	~ Additional Names option
	-- strStyle	~ Font style for Names option

	local strFileHtml = strFolder.."\\_nameindex.html"							-- Name index HTML filename -- V2.4
	local strFileJava = strFolder.."\\_nameindex.js"								-- Name index Java filename -- V2.4
	local strFileJmin = strFolder.."\\jquery.min.js"								-- Jquery.min Java filename -- V2.4
	local tblNameList = {}																-- Name list of index page entries
	local tblShortcut = {}																-- Shortcut to Name list entries
	local strPagelink = ''																-- Pagelink to web page for current person
	local strRecordId = ''																-- Record Id of current person used to make Name list entry distinct
	local strLifedate = ''																-- Lifedates of current person in index page format or '( - )' if Living
	local strAsterisk = ''																-- Asterisk indicating has own or shared page in FH V7+	-- V3.1
	local strIdentity = ''																-- Identity text of current person associated with Identity GUI options
	local strTitleTxt = ''																-- Tooltip title text for Name list entry

	-- Obtain Individual Lastname & Forenames --

	local function strGetNames(ptrIndiName)
		local strLastname = fhGetItemText(ptrIndiName,'~:SURNAME')				-- Get the Surname
	local strForename = fhGetItemText(ptrIndiName,'~:GIVEN_ALL')				-- Get the Forenames etc
		if strLastname == '' then
			strLastname = '?'
		end
		if strForename == '' then
			strForename = '?'
		end
		strLastname = encoder.StrEncode_XML(strLastname)							-- Translate ANSI/UTF-8 characters into XML/HTML characters
		strForename = encoder.StrEncode_XML(strForename)
		return strLastname, strForename
	end -- local function strGetNames

	-- Obtain Individual Identity Data Conditionally --

	local tblIdentity = {																-- V3.2
		{ Control=StrIdRiD; Tag=' '      ; Prefix=' RiD:'; };						-- Record Identity
		{ Control=StrIdPRN; Tag='~.RFN'  ; Prefix=' PRN:'; };						-- Permanent Record Number
		{ Control=StrIdCiD; Tag='~.REFN' ; Prefix=' CiD:'; };						-- Custom Identity
		{ Control=StrIdARI; Tag='~.RIN'  ; Prefix=' ARI:'; };						-- Automatic Record Identity
		{ Control=StrIdUID; Tag='~._UID' ; Prefix=' UID:'; };						-- Unique Identity
		{ Control=StrIdFSI; Tag='~._FSID'; Prefix=' FSI:'; };						-- Family Search Identity
	}

	local function strGetIdentity(ptrIndi) 											-- V3.2
		local strIdentities = ''
		for intIdentity, tblIdentity in ipairs(tblIdentity) do					-- Repeat for each GUI Identity option
			local strIdentity = strRecordId											-- Default to Record Id
			if #tblIdentity.Tag > 3 then 												-- Get the Identity text
				strIdentity = fhGetValueAsText(fhGetItemPtr(ptrIndi,tblIdentity.Tag))
			end
			if strIdentity ~= '' and tblIdentity.Control == "ON" then
				strIdentity = tblIdentity.Prefix..strIdentity						-- Add prefix if required
			else
				strIdentity = ''
			end
			strIdentities = strIdentities..strIdentity								-- Accumulate each required Identity
		end
		if strIdentities ~= '' then strIdentities = '<a class="name" href={HREF}>'..encoder.StrEncode_XML(strIdentities)..' </a>' end -- V2.4	-- V2.5 <p> => <a class="name" href={HREF}>
		return strIdentities
	end -- local function strGetIdentity

	-- Find Existing Name list entry and update RecordId & Identity --

	local function isExisting(strEntry)
		local tblEntry = tblShortcut[strEntry] or {}								-- Lookup shortcut to Name list entries
		for i, intEntry in ipairs(tblEntry) do										-- Search any matching entries
			local strRecId = tblNameList[intEntry].RecordId
			if strRecId == strRecordId or strRecId == '' then						-- Record Id matches, or not yet assigned
				tblNameList[intEntry].RecordId = strRecordId
				tblNameList[intEntry].Identity = strIdentity
				return true																-- Found entry with matching Pagelink, FullName, Lifedate & RecordId
			end
		end
		return false																		-- No entry found
	end -- local function isExisting

	-- Obtain matching Pagelink for own web page or relative's web page --

	local function strGetPageLink(ptrIndi,intFamilyId)
		local strLastname, strForename = strGetNames(fhGetItemPtr(ptrIndi,'~.NAME'))
		local strSelfname = strLastname..strForename								-- Pagelink + Selfname + Lifedate is Shortcut index to Name list
		local strPagelink = ''															-- Pagelink for own or relative's featured web page
		local intRecordId = 0															-- RecordId for current Family or Individual record
		local flagLiving = fhGetItemText(ptrIndi,'~._FLGS.__LIVING')			-- 'Y' or ''
		local ptrLink = fhNewItemPtr()												-- Pointer to self and each relative
		local ptrFams = fhNewItemPtr()												-- Pointer to each Family of the above
		repeat
			for intTag, strTag in ipairs({ '~'; '~.~FATH[1]>'; '~.~MOTH[1]>'; '~.~SPOU[1]>'; '~.~CHIL[1]>'; }) do
				local intNext = 1
				ptrLink:MoveTo(ptrIndi,strTag)										-- Search own and each relative's web page links
				while ptrLink:IsNotNull() do
					if intFamilyId ~= 0 then											-- Family web page search needed
						ptrFams:MoveTo(ptrLink,'~.FAMS')
						while ptrFams:IsNotNull() do									-- Check each Family Pagelink
							intRecordId = fhGetRecordId(fhGetValueAsLink(ptrFams))
							strPagelink = '"fam'..tostring(intRecordId)..'.html"'
							if intFamilyId < 0 then
								if isExisting(strPagelink..strSelfname..strLifedate) then return strPagelink end
							elseif intFamilyId == intRecordId then
								return strPagelink										-- Husband entry needs Family Pagelink (could check web page file exists)
							end
							ptrFams:MoveNext('SAME_TAG')
						end
					end
					intRecordId = fhGetRecordId(ptrLink)								-- Check the Individual Pagelink
					strPagelink = '"ind'..tostring(intRecordId)..'.html"'
					if isExisting(strPagelink..strSelfname..strLifedate) then return strPagelink end
					if strTag == '~' then
						ptrLink:SetNull()												-- Only one instance of self, so close while ptrLink:IsNotNull() loop
					else
						intNext = intNext + 1											-- Next instance of relative e.g. '~.~SPOU[2]>' or '~.~CHIL[9]>'
						ptrLink:MoveTo(ptrIndi,(strTag:gsub('1',intNext)))		-- ptrLink:MoveNext('SAME_TAG') does not work
					end
				end
			end
			if strLifedate == '( - )' then flagLiving = '' end					-- After trying blank Lifedate exit repeat loop
			if flagLiving == 'Y' then strLifedate = '( - )' end					-- If Living flag then try blank Lifedate
		until flagLiving == ''
		return nil																		-- No matching entry found
	end -- local function strGetPageLink

	-- Conditionally Update Name List and Shortcut --

	local function doUpdateNameList(strLastname,strForename,strFullname,strAsterisk)
		local strEntry = strPagelink..strLastname..strForename..strLifedate
		if not tblShortcut[strEntry] then tblShortcut[strEntry] = {} end		-- New shortcut to Name entry needed
		if #tblShortcut[strEntry] == 0 or strRecordId == '' then					-- New shortcut to new Name, or replica Name in name index page
			table.insert(tblNameList,{ Pagelink=strPagelink; Lastname=strLastname; Sortname=encoder.StrUTF8_ASCII(strLastname); Forename=strForename; Fullname=strFullname; Lifedate=strLifedate; Asterisk=strAsterisk; RecordId=strRecordId; Identity=strIdentity; TitleTxt=strTitleTxt; })	-- V3.1
			table.insert(tblShortcut[strEntry],#tblNameList)						-- Save shortcut to Name entry, which may have replicas
		end
	end -- local function doUpdateNameList

	-- Comparison for table sort that returns true when 1st is less than 2nd --

	local function isLessThan(tbl1st,tbl2nd)
		local str1stPref = ''															-- Adjust sort so non-alpabetic initial chars come first but ordered according to any subsequent letters
		local str2ndPref = ''
		local str1stName = tbl1st["Sortname"]
		local str2ndName = tbl2nd["Sortname"]
		if not str1stName:match('^%u') then str1stPref = '!'..(str1stName:match('(%u+)') or '!') end
		if not str2ndName:match('^%u') then str2ndPref = '!'..(str2ndName:match('(%u+)') or '!') end
		str1stName = str1stPref..str1stName..','..tbl1st["Forename"]..tbl1st["Lifedate"]..tbl1st["Pagelink"]	-- V2.5 added ',' needed to separate names
		str2ndName = str2ndPref..str2ndName..','..tbl2nd["Forename"]..tbl2nd["Lifedate"]..tbl2nd["Pagelink"]	-- V2.5 added ',' needed to separate names
		return str1stName < str2ndName
	end -- local function isLessThan

	--	Read _nameindex.html file of text into tblNameIndex, down to <div class="FhIndexList">

	fhOverridePreference("SURNAMES_UPPERCASE",true,true)
	local strStyleCSS = ' '
	if strStyle:match("Italics")   then strStyleCSS = strStyleCSS..'font-style:italic; ' end
	if strStyle:match("Underline") then strStyleCSS = strStyleCSS..'text-decoration:underline; ' end
	local strDivIdTop = nil																-- V2.4 -- First div id may be "header" or "menubar"
	local intAlphabet = 0																-- Alphabet Anchor Hyperlinks line number
	local tblNameIndex = {}																-- Table of _nameindex.html leading text lines
	local strNameIndex = ''																-- Text of _nameindex.html trailing text lines

	local strLastname = ''
	local strForename = ''
	local strFullname = ''
	local intFamilyId = 0

	local strFileMode = 'head'

	local strLoad = general.StrLoadFromFile(strFileHtml)
	for strLine in strLoad:gmatch("(.-)\r?\n") do									-- Read _nameindex.html leading text line by line	-- V3.3
	
		if strFileMode == 'head' then
			if not																			-- V2.4 -- Exclude search filter scripts & paragraphs and XHTML CSS married/alternate/index/ident/FhInd styles
				(   strLine:match('^<script type="text/javascript" src="[j_]........[nx]%.js"> </script>$')
				 or strLine:match('^<style type="text/css"> .+married .+alternate .+ </style>$')
				 or strLine:match('^<p id="search" style=.+')
				 or strLine:match('^&nbsp;%p.+')
				 or strLine:match('^<p class="hide" style=.+<br/>.+</p>')		-- V2.4 -- V2.5 
				) then
				if strLine == '</head>' then											-- V2.5 -- End of Header so insert XHTML CSS married/alternate/name/FhIndexList/FhInd styles (FhInd needed to remove white borders around Alphabet Index when custom body background)
	 				-- V2.5 {float:left;width:xx%;} style made Search Filter run very slowly so changed to {display:inline-block;width:50%} and .FhIndexList ul {margin-top:-1.25em;} style
					table.insert(tblNameIndex,'<style type="text/css"> /*<![CDATA[*/ span.married {'..strStyleCSS..'} span.alternate {'..strStyleCSS..'} a.name {display:inline-block;width:50%} .FhIndexList {margin-left:10%;width:90%;} .FhIndexList ul {margin-left:0em;} .FhIndexList ul li ul {margin-left:15em;} .FhInd {font-size:120%;margin-top:-0.2em;margin-bottom:2.5em;border:none;} .FhInd a:link {border:none;} /*]]>*/ </style>')
				end
				strDivIdTop = strDivIdTop or strLine:match('^<div id="(%l+)">')	-- V2.4 -- Save first div id name for Return to Top links
				if strLine:match('<div class="FhInde?x?P?a?g?e?">') then			-- V3.1 -- class= FH V7 FhIndexPage FH V6 FhInd
					if isFilter then														-- V2.5 -- Insert Search Filter box and Alpahbetic Lookup advice above <div class="FhInd">
						local arrTitle = { }											-- Translate advice -- V3.2
						table.insert( arrTitle, StrTranslate("Examples of what Search Filter text will find:") )
						table.insert( arrTitle, "' Bond, James ('	"..StrTranslate("full name").." BOND, James" )
						table.insert( arrTitle, "' Anderson, '		"..StrTranslate("any").." "..StrTranslate("matching").." "..StrTranslate("Surname") )
						table.insert( arrTitle, "' Elizabeth '		"..StrTranslate("any").." "..StrTranslate("matching").." "..StrTranslate("Forename") )
						table.insert( arrTitle, "', Jonathan '	 	"..StrTranslate("matching").." "..StrTranslate("first").." "..StrTranslate("Forename") )
						table.insert( arrTitle, "' Jonathan ('		"..StrTranslate("matching").." "..StrTranslate("final").." "..StrTranslate("Forename") )
						table.insert( arrTitle, "'arth'       		Arthur, Martha, Garth, etc" )
						table.insert( arrTitle, "'(1789-1876)'   	"..StrTranslate("matching").." ("..StrTranslate("Life-Dates")..")" )
						table.insert( arrTitle, "'RiD:12 '    		"..StrTranslate("matching").." "..StrTranslate("Identities") )
						table.insert( arrTitle, "( "..StrTranslate("Note the space character before and after names").." )" )
						local strTitle = "&nbsp;"..table.concat(arrTitle,"\n&nbsp;") -- V2.5 -- Add tooltip help text to Search Filter (leading &nbsp; makes it match uniquely above)
						local strLine = '<p id="search" style="text-align:center;" title="'..strTitle..'"><b>'..StrTranslate("Index of Names Search Filter")..'</b><br/>'..StrTranslate("Enter case-insensitive text in filter box to match consecutive text in index below (long lists may react slowly)")..'</p> '
						table.insert(tblNameIndex,strLine)							-- V2.5 -- Insert the Search Filter advice and id="search" for filter form
						local strLine = '<p class="hide" style="text-align:center;"><b>'..StrTranslate("Surnames Alphabetic Lookup")..'</b><br/>'..StrTranslate("Click any letter below to jump to surnames starting with that letter")..'</p> '
						table.insert(tblNameIndex,strLine)							-- V2.5 -- Insert the Alphabetic Lookup advice and Search Filter javascript
						table.insert(tblNameIndex,'<script type="text/javascript" src="jquery.min.js"> </script>')
						table.insert(tblNameIndex,'<script type="text/javascript" src="_nameindex.js"> </script>')
						Str_filter_js = Str_filter_js:gsub("Clear Search",StrTranslate("Clear Search"))
						Str_filter_js = Str_filter_js:gsub("Start Search",StrTranslate("Start Search"))
						Str_filter_js = Str_filter_js:gsub("Please Wait" ,StrTranslate("Please Wait"))
						general.SaveStringToFile(Str_filter_js,strFileJava)		-- V2.5 -- Save _nameindex.js file
						general.SaveStringToFile(Str_jquery_js,strFileJmin)		-- V2.5 -- Save jquery.min.js file
					else
						general.DeleteFile(strFileJava)								-- V2.5 -- Remove _nameindex.js file
						general.DeleteFile(strFileJmin)								-- V2.5 -- Remove jquery.min.js file
					end
				end
				table.insert(tblNameIndex,strLine)									-- Save leading text lines
				if strLine:match('^<p.->.*<a href="#%u".*>%u</a>.*</p>$') then	-- V2.4 -- V3.2
					intAlphabet = #tblNameIndex										-- Save index to Alphabet Anchor Hyperlinks line
				end
				if strLine == '<div class="FhIndexList">' then						-- Pause at <div class="FhIndexList"> line
					strFileMode = 'list'
				end
			end

		elseif strFileMode == 'list' then

			-- Read _nameindex.html web page link & full name & life dates & asterisk into a tblNameList and tblShortcut dictionary

			local strStar1, strStar2
			strPagelink, strFullname, strLifedate, strStar1, strStar2 = strLine:match('^<li.*>.-<a .-href=("[a-z0-9]-%.html")> *(.+ )(%(.-%))(.-)</a>(.-)</li>$') -- V2.4 -- V3.1
			if strPagelink and strFullname and strLifedate then					-- List the entry details
				if not ( strFullname:match(' title="%u%l+ Name">')				-- Exclude alternate/married names with tooltip title="Alternate/Married Name"
						or strFullname:match('</?i>')									-- V2.4 -- or with legacy <i> italics </i>
						or strFullname:match('</?span.->') ) then					-- or with <span class=...> name </span>
					strLastname = strFullname:match('^([^a-z]+), ') or '?'		-- Allow for any surname including accented capitals
					strForename = strFullname:match(strLastname:plain()..', (.+) ') or '?'
					strAsterisk = strStar1:match('(<sup>%*</sup>)') or strStar2:match('(<sup>%*</sup>)') or ''		-- FH V7 superscipt asterisk	-- V3.1
					doUpdateNameList(strLastname,strForename,strLastname..', '..strForename..' ',' '..strAsterisk)	-- V3.1
					if strPagelink:match('fam') then intFamilyId = -1 end
				end
			end
			if strLine == '</div>' or strLine:match('<p>&nbsp;?</p>') then		-- FH V7 <p>&nbsp;</p> FH V6 </div> 	-- V3.1	
				strNameIndex = strLine..'\n'											-- Save _nameindex.html trailing lines -- V3.1
				strFileMode = 'tail'
			end

		elseif strFileMode == 'tail' then

			strNameIndex = strNameIndex..strLine..'\n'
		end
	end

	-- Search all GEDCOM Names to add Alternate Names &/or Married Womens Surnames to tables with correct web page link and Identity

	local ptrName = fhNewItemPtr()
	local ptrFams = fhNewItemPtr()
	local ptrFamr = fhNewItemPtr()
	local ptrSpou = fhNewItemPtr()
	local strStat = ''
	local strMarriedName	= ' title="'..StrTranslate("Married Name")  ..'"'	-- V3.2
	local strAlternateName	= ' title="'..StrTranslate("Alternate Name")..'"'	-- V3.2
	local ptrIndi = fhNewItemPtr()
	ptrIndi:MoveToFirstRecord('INDI')
	while ptrIndi:IsNotNull() do														-- Loop through every Individual to ensure RecordId & Identity added to Primary Names
		strRecordId = tostring(fhGetRecordId(ptrIndi))								-- Get current RecordId text
		strLifedate = '('..fhCallBuiltInFunction("LifeDates2",ptrIndi)..')'	-- Get current Lifedate text in name index format
		strIdentity = strGetIdentity(ptrIndi)										-- Get current Identity text required by GUI option
		strPagelink = strGetPageLink(ptrIndi,intFamilyId)							-- Get current Pagelink text from matching Name list entry
		if strPagelink then
			ptrName = fhGetItemPtr(ptrIndi,'~.NAME')
			collectgarbage("step",0)													-- Improves run time in loops!	-- V3.2

			if strNames:match( "Married" ) then 										-- Add Married Womens Surnames
				strTitleTxt = strMarriedName											-- V3.2
				if fhGetItemText(ptrIndi,'~.SEX') == "Female" then				-- For Females use her Forename with the Husband's Lastname
					strLastname, strForename = strGetNames(ptrName)				-- Get her Lastname & Forename
					ptrFams:MoveTo(ptrIndi,'~.FAMS')
					while ptrFams:IsNotNull() do
	                ptrFamr = fhGetValueAsLink(ptrFams)
						ptrSpou = fhGetItemPtr(ptrFamr,'~.HUSB>')					-- Check husband is Male
						if fhGetItemText(ptrSpou,'~.SEX') == "Male" then
		                strStat = fhGetItemText(ptrFamr,'~._STAT')
		                if strStat ~= "Never Married" and strStat ~= "Unmarried Couple" then
								if intFamilyId < 0 then									-- Use the Husband's family Pagelink
									strPagelink = strGetPageLink(ptrSpou,fhGetRecordId(ptrFamr))
								end
								if strPagelink then										-- Get the Husband's Surname
									strLastname = strGetNames(fhGetItemPtr(ptrSpou,'~.NAME'))
									if strLastname ~= '?' then							-- Add the Married Name in italics &/or underline with tooltip title
										doUpdateNameList(strLastname,strForename,'<span class="married">'..strLastname..'</span>, '..strForename..' ')
									end
								end
							end
						end
						ptrFams:MoveNext('SAME_TAG')
					end
				end
			end -- Add Married Womens Surnames

			if strNames:match( "Alternate" ) then									-- Add Alternate Names
				strTitleTxt = strAlternateName										-- V3.2
				ptrName:MoveNext('SAME_TAG')											-- Check each Alternate Name entry
				while ptrName:IsNotNull() do
					strLastname, strForename = strGetNames(ptrName)				-- Get Alternate Surname & Forename
					if strLastname..strForename ~= '??' then						-- Add the Alternate Name in italics &/or underline with tooltip title
						doUpdateNameList(strLastname,strForename,'<span class="alternate">'..strLastname..', '..strForename..'</span> ')
					end
					ptrName:MoveNext('SAME_TAG')
				end
			end -- Add Alternate Names

		end
		ptrIndi:MoveNext()
	end

	table.sort(tblNameList,isLessThan) 												-- Sort the NameList alphabetically by Name and Lifedates and Pagelink

	local strHeadName = nil
	local strAlphabet = '<p class="hide">A&nbsp;B&nbsp;C&nbsp;D&nbsp;E&nbsp;F&nbsp;G&nbsp;H&nbsp;I&nbsp;J&nbsp;K&nbsp;L&nbsp;M&nbsp;N&nbsp;O&nbsp;P&nbsp;Q&nbsp;R&nbsp;S&nbsp;T&nbsp;U&nbsp;V&nbsp;W&nbsp;X&nbsp;Y&nbsp;Z&nbsp;</p>'
	local strNextInit = ''
	local strPrevInit = ''
	local strPreamble = ''
	local strReturnToTop = '<a href="#'..strDivIdTop..'" title="'..StrTranslate("Return to Top")..'">'	-- V3.2
	table.insert(tblNameIndex,'<ul id="list">')										-- V2.4 -- Start of Search Filter unordered list
	for i, tblItem in ipairs(tblNameList) do										-- Add each NameList item to _nameindex.html text lines
		strPagelink = tblItem["Pagelink"]
		strLastname = tblItem["Lastname"]
		strSortname = tblItem["Sortname"]
		strForename = tblItem["Forename"]
		strFullname = tblItem["Fullname"]
		strLifedate = tblItem["Lifedate"]
		strAsterisk = tblItem["Asterisk"] or ''										-- V3.1
		strIdentity = tblItem["Identity"]
		strTitleTxt = tblItem["TitleTxt"]
		if strHeadName ~= strSortname then
			if strHeadName then table.insert(tblNameIndex,'</ul>\n</li>') end	-- V2.5 -- End of previous Names unordered sub-list
			strHeadName = strSortname													-- Each new Lastname needs a Header
			strNextInit = strHeadName:sub(1,1)
			if strPrevInit ~= strNextInit												-- Each new Initial Letter needs an Alphabet Hyperlink <a href="#I">I</a> and Anchor <a id="I"></a>
			and strNextInit:match('%u') then											-- ??????
				strAlphabet = strAlphabet:gsub(strNextInit..'&nbsp;','<a href="#'..strNextInit..'" title="'..StrTranslate("Surnames starting with")..' '..strNextInit..'">'..strNextInit..'</a>&nbsp;')
				strPrevInit = '<a id="'..strNextInit..'"></a>'
			else
				strPrevInit = ''
			end
			strLastname = strLastname:gsub('^?$','(no surname)')					-- V2.4 -- Change ? to (no surname)
			strLastname = strLastname:sub(1,IntLength)								-- V3.0 -- Truncate to avoid overwriting Names list
			strPreamble = '<li>\n<p>'..strPrevInit..strReturnToTop..strLastname..'</a></p>\n</li>' -- V2.5 -- V3.2
			table.insert(tblNameIndex,strPreamble)									-- V2.5 
			table.insert(tblNameIndex,'<li>\n<ul>')									-- V2.5 -- Start of next Names unordered sub-list
			strPrevInit = strNextInit
		end
--#		strIdentity = '<a class="name" href={HREF}>Rid:{HREF} </a>'				-- V2.5 Temporary fudge for testing
		strIdentity = strIdentity:gsub("{HREF}",strPagelink)						-- V2.4 -- Identity hyperlink
		local strClassName = strIdentity:match('class="%l+" ') or ''			-- V2.5 
		table.insert(tblNameIndex,'<li><a '..strClassName..'href='..strPagelink..strTitleTxt..'> '..strFullname..strLifedate..strAsterisk..'</a>'..strIdentity..'</li>')	-- V2.5 -- Insert Page link, full Name, Life dates & Idents -- V3.1 Asterisk
	end
	strAlphabet = strAlphabet:gsub('&nbsp;</p>$','</p>')							-- Remove trailing &nbsp; from Alphabet Anchor Hyperlinks
	tblNameIndex[intAlphabet] = strAlphabet
	table.insert(tblNameIndex,'</ul>\n</li>')										-- V2.5 -- End of final Names unordered sub-list
	table.insert(tblNameIndex,'</ul>\n')												-- V2.4 -- End of Search Filter unordered list
	strNameIndex = table.concat(tblNameIndex,'\n')..strNameIndex
	strLoadIndex = general.StrLoadFromFile(strFileHtml)
	if strLoadIndex == strNameIndex then return 0 end								-- V3.2
	general.SaveStringToFile(strNameIndex,strFileHtml)							-- Save _nameindex.html file

	return #tblNameList																	-- Number of names in list
	
end -- function IntImproveIndex

-- Create a 'gendex.txt' file for the http://gendexnetwork.org/ GenDex web site --

function IntCreateGenDex(strFolder,strGenDex)
	-- strFolder	~ Website HTML folder

	-- Compose webpage Filename matching Individual Record --

	local function strFilename(ptrIndi)
			local strFile = "ind"..fhGetRecordId(ptrIndi)..".html"				-- Does "ind{RecId}.html" Individual Summary webpage file exist?
			if general.FlgFileExists(strFolder.."\\"..strFile) then return strFile end
			local ptrFams = fhNewItemPtr()
			ptrFams:MoveTo(ptrIndi,"~.FAMS>")
			strFile = "fam"..fhGetRecordId(ptrFams)..".html"						-- Does "fam{RecId}.html" Family Group Sheet webpage file exist?
			if general.FlgFileExists(strFolder.."\\"..strFile) then return strFile end
			return nil
	end -- local function strFilename

	local strGedcomDate = NewGedcomDate()											-- Define local function from prototype below

	fhOverridePreference("SURNAMES_UPPERCASE",true,true)
	local tblGenDex = {}
	local ptrIndi = fhNewItemPtr()
	ptrIndi:MoveToFirstRecord("INDI")
	while ptrIndi:IsNotNull() do
		local strFile = strFilename(ptrIndi)
		if strFile
		and not ( strGenDex:match("Living")  and fhGetItemText(ptrIndi,"~._FLGS.__LIVING")  == "Y" )
		and not ( strGenDex:match("Private") and fhGetItemText(ptrIndi,"~._FLGS.__PRIVATE") == "Y" ) then
			collectgarbage("step",0)													-- Improves run time in loops!	-- V3.2
			local tblData = {}
			table.insert(tblData,strFile)												-- Reference is featured webpage filename
			table.insert(tblData,fhGetItemText(ptrIndi,"~.NAME:SURNAME"))		-- Surname in uppercase
			table.insert(tblData,fhGetItemText(ptrIndi,"~.NAME:STORED"))		-- Stored full name
			for intList, tblList in ipairs ( { { "~.BIRT"; "~.BAPM"; "~.CHR"; }; { "~.DEAT"; "~.BURI"; "~.CREM"; }; } ) do
				local strDate = ""
				local strPlac = ""
				for intFact, strFact in ipairs ( tblList ) do
					local ptrFact = fhGetItemPtr(ptrIndi,strFact)					-- Get Birth/Baptism/Christening or Death/Burial/Cremation Date & Place
					if ptrFact:IsNotNull() then
						if strDate == "" then strDate = fhGetItemText(ptrFact,"~.DATE") end
						if strPlac == "" then strPlac = fhGetItemText(ptrFact,"~.PLAC") end
					end
				end
				table.insert(tblData,strGedcomDate(strDate))						-- Convert date to GEDCOM format
				table.insert(tblData,strPlac)
			end													-- Should characters be converted from CP1252 to UTF-8 ???
			table.insert(tblData,"")
			table.insert(tblGenDex,table.concat(tblData,"|"))						-- Create "|" separated Individual data entry
		end
		ptrIndi:MoveNext()
	end

	local strGendex = strFolder.."\\gendex.txt"
	local strLoad = ""
	if general.FlgFileExists(strGendex) then
		strLoad = general.StrLoadFromFile(strGendex)								-- V3.2
	end
	local strSave = table.concat(tblGenDex,"\n")
	if strLoad == strSave then return 0 end											-- V3.2
	general.SaveStringToFile(strSave,strGendex)										-- Create the GenDex file in website folder
 
	return #tblGenDex

end -- function IntCreateGenDex

-- Apply current Output Language to all HTML page menus and headings --		-- V3.2

function IntApplyLanguage(strFolder)
	-- strFolder	~ Website HTML folder
	local intFile = 0																	-- Count HTML file pages found
	local intPage = 0																	-- Count HTML file pages changed
	local strMenu = nil 																-- New translated menu bar
	local strBar  = '<div id="menubar">\n.-\n</ul>\n</div>\n'					-- Menu bar pattern match
	local arrFind = {																	-- 'See also' section key words
		{ Text='other family'; 	Suffix=': ' ; };
		{ Text='other families';	Suffix=': ' ; };
		{ Text='with';				Suffix=' <a'; };
		{ Text='parents';			Suffix=': ' ; };
		{ Text='father';			Suffix=': ' ; };
		{ Text='mother';			Suffix=': ' ; };
		{ Text='siblings';			Suffix=': ' ; };
		{ Text='brother';			Suffix=': ' ; };
		{ Text='sister';			Suffix=': ' ; };
		{ Text='and';				Suffix=' <a'; };
		{ Text='bap';				Suffix='.'  ; };
		{ Text='chr';				Suffix='.'  ; };
		{ Text='bur';				Suffix='.'  ; };
		{ Text='crem';				Suffix='.'  ; };
	}

	local function strNewFeature(strPage)											-- Translate featured ind & fam pages 'See also' section
		local strSee, strRef = strPage:match('<div class="FhSeeAlso">\n(.-)\n<ul>\n(.-)\n</ul>\n</div>')
		if strSee and strRef then
			local strMap = strRef:match('(<li><a href=.-</a></li>\n)<[!li>][^<]') or ""	-- Map of Locations entries from Map Life Facts plugin
			local strEng = strRef:match('<!%-- English\n(.-)\nEnglish %-->') or strRef:match('<li>[^<].-$')
			local strPre = strRef:match('\n(<!%-- \n)<li>') or ""
			local strSuf = strRef:match('</li>(\n %-->)\n') or ""
			local strNew = strPre..strEng..strSuf
			strSee = strSee:gsub( '<p>.-</p>', '<p>'..StrTranslate("See also")..'</p>', 1 )
			for _, dicFind in ipairs (arrFind) do									-- Use lookup table above
				local strText = dicFind.Text
				local strSuff = dicFind.Suffix
				strNew = strNew:gsub( '([ (])'..strText..'%'..strSuff, '%1'..StrTranslate(strText)..strSuff )
			end
			strMap = strMap:gsub( '(<li><a href=".-">).-(&nbsp;.-</a></li>)', '%1'..StrTranslate("Map of Locations for")..'%2' )
			strPage = strPage:gsub( '(<div class="FhSeeAlso">\n).-(\n</ul>\n</div>)', '%1'..strSee:inert()..'\n<ul>\n'..strMap:inert()..strNew:inert()..'\n<!-- English\n'..strEng:inert()..'\nEnglish -->%2', 1 )
		end
		return strPage
	end -- local function strNewFeature

	local function strNewTitle(strPage,strTitle)									-- Translate page title
		strPage = strPage:gsub( '( class="FhPageTitle">)[^\n]-(</[ph1?>])', '%1'..StrTranslate(strTitle)..'%2', 1 )
		return strPage
	end -- local function strNewTitle

	local function strNewIndexHome(strPage)											-- Translate index or home page
		strPage = strNewTitle(strPage,"Contents")
		strPage = strPage:gsub( '(<a class="fhextlink" href="[^\n]-">)[^\n]-( Family Historian 7</a></p>)', '%1'..StrTranslate("Created with")..'%2', 1 )
		return strPage
	end -- local function strNewIndexHome

	local function strNewContact(strPage)											-- Translate contact details page
		strPage = strNewTitle(strPage,"Contact Details")
		strPage = strPage:gsub( '<p>[^\n]-: <a href', '<p>'..StrTranslate("Email")..': <a href', 1 )
		return strPage
	end -- local function strNewContact

	local function strNewStatistics(strPage)										-- Translate statistics page
		strPage = strNewTitle(strPage,"Statistics")
		strPage = strPage:gsub( '(<tr><td>)[^\n]-(:</td><td>%d+</td></tr>\n<tr><td>)[^\n]-(:</td><td>%d+</td></tr>\n<tr><td>)[^\n]-(:</td><td>%d+</td></tr>)',
								 '%1'..StrTranslate("Pages")..'%2'..StrTranslate("People")..'%3'..StrTranslate("Pictures")..'%4', 1 )
		return strPage
	end -- local function strNewStatistics

	local function strNewNameIndex(strPage)											-- Translate index of names page
		strPage = strNewTitle(strPage,"Index of Names")
		strPage = strPage:gsub( '(<p>%* )[^\n]-(</p>\n</div>)', '%1'..StrTranslate("Has own or shared page")..'%2', 1 )
		return strPage
	end -- local function strNewNameIndex

	local function strNewTableOf(strPage)											-- Translate Table of Pictures, Reports, Downloads pages
		strPage = strPage:gsub( '(<a class="fhextlink" href="[^\n]-">)[^\n]-( Family Historian 7</a></p>)', '%1'..StrTranslate("Created with")..'%2', 1 )
		return strPage
	end -- local function strNewTableOf

	local function strNewMapOfLoc(strPage)											-- Translate Map Life Facts Map of Locations pages
		return strPage
	end -- local function strNewMapOfLoc

	local function strNewContents(strPage)											-- Translate Table of Contents pages
		return strPage
	end -- local function strNewContents

	local function strNewMyLoc(strPage)												-- Translate My Locations page
		return strPage
	end -- local function strNewMyLoc

	local dicPage = {																	-- Invoke translation function per page file
		[StrHomeHTML]			= strNewIndexHome	;
		["_contact.html"]	= strNewContact		;
		["_statistics.html"]= strNewStatistics	;
		["_nameindex.html"]	= strNewNameIndex	;
		["_topindex.html"]	= strNewTableOf		;
		["_torindex.html"]	= strNewTableOf		;
		["_todindex.html"]	= strNewTableOf		;
		["ind9.html"]			= strNewFeature		;
		["fam9.html"]			= strNewFeature		;
		["map9.html"]			= strNewMapOfLoc		;
		["toc9.html"]			= strNewContents		;
		["myloc.html"]		= strNewMyLoc			;
	}

	-- Search each HTML file and convert its menu bar and headings of unique pages --

	progbar.Setup(iup_gui.DialogueAttributes("Bars"))
	local arrFile = general.GetFolderContents(strFolder)
	for _, dicFile in ipairs (arrFile) do											-- V3.3
		local strFile = dicFile.name
		if strFile:match("^.+%.html$") then intFile = intFile + 1 end			-- Count all HTML file pages
	end
	if intFile > 100 then
		progbar.Start("Translating HTML Pages",intFile)							-- If more than 100 files, start progress bar
	end
	intFile = 0
	for _, dicFile in ipairs (arrFile) do											-- V3.3
		local strFile = dicFile.name
		if strFile:match("^.+%.html$") then											-- HTML file page found
			intFile = intFile + 1
			if intFile % 23 == 0 then
				progbar.Message("Translating HTML page "..strFile)				-- Reduce rate of messages
				progbar.Step(23)
				collectgarbage("step",0)												-- Improves run time in loops!
			end
			local strPath = strFolder.."\\"..strFile								-- Load HTML file to translate
			local strPage = general.StrLoadFromFile(strPath)
			local strOrig = strPage

			if not strMenu then 														-- Translate the menu bar once
				strMenu = strPage:match( strBar )
				if strMenu then
					strMenu = strMenu:gsub( '(<a href="[^\n]-">)[^\n]-</a>'           , '%1'..StrTranslate("Home")..'</a>'      , 1 )
					strMenu = strMenu:gsub( '(<a href="_contact%.html">)[^\n]-</a>'   , '%1'..StrTranslate("Contact")..'</a>'   , 1 )
					strMenu = strMenu:gsub( '(<a href="_statistics%.html">)[^\n]-</a>', '%1'..StrTranslate("Statistics")..'</a>', 1 )
					strMenu = strMenu:gsub( '(<a href="_nameindex%.html">)[^\n]-</a>' , '%1'..StrTranslate("Index")..'</a>'     , 1 )
				end
			end
			if strMenu then
				strPage = strPage:gsub( strBar, strMenu, 1 )						-- Substitute the menu bar in every page
			end
			strPage = dicPage[ strFile:gsub('%d+','9') ](strPage)					-- Translate each type of HTML file page
			if strOrig ~= strPage then
				general.SaveStringToFile(strPage,strPath)							-- Save changed HTML file page
				intPage = intPage + 1
			end
			if progbar.Stop() then break end
		end
	end
	progbar.Close()																		-- Close the Progress Bar

	return intPage

end -- function IntApplyLanguage

-- Convert any Date to Gedcom Format Function Prototype --

function NewGedcomDate()

	-- Convert 'approx.', 'calculated', 'estimated' dates --

	local tblQual = { app="ABT "; cal="CAL "; est="EST "; }

	local function strQualifiedDate(strDate,strQual)
		if strQual then
			return tblQual[strQual:sub(1,3)]..strDate
		else
			return nil
		end
	end -- local function strQualifiedDate

	-- Convert a Quarter Date to Gedcom format --

	local tblBeg = { "JAN "; "APR "; "JUL "; "OCT "; }
	local tblEnd = { "MAR "; "JUN "; "SEP "; "DEC "; }

	local function strQuarterDate(strNum,strYear)
		if strNum then
			local intNum = tonumber(strNum)
			return "BET "..tblBeg[intNum]..strYear.." AND "..tblEnd[intNum]..strYear
		else
			return nil
		end
	end -- local function strQuarterDate

	-- Convert any Date to Gedcom format --

	local tblGedcomDate =
	{
		January="JAN"; February="FEB"; March="MAR"; April="APR"; May="MAY"; June="JUN"; July="JUL"; August="AUG"; September="SEP"; October="OCT"; November="NOV"; December="DEC";
		from="FROM"; ["to "]="TO ";
		before="BEF"; after="AFT"; between="BET"; ["and"]="AND";
	}

	return function(strDate)
		local strText = ""
		if strDate:match("\".*\"") then												-- Convert 'Date Phrase' must be first to avoid converting months, etc in Phrase text
			local strGsub = "(.-)%(?\"(.*)\"%)?$"
			strText = strDate:gsub(strGsub,"(%2)")									-- Separate Phrase (Text) from interpreted Date
			strDate = strDate:gsub(strGsub,"%1")
			if strDate ~= "" then strDate = "INT "..strDate end					-- Convert '...interpreted as'
		end
		strDate = strDate:gsub("(.*) %((.*)%)$",strQualifiedDate)				-- Convert (qualified) date
		for strOld, strNew in pairs ( tblGedcomDate ) do
			strDate = strDate:gsub(strOld,strNew)									-- Convert months, and 'Period' and 'Range' dates
		end
		strDate = strDate:gsub("^Q([1-4]) (%d%d%d%d)",strQuarterDate)			-- Convert 'Quarter Date'
		return strDate..strText
	end -- anonymous function

end -- function NewGedcomDate

-- Graphical User Interface --

function GUI_MainDialogue()

	local strInitialText = " No improvement executed in this session "

	-- Create GUI controls
	local btnFolder = iup.button	{ Title="Browse to the Project exported Website, CD, DVD or equivalent HTML folder"; }	-- V3.3
	local txtFolder = iup.text		{ Value=strInitialText; ReadOnly="YES"; Border="NO"; }
	local txtStatus = iup.text		{ Value=strInitialText; ReadOnly="YES"; Border="NO"; }
	local vbxFolder = iup.vbox		{ btnFolder; txtFolder; txtStatus; }
	-- Hyperlinks / Text tab
	local lblPages  = iup.label	{ Title=" Open URL pages:"; }
	local lstPages  = iup.list		{ DropDown="YES"; Visible_Items="9"; Value=IntPages; " In same Page frame"; " In new Tab / Window"; }
	local lblChars  = iup.label	{ Title=" Abbreviate URL:"; }
	local lstChars  = iup.list		{ DropDown="YES"; Visible_Items="9"; Value=IntChars; " Never"; " > 30 char"; " > 50 char"; " > 70 char"; " > 90 char"; }
	local lblTabSep = iup.label	{ Title=" Tab separator:"; }
	local lstTabSep = iup.list		{ DropDown="YES"; Visible_Items="9"; Value=IntTabSep; " None"; " Comma ,"; " Bar |"; " {TAB}"; " ,{TAB}"; " {TAB}|"; " {TAB}…"; }
	local tglBorder = iup.toggle	{ Title=" Table borders:"; Value=StrBorder; RightButton="YES"; }				-- V3.3
	local hbxHyper  = iup.hbox		{ lblPages; lstPages; lblChars; lstChars; lblTabSep; lstTabSep; tglBorder; }	-- V3.3
	local btnHyper  = iup.button	{ Title="Convert all URL (www. http: https: ftp: mailto:) to active Hyperlinks and alter special Hypertext"; }
	local txtHyper  = iup.text		{ Value=strInitialText; ReadOnly="YES"; Border="NO"; }
	local vbxHyper  = iup.vbox		{ hbxHyper; iup.hbox{ btnHyper; Margin="99x0"; }; txtHyper; }	-- V3.0
	-- Media Popups tab
	local btnMedia  = iup.button	{ Title="Turn non-image Media into icons"; }						-- V2.8
	local lblPopup  = iup.label	{ Title=" Version of image window Popup:"; }
	local lstPopup  = iup.list		{ DropDown="YES"; Visible_Items="9"; Value=IntPopup; " Default Lytebox v4.0 supplied with FH"; " Updated Lytebox v5.5 from lytebox.com"; " Customised version with Zoom & Scroll"; " Customised version Large Screen popup"; " Customised version Dojo Zoomer popup"; " None - popups completely inhibited"; }	-- V2.4 Dojo and None added
	local hbxPopup  = iup.hbox		{ btnMedia; lblPopup; lstPopup; }
	local btnPopup  = iup.button	{ Title="Convert all media file Popups to one of the alternative versions chosen above"; }
	local txtPopup  = iup.text		{ Value=strInitialText; ReadOnly="YES"; Border="NO"; }
	local vbxPopup  = iup.vbox		{ hbxPopup; iup.hbox{ btnPopup; Margin="99x0"; }; txtPopup; }	-- V3.0
	-- Tree Diagrams tab
	local tglAlso   = iup.toggle	{ Title=" Retain 'See also' links at the top: "; Value=StrAlso; RightButton="YES"; }	-- V3.2
	local tglMini   = iup.toggle	{ Title=" Align to left instead of in centre: "; Value=StrMini; RightButton="YES"; }	-- V3.2
	local hbxTrees  = iup.hbox		{ tglAlso; tglMini; Homogeneous="YES"; }							-- V3.2
	local btnAddMin = iup.button	{ Title="Insert GEDmill minitrees into featured pages"; }		-- V3.2
	local btnRemMin = iup.button	{ Title="Remove GEDmill minitrees from featured pages"; }		-- V3.2
	local txtTrees  = iup.text		{ Value=strInitialText; ReadOnly="YES"; Border="NO"; }			-- V3.2
	local vbxTrees  = iup.vbox		{ hbxTrees; iup.hbox{ btnAddMin; btnRemMin; Margin="99x0"; }; txtTrees; }	-- V3.2
	-- Content Tables tab
	local tglToPs   = iup.toggle	{ Title=" Table of Pictures: "; Value=StrToPs; RightButton="YES"; }
	local tglToRs   = iup.toggle	{ Title="  Table of Reports: "; Value=StrToRs; RightButton="YES"; }
	local tglToDs   = iup.toggle	{ Title="Table of Downloads: "; Value=StrToDs; RightButton="YES"; }
	local tglMenu   = iup.toggle	{ Title="     Links in Menu: "; Value=StrMenu; RightButton="YES"; }
	local hbxTable  = iup.hbox		{ tglToPs; tglToRs; tglToDs; tglMenu; Homogeneous="YES"; }
	local btnTable  = iup.button	{ Title="Adjust custom Tables for each type of Contents item chosen above"; }
	local txtTable  = iup.text		{ Value=strInitialText; ReadOnly="YES"; Border="NO"; }
	local vbxTable  = iup.vbox		{ hbxTable; iup.hbox{ btnTable; Margin="99x0"; }; txtTable; }	-- V3.0
	-- Index of Names tab
	local tglFilter = iup.toggle	{ Title="Filter:"; Value=StrFilter; RightButton="YES"; }			-- V2.5
	local lblLength	= iup.label	{ Title=" Surname:"; } 													-- V3.0 -- V3.2
	local maxLength	= iup.text	{ Spin="YES"; Size=28; SpinValue=30; SpinMin=1; SpinMax=99; }	-- V3.0
	local lblNames  = iup.label	{ Title=" Names:"; }
	local lstNames  = iup.list		{ DropDown="YES"; Visible_Items="9"; VisibleColumns="12"; Value=IntNames; "Default Primary Names"; "+Alternate Names only"; "+Married Surnames only"; "+Alternate/Married Names"; }
	local lblStyle  = iup.label	{ Title=" Style:"; }
	local lstStyle  = iup.list		{ DropDown="YES"; Visible_Items="9"; VisibleColumns="8"; Value=IntStyle; "Italics only"; "Underline only"; "Italics+Underline"; }
	local tglIdRiD  = iup.toggle	{ Title=" RiD:"; Value=StrIdRiD; RightButton="YES"; }				-- V3.2
	local tglIdPRN  = iup.toggle	{ Title=" PRN:"; Value=StrIdPRN; RightButton="YES"; }				-- V3.2
	local tglIdCiD  = iup.toggle	{ Title=" CiD:"; Value=StrIdCiD; RightButton="YES"; }				-- V3.2
	local tglIdARI  = iup.toggle	{ Title=" ARI:"; Value=StrIdARI; RightButton="YES"; }				-- V3.2
	local tglIdUID  = iup.toggle	{ Title=" UID:"; Value=StrIdUID; RightButton="YES"; }				-- V3.2
	local tglIdFSI  = iup.toggle	{ Title=" FSI:"; Value=StrIdFSI; RightButton="YES"; }				-- V3.2
	local hbxIndex  = iup.hbox		{ tglFilter; lblLength; maxLength; lblNames; lstNames; lblStyle; lstStyle; tglIdRiD; tglIdPRN; tglIdCiD; tglIdARI; }	-- V3.2
	if fhGetAppVersion() > 6 then hbxIndex:append( tglIdUID ) hbxIndex:append( tglIdFSI ) end
	local btnIndex  = iup.button	{ Title="Adjust Search Filter, Surname max length, Alternate Names / Married Women Surnames, and Idents"; }
	local txtIndex  = iup.text		{ Value=strInitialText; ReadOnly="YES"; Border="NO"; }
	local vbxIndex  = iup.vbox		{ hbxIndex; iup.hbox{ btnIndex; Margin="99x0"; }; txtIndex; }	-- V3.0
	-- Create GenDex tab
	local lblGenDex = iup.label	{ Title=" Exclusion Flags:"; }
	local lstGenDex = iup.list		{ DropDown="YES"; Visible_Items="9"; Value=IntGenDex; " None"; " Private only"; " Living only"; " Private & Living"; }
	local hbxGenDex = iup.hbox		{ lblGenDex; lstGenDex; }
	local btnGenDex = iup.button	{ Title="Create a 'gendex.txt' file excluding Individuals with chosen flags"; }
	local txtGenDex = iup.text		{ Value=strInitialText; ReadOnly="YES"; Border="NO"; }
	local vbxGenDex = iup.vbox		{ hbxGenDex; iup.hbox{ btnGenDex; Margin="99x0"; }; txtGenDex; }	-- V3.0
	-- Apply Language tab
	local lblDoLang = iup.label	{ Title=" Apply translations"..StrTranslate("Output_Language"); }				-- V3.2
	local hbxDoLang = iup.hbox		{ lblDoLang; }
	local btnDoLang = iup.button	{ Title="Apply the chosen Output Language to all page menus and headings"; }	-- V3.2
	local txtDoLang = iup.text		{ Value=strInitialText; ReadOnly="YES"; Border="NO"; }							-- V3.2
	local vbxDoLang = iup.vbox		{ hbxDoLang; iup.hbox{ btnDoLang; Margin="99x0"; }; txtDoLang; }				-- V3.2
	-- Shared buttons
	local btnDefault= iup.button	{ Title="Restore Defaults"; }
	local btnSetFont= iup.button	{ Title="Set Window Fonts"; }
	local btnUpdates= iup.button	{ Title="Check for Updates"; }				-- V3.3
	local btnGetHelp= iup.button	{ Title="Help && Advice"; }
	local btnDestroy= iup.button	{ Title="Close Plugin"; }

	-- Create the Tab controls layout
	vbxHyper. TabTitle="  Hyperlinks / Text  "
	vbxPopup. TabTitle="   Media  Popups   "
	vbxTrees. TabTitle="   Tree Diagrams   "										-- V3.2
	vbxTable. TabTitle="  Content Tables   "
	vbxIndex. TabTitle="  Index of Names   "
	vbxGenDex.TabTitle="   Create GenDex   "
	vbxDoLang.TabTitle="  Apply Language   "										-- V3.2
	local tabCont = iup.tabs { vbxHyper; vbxPopup; vbxTrees; vbxTable; vbxIndex; vbxGenDex; }
	if fhGetAppVersion() > 6 then tabCont:append( vbxDoLang ) end

	-- Combine all the above controls
	local allCont  = iup.vbox {
								iup.hbox	{ vbxFolder;	};
								iup.hbox	{ tabCont;	};
								iup.hbox	{ btnDefault; btnSetFont; btnUpdates; btnGetHelp; btnDestroy; Homogeneous="YES"; }	-- V3.3
 							}

	-- Create dialogue and turn off resize, maximize, minimize, and menubox except Close button
	local dialogMain =	iup.dialog { Title=iup_gui.Plugin..iup_gui.Version..StrTranslate("Output_Language");	-- V3.2
								allCont;
							}

	local function setStyleList(strMode)												-- Disable Style option when only Primary Names included
		if lstNames[IntNames]:match(" Primary ") then strMode = "NO" end
		lstStyle.Active = strMode
	end -- local function setStyleList

	local function setActiveGUI(strMode)												-- Disable GUI options when invalid folder and during button operations
		dialogMain.Active= strMode
		vbxHyper.Active  = strMode
		vbxPopup.Active  = strMode
		vbxTrees.Active  = strMode														-- V3.2
		vbxTable.Active  = strMode
		vbxIndex.Active  = strMode
		vbxGenDex.Active = strMode
		btnMedia.Active  = strMode														-- V2.9
		setStyleList(strMode)
	end -- local function setActiveGUI

	local function setNumberOfText(itemName,intNumber,strOld,strNew)			-- Insert number into text status message for each tab
		if intNumber >= 0 then
			local strText = itemName.Tip:gsub("Number of",tostring(intNumber))
			if strOld and strNew then
				strText = strText:gsub(strOld,strNew)								-- Adjust wording of tip
			end
			if intNumber == 1 then
				strText = strText:gsub("s "," ",1)									-- Remove plural "s" if number is 1
			end
			itemName.Value = strText
		end
	end -- local function setNumberOfText

	local function getShortFolder()													-- Get short HTML folder path -- V3.3
		local strPath = StrFolder
		local intPath = #strPath
		if intPath > 120 then															-- Constrain length of Export folder path
			local arrDir = strPath:split("\\")
			local intDir = 1
			local intSum = 0
			repeat
				local strDir = arrDir[intDir]
				intPath = intPath - #strDir - 1										-- Subtract each subfolder length from path length
				if intSum <= 20 then
					intSum = intSum + #strDir + 1										-- Retain at least 20 characters of leading path
					intDir = intDir + 1
				else
					if intPath > 120 then
						table.remove(arrDir,intDir)									-- Remove subfolders from path to reduce length below 120 characters
					else
						arrDir[intDir] = " ... "										-- Insert ellipsis in place of removed subfolders
						break
					end
				end
			until false
			strPath = table.concat(arrDir,"\\")										-- Rebuild constrained path
		end
		return strPath
	end -- local function getShortFolder

	local function isFolderOK()														-- Check if folder contains FH Website or CD-DVD HTML files and set global paths
		local strNameIndex = StrFolder.."\\_nameindex.html"
		local isOK = general.FlgFileExists(strNameIndex) and general.FlgFileExists(StrFolder.."\\fhstyle.css")
		if isOK then
			local intLine = 0
			local strLoad = general.StrLoadFromFile(strNameIndex)
			for strLine in strLoad:gmatch("(.-)\r?\n") do							-- Search the _nameindex.html file	-- V3.3
				intLine = intLine + 1
				if intLine == 1 then
					if not strLine:match(" XHTML ")									-- First line for FH V5 & V6 contains XHTML, earlier versions do not
					and fhGetAppVersion() < 7 then									-- First line for FH V7 also does not contain XHTML				-- V3.1
						isOK = false						
						break
					end
				elseif intLine < 30 then												-- Find custom style CSS subfolder path and Home page HTML filename -- V3.0
					local strStyleCSS = strLine:match('^<link rel="stylesheet".+href="(.+/.+css)" ?/?>$')	-- FH V7 CSS line not on new line -- V3.1 -- FH V7.0.8 is on new line -- V3.2
					if strStyleCSS then StrStyleCSS = strStyleCSS end
					local strHomeHTML = strLine:match('^<li><span><a href="([^_].+)">.+</a></span></li>$') -- Allow for translated Home menu entry -- V3.2	
 					if strHomeHTML then StrHomeHTML = strHomeHTML end
				else
					break
				end
			end
		end
		if isOK then
			setActiveGUI("YES")
			txtStatus.Value = "The HTML folder is valid, so please use any of the improvement option tabs below"
			txtStatus.FgColor = iup_gui.Safe
			txtFolder.FgColor = iup_gui.Info
		else
			setActiveGUI("NO")
			txtStatus.Value = "Folder does NOT contain FH V5 or later Website or CD-DVD HTML files, so use Browse button"
			txtStatus.FgColor = iup_gui.Warn
			txtFolder.FgColor = iup_gui.Warn
		end
		txtFolder.Value = getShortFolder()											-- V3.3
		dialogMain.Active = "YES"
		btnMedia.Active = "YES"															-- "Turn non-image Media into icons" button must always be active -- V2.9
		return isOK
	end -- local function isFolderOK

	local function setControls()														-- Reset GUI control values
		lstPages.Value	= IntPages
		lstChars.Value	= IntChars
		lstTabSep.Value	= IntTabSep
		tglBorder.Value	= StrBorder													-- V3.3
		txtHyper.Value	= strInitialText
		lstPopup.Value	= IntPopup
		txtPopup.Value	= strInitialText
		tglAlso.Value		= StrAlso														-- V3.2
		tglMini.Value		= StrMini														-- V3.2
		txtTrees.Value	= strInitialText												-- V3.2
		tglToPs.Value		= StrToPs
		tglToRs.Value		= StrToRs
		tglToDs.Value		= StrToDs
		tglMenu.Value		= StrMenu
		txtTable.Value	= strInitialText
		tglFilter.Value	= StrFilter													-- V2.5
		maxLength.SpinValue = IntLength												-- V3.0
		lstNames.Value	= IntNames
		lstStyle.Value	= IntStyle
		tglIdRiD.Value	= StrIdRiD													-- V3.2
		tglIdPRN.Value	= StrIdPRN													-- V3.2
		tglIdCiD.Value	= StrIdCiD													-- V3.2
		tglIdARI.Value	= StrIdARI													-- V3.2
		tglIdUID.Value	= StrIdUID													-- V3.2
		tglIdFSI.Value	= StrIdFSI													-- V3.2
		txtIndex.Value	= strInitialText
		lstGenDex.Value	= IntGenDex
		txtGenDex.Value	= strInitialText
		tabCont.ValuePos	= math.max(0,IntTabPosn - 1)								-- Adjust tab selection min value = 0	-- 31 July 2013
		isFolderOK()																		-- Adjust buttons according to current folder, etc
	end -- local function setControls

	-- Set other GUI control attributes
	local tblControls={{"Font";"FgColor";"Alignment";"Expand";"Padding";"Gap";"Margin";"Tip";{"TipBalloon";"Balloon"};{"help_cb";function() iup_gui.HelpDialogue(0) end};setControls};
		[btnFolder] = { "FontHead"; "Safe"; false    ; "YES"; "4x8"; false; false; " Click here to choose HTML folder "; };
		[txtFolder] = { "FontBody"; "Body"; "ACENTER"; "YES"; "0x8"; false; false; " Chosen HTML folder full path "; };
		[txtStatus] = { "FontBody"; "Body"; "ACENTER"; "YES"; "4x8"; false; false; " Advisory HTML folder message "; };
		[vbxFolder] = { "FontBody"; "Body"; "ACENTER"; "YES"; false; "10" ; false; false; };
		-- Hyperlinks / Text tab
		[lblPages]  = { "FontBody"; "Body"; "ARIGHT" ; "NO" ; "0x8"; false; false; " Choose URL target attribute "; };
		[lstPages]  = { "FontBody"; "Safe"; false    ; "NO" ; "0x8"; false; false; " Choose URL target attribute "; };
		[lblChars]  = { "FontBody"; "Body"; "ARIGHT" ; "NO" ; "0x8"; false; false; " Choose URL text abbreviation length "; };
		[lstChars]  = { "FontBody"; "Safe"; false    ; "NO" ; "0x8"; false; false; " Choose URL text abbreviation length "; };
		[lblTabSep] = { "FontBody"; "Body"; "ARIGHT" ; "NO" ; "0x8"; false; false; " Choose column tab separator characters "; };
		[lstTabSep] = { "FontBody"; "Safe"; false    ; "NO" ; "0x8"; false; false; " Choose column tab separator characters "; };
		[tglBorder] = { "FontBody"; "Safe"; false    ; "NO" ; false; false; false; " Enable borders on tables and cells ? "; };	-- V3.3
		[hbxHyper]  = { "FontBody"; "Body"; "ACENTER"; "YES"; false; "4"  ; "0x0"; false; };
		[btnHyper]  = { "FontHead"; "Safe"; false    ; "YES"; "0x8"; false; false; " Click here to convert URL Hyperlinks and Hypertext "; };
		[txtHyper]  = { "FontBody"; "Body"; "ACENTER"; "YES"; "0x8"; false; false; " Number of converted lines of Hyperlinks / Text in the HTML folder pages "; };
		[vbxHyper]  = { "FontBody"; "Body"; "ACENTER"; "YES"; false; "10" ; false; false; };
		-- Media Popups tab
		[btnMedia]  = { "FontHead"; "Safe"; false    ; "NO" ; "8x4"; false; false; " Temporarily turn each non-image Media into a JPG icon \n See Help & Advice for full details before using this button "; };	-- V2.8 -- V3.0
		[lblPopup]  = { "FontBody"; "Body"; "ARIGHT" ; "NO" ; "0x8"; false; false; " Choose image popup version "; };
		[lstPopup]  = { "FontBody"; "Safe"; false    ; "NO" ; "0x8"; false; false; " Choose image popup version "; };
		[hbxPopup]  = { "FontBody"; "Body"; "ACENTER"; "YES"; false; "4"  ; "0x0"; false; };
		[btnPopup]  = { "FontHead"; "Safe"; false    ; "YES"; "0x8"; false; false; " Click here to convert media file Popups "; };
		[txtPopup]  = { "FontBody"; "Body"; "ACENTER"; "YES"; "0x8"; false; false; " Number of changed non-image Media records or HTML folder files for media Popups "; };
		[vbxPopup]  = { "FontBody"; "Body"; "ACENTER"; "YES"; false; "10" ; false; false; };
		-- Tree Diagrams tab
		[tglAlso]   = { "FontBody"; "Safe"; false    ; "NO" ; false; false; false; " Retain 'See also' links section at top ? "; };		-- V3.2
		[tglMini]   = { "FontBody"; "Safe"; false    ; "NO" ; false; false; false; " Align minitrees to left instead of centre ? "; };
		[hbxTrees]  = { "FontBody"; "Body"; "ACENTER"; "YES"; false; "60" ; "0x8"; false; };													-- V3.2
		[btnAddMin] = { "FontHead"; "Safe"; false    ; "YES"; "0x8"; false; false; " Click here to insert GEDmill minitrees "; };		-- V3.2
		[btnRemMin] = { "FontHead"; "Safe"; false    ; "YES"; "0x8"; false; false; " Click here to remove GEDmill minitrees "; };		-- V3.2
		[txtTrees]  = { "FontBody"; "Body"; "ACENTER"; "YES"; "0x8"; false; false; " Number of HTML folder featured pages with GEDmill minitrees updated "; };
		[vbxTrees]  = { "FontBody"; "Body"; "ACENTER"; "YES"; false; "10" ; false; false; };													-- V3.2
		-- Content Tables tab
		[tglToPs]   = { "FontBody"; "Safe"; false    ; "NO" ; false; false; false; " Create a Table of Picture Images ? "; };
		[tglToRs]   = { "FontBody"; "Safe"; false    ; "NO" ; false; false; false; " Create a Table of all Reports ? "; };
		[tglToDs]   = { "FontBody"; "Safe"; false    ; "NO" ; false; false; false; " Create a Table of File Downloads ? "; };
		[tglMenu]   = { "FontBody"; "Safe"; false    ; "NO" ; false; false; false; " Include links in the Menu Bar ? "; };
		[hbxTable]  = { "FontBody"; "Body"; "ACENTER"; "YES"; false; "4"  ; "0x8"; false; };
		[btnTable]  = { "FontHead"; "Safe"; false    ; "YES"; "0x8"; false; false; " Click here to create custom Tables of Contents "; };
		[txtTable]  = { "FontBody"; "Body"; "ACENTER"; "YES"; "0x8"; false; false; " Number of HTML folder pages changed due to the Contents item Tables chosen "; };
		[vbxTable]  = { "FontBody"; "Body"; "ACENTER"; "YES"; false; "10" ; false; false; };
		-- Index of Names tab
		[tglFilter] = { "FontBody"; "Safe"; false    ; "NO" ; false; false; false; " Create the Names Search Filter form ? "; };			-- V2.5 
		[lblLength] = { "FontBody"; "Body"; "ARIGHT" ; "NO" ; "0x0"; false; false; " Set maximum length of Surnames in 1st column "; };	-- V3.0
		[maxLength] = { "FontBody"; "Safe"; "ARIGHT" ; "NO" ; "0x0"; false; false; " Set maximum length of Surnames in 1st column "; };	-- V3.0
		[lblNames]  = { "FontBody"; "Body"; "ARIGHT" ; "NO" ; "0x8"; false; false; " Choose Names to include in Index "; };
		[lstNames]  = { "FontBody"; "Safe"; false    ; "NO" ; "0x8"; false; false; " Choose Names to include in Index "; };
		[lblStyle]  = { "FontBody"; "Body"; "ARIGHT" ; "NO" ; "0x8"; false; false; " Choose font style of additional Names "; };
		[lstStyle]  = { "FontBody"; "Safe"; false    ; "NO" ; "0x8"; false; false; " Choose font style of additional Names "; };
		[tglIdRiD]  = { "FontBody"; "Safe"; false    ; "NO" ; false; false; false; " Include the Record Identity ? "		; };	-- V3.2 
		[tglIdPRN]  = { "FontBody"; "Safe"; false    ; "NO" ; false; false; false; " Include the Permanent Record No ? "; };		-- V3.2 
		[tglIdCiD]  = { "FontBody"; "Safe"; false    ; "NO" ; false; false; false; " Include the Custom Identity ? "		; };	-- V3.2 
		[tglIdARI]  = { "FontBody"; "Safe"; false    ; "NO" ; false; false; false; " Include the Automatic Record Id ? "; };		-- V3.2 
		[tglIdUID]  = { "FontBody"; "Safe"; false    ; "NO" ; false; false; false; " Include the Unique Identity ? "		; };	-- V3.2 
		[tglIdFSI]  = { "FontBody"; "Safe"; false    ; "NO" ; false; false; false; " Include the Family Search Id ? "	; };		-- V3.2 
		[hbxIndex]  = { "FontBody"; "Body"; "ACENTER"; "YES"; false; "4"  ; "0x0"; false; };
		[btnIndex]  = { "FontHead"; "Safe"; false    ; "YES"; "0x8"; false; false; " Click here to convert Index of Names "; };
		[txtIndex]  = { "FontBody"; "Body"; "ACENTER"; "YES"; "0x8"; false; false; " Number of Names processed in the 'Index of Names' page "; };
		[vbxIndex]  = { "FontBody"; "Body"; "ACENTER"; "YES"; false; "10" ; false; false; };
		-- Create GenDex tab
		[lblGenDex] = { "FontBody"; "Body"; "ARIGHT" ; "NO" ; "0x8"; false; false; " Choose flags to exclude Individuals "; };
		[lstGenDex] = { "FontBody"; "Safe"; false    ; "NO" ; "0x8"; false; false; " Choose flags to exclude Individuals "; };
		[hbxGenDex] = { "FontBody"; "Body"; "ACENTER"; "YES"; false; "4"  ; "0x0"; false; };
		[btnGenDex] = { "FontHead"; "Safe"; false    ; "YES"; "0x8"; false; false; " Click here to create 'gendex.txt' file "; };
		[txtGenDex] = { "FontBody"; "Body"; "ACENTER"; "YES"; "0x8"; false; false; " Number of Individuals included in a new 'gendex.txt' file "; };
		[vbxGenDex] = { "FontBody"; "Body"; "ACENTER"; "YES"; false; "10" ; false; false; };
		-- Apply Language tab
		[lblDoLang] = { "FontBody"; "Body"; "ARIGHT" ; "NO" ; "0x8"; false; false; " Apply translations"..StrTranslate("Output_Language"); };				-- V3.2
		[hbxDoLang] = { "FontBody"; "Body"; "ACENTER"; "YES"; false; "4"  ; "0x0"; false; };
		[btnDoLang] = { "FontHead"; "Safe"; false    ; "YES"; "0x8"; false; false; " Click here to apply current Output Language to page headings "; };	-- V3.2
		[txtDoLang] = { "FontBody"; "Body"; "ACENTER"; "YES"; "0x8"; false; false; " Number of HTML folder pages translated to Output Language "; };	-- V3.2
		[vbxDoLang] = { "FontBody"; "Body"; "ACENTER"; "YES"; false; "10" ; false; false; };
		-- Shared buttons
		[btnDefault]= { "FontBody"; "Safe"; false    ; "YES"; "4x6"; false; false; " Restore all tab option settings, and window positions and sizes "; };
		[btnSetFont]= { "FontBody"; "Safe"; false    ; "YES"; "4x6"; false; false; " Choose user interface window font styles "; };
		[btnUpdates]= { "FontBody"; "Safe"; false    ; "YES"; "4x6"; false; false; " Check for a later version in the Plugin Store "; };	-- V3.3
		[btnGetHelp]= { "FontBody"; "Safe"; false    ; "YES"; "4x6"; false; false; " Obtain online Help and Advice pages "; };
		[btnDestroy]= { "FontBody"; "Risk"; false    ; "YES"; "4x6"; false; false; " Close this Plugin "; };

		[tabCont]   = { "FontHead"; "Safe"; false    ; false; false; false; false; " Select required improvement option tab "; }; -- V3.1
		[allCont]   = { "FontBody"; "Body"; false    ; false; false; "6"  ; "3x8"; false; };
		}

	iup_gui.AssignAttributes(tblControls)											-- Assign GUI control attributes

	if fhGetAppVersion() > 6 then														-- FH V7 IUP 3.28
		tabCont.TabPadding = "4x4"														-- V3.2 -- was 26x4
	else																					-- FH V6 IUP 3.11
		tabCont.Padding = "4x4"															-- V3.2 -- was 26x4
	end

	function btnFolder:action()														-- Action for Folder button
		repeat
			local strDirectory = StrFolder
			if not general.FlgFolderExists(StrFolder) then strDirectory = StrPublic end
			local dialogFolder = iup.filedlg { DialogType="DIR"; Title="Please select the Project exported Website, CD, DVD or equivalent HTML folder"; Directory=strDirectory; }
			dialogFolder:popup(iup.CENTERPARENT,iup.CENTERPARENT)					-- V3.3
			local strStatus = dialogFolder.Status
			if strStatus == "0"
			and StrFolder ~= dialogFolder.Value then
				StrFolder = dialogFolder.Value
				SaveSettings()															-- Save sticky data settings
				txtHyper.Value  = strInitialText
				txtPopup.Value  = strInitialText
				txtTrees.Value  = strInitialText										-- V3.2
				txtIndex.Value  = strInitialText
				txtGenDex.Value = strInitialText
			end
		until isFolderOK() or strStatus == "-1"
	end -- function btnFolder:action

	function lstPages:action(strText,intItem,intState)							-- Action for Pages dropdown
		if intState == 1 then
			IntPages = intItem
			SaveSettings()																-- Save sticky data settings
		end
	end -- function lstPages:action

	function lstChars:action(strText,intItem,intState)							-- Action for Chars dropdown
		if intState == 1 then
			IntChars = intItem
			SaveSettings()																-- Save sticky data settings
		end
	end -- function lstChars:action

	function lstTabSep:action(strText,intItem,intState)							-- Action for TabSep dropdown
		if intState == 1 then
			IntTabSep = intItem
			SaveSettings()																-- Save sticky data settings
		end
	end -- function lstTabSep:action

	function tglBorder:action(iState)													-- Action for table Border setting
		if iState == 0 then
			StrBorder = "OFF"
		elseif iState == 1 then
			StrBorder = "ON"
		else
			iup_gui.MemoDialogue("tglBorder invalid iState")
			Strlso = "ERROR"
		end
		SaveSettings()																	-- Save sticky data settings
	end -- function tglBorder:action

	function btnHyper:action()															-- Action for Hyper button
		if isFolderOK() then
			setActiveGUI("NO")
			local intLines = IntImproveHTML(StrFolder,tonumber(IntPages),tonumber(IntChars),lstTabSep[IntTabSep])
			setNumberOfText(txtHyper,intLines)
			setActiveGUI("YES")
			dialogMain.BringFront = "YES"
		end
	end -- function btnHyper:action

	function btnMedia:action()															-- Action for Media button	-- V2.8 Unconditional -- V3.0
		setActiveGUI("NO")
		local strAns = 1
		if not isFolderOK() then														-- V3.2
			strAns = iup_gui.WarnDialogue("Confirm Usage"," This is intended only for use with FH Website/CD/DVD HTML pages \n The next step would be Publish > Create a Website/CD/DVD wizard \n If that is not your purpose then please Cancel now \n","OK","Cancel")
		end
		if strAns == 1 then
			local intLines = IntMediaIcons()
			if intLines >= 0 then
				setNumberOfText(txtPopup,intLines)
				iup_gui.MemoDialogue(" Non-image Media icons prepared, so now Close Plugin and use \n\n Publish > Create a Website/CD/DVD wizard \n or \n Edit > Undo Plugin Updates if not wanted \n")
			end
			setActiveGUI("YES")
			dialogMain.BringFront = "YES"
		end
	end -- function btnMedia:action

	function lstPopup:action(strText,intItem,intState)							-- Action for Popup dropdown
		if intState == 1 then
			IntPopup = intItem
			SaveSettings()																-- Save sticky data settings
		end
	end -- function lstPopup:action

	function btnPopup:action()															-- Action for Popup button
		if isFolderOK() then
			setActiveGUI("NO")
			local intLines = IntImprovePopup(StrFolder,lstPopup[IntPopup])
			setNumberOfText(txtPopup,intLines)
			setActiveGUI("YES")
			dialogMain.BringFront = "YES"
		end
	end -- function btnPopup:action

	function tglAlso:action(iState)													-- Action for See Also links setting
		if iState == 0 then
			StrAlso = "OFF"
		elseif iState == 1 then
			StrAlso = "ON"
		else
			iup_gui.MemoDialogue("tglAlso invalid iState")
			Strlso = "ERROR"
		end
		SaveSettings()																	-- Save sticky data settings
	end -- function tglAlso:action

	function tglMini:action(iState)													-- Action for Minitree alignment setting
		if iState == 0 then
			StrMini = "OFF"
		elseif iState == 1 then
			StrMini = "ON"
		else
			iup_gui.MemoDialogue("tglMini invalid iState")
			Strlso = "ERROR"
		end
		SaveSettings()																	-- Save sticky data settings
	end -- function tglMini:action

	function btnAddMin:action()														-- Action for Update GEDmill Minitrees button -- V3.2
		if isFolderOK() then
			setActiveGUI("NO")
			local intTrees = IntAddMiniTrees(StrFolder)
			setNumberOfText(txtTrees,intTrees)
			setActiveGUI("YES")
			dialogMain.BringFront = "YES"
		end
	end -- function btnAddMin:action

	function btnRemMin:action()														-- Action for Remove GEDmill Minitrees button -- V3.2
		if isFolderOK() then
			setActiveGUI("NO")
			local intTrees = IntRemMiniTrees(StrFolder)
			setNumberOfText(txtTrees,intTrees,"updated","removed")
			setActiveGUI("YES")
			dialogMain.BringFront = "YES"
		end
	end -- function btnRemMin:action

	function tglToPs:action(iState)													-- Action for Table of Pictures
		if iState == 0 then
			StrToPs = "OFF"
		elseif iState == 1 then
			StrToPs = "ON"
		else
			iup_gui.MemoDialogue("tglToPs invalid iState")
			StrToPs = "ERROR"
		end
		SaveSettings()																	-- Save sticky data settings
	end -- function tglToPs:action

	function tglToRs:action(iState)													-- Action for Table of Reports
		if iState == 0 then
			StrToRs = "OFF"
		elseif iState == 1 then
			StrToRs = "ON"
		else
			iup_gui.MemoDialogue("tglToRs invalid iState")
			StrToRs = "ERROR"
		end
		SaveSettings()																	-- Save sticky data settings
	end -- function tglToRs:action

	function tglToDs:action(iState)													-- Action for Table of Downloads
		if iState == 0 then
			StrToDs = "OFF"
		elseif iState == 1 then
			StrToDs = "ON"
		else
			iup_gui.MemoDialogue("tglToDs invalid iState")
			StrToDs = "ERROR"
		end
		SaveSettings()																	-- Save sticky data settings
	end -- function tglToDs:action

	function tglMenu:action(iState)													-- Action for Menu Bar setting
		if iState == 0 then
			StrMenu = "OFF"
		elseif iState == 1 then
			StrMenu = "ON"
		else
			iup_gui.MemoDialogue("tglMenu invalid iState")
			StrMenu = "ERROR"
		end
		SaveSettings()																	-- Save sticky data settings
	end -- function tglMenu:action

	function btnTable:action()															-- Action for Table button
		if isFolderOK() then
			setActiveGUI("NO")
			local intTable = IntImproveTable(StrFolder,StrToPs=="ON",StrToRs=="ON",StrToDs=="ON",StrMenu=="ON")
			setNumberOfText(txtTable,intTable)
			setActiveGUI("YES")
			dialogMain.BringFront = "YES"
		end
	end -- function btnTable:action

	function tglFilter:action(iState)													-- V2.5 -- Action for Search Filter setting
		if iState == 0 then
			StrFilter = "OFF"
		elseif iState == 1 then
			StrFilter = "ON"
		else
			iup_gui.MemoDialogue("tglFilter invalid iState")
			StrFilter = "ERROR"
		end
		SaveSettings()																	-- Save sticky data settings
	end -- function tglFilter:action

	function maxLength:valuechanged_cb()												-- Action for Length spin value
		maxLength.SpinValue = math.min(tonumber(maxLength.SpinValue),tonumber(maxLength.SpinMax))
		IntLength = tonumber(maxLength.SpinValue)
		SaveSettings()																	-- Save sticky data settings
	end -- function maxLength:valuechanged_cb

	function lstNames:action(strText,intItem,intState)							-- Action for Names dropdown
		if intState == 1 then
			IntNames = intItem
			SaveSettings()																-- Save sticky data settings
			setStyleList("YES")
		end
	end -- function lstNames:action

	function lstStyle:action(strText,intItem,intState)							-- Action for Style dropdown
		if intState == 1 then
			IntStyle = intItem
			SaveSettings()																-- Save sticky data settings
		end
	end -- function lstStyle:action

	function tglIdRiD:action(iState)													-- V3.2 -- Action for RiD setting
		if iState == 0 then
			StrIdRiD = "OFF"
		elseif iState == 1 then
			StrIdRiD = "ON"
		else
			iup_gui.MemoDialogue("tglIdRiD invalid iState")
			StrFilter = "ERROR"
		end
		SaveSettings()																	-- Save sticky data settings
	end -- function tglIdRiD:action

	function tglIdPRN:action(iState)													-- V3.2 -- Action for PRN setting
		if iState == 0 then
			StrIdPRN = "OFF"
		elseif iState == 1 then
			StrIdPRN = "ON"
		else
			iup_gui.MemoDialogue("tglIdPRN invalid iState")
			StrFilter = "ERROR"
		end
		SaveSettings()																	-- Save sticky data settings
	end -- function tglIdPRN:action

	function tglIdCiD:action(iState)													-- V3.2 -- Action for CiD setting
		if iState == 0 then
			StrIdCiD = "OFF"
		elseif iState == 1 then
			StrIdCiD = "ON"
		else
			iup_gui.MemoDialogue("tglIdCiD invalid iState")
			StrFilter = "ERROR"
		end
		SaveSettings()																	-- Save sticky data settings
	end -- function tglIdCiD:action

	function tglIdARI:action(iState)													-- V3.2 -- Action for ARI setting
		if iState == 0 then
			StrIdARI = "OFF"
		elseif iState == 1 then
			StrIdARI = "ON"
		else
			iup_gui.MemoDialogue("tglIdARI invalid iState")
			StrFilter = "ERROR"
		end
		SaveSettings()																	-- Save sticky data settings
	end -- function tglIdARI:action

	function tglIdUID:action(iState)													-- V3.2 -- Action for UID setting
		if iState == 0 then
			StrIdUID = "OFF"
		elseif iState == 1 then
			StrIdUID = "ON"
		else
			iup_gui.MemoDialogue("tglIdUID invalid iState")
			StrFilter = "ERROR"
		end
		SaveSettings()																	-- Save sticky data settings
	end -- function tglIdUID:action

	function tglIdFSI:action(iState)													-- V3.2 -- Action for FSI setting
		if iState == 0 then
			StrIdFSI = "OFF"
		elseif iState == 1 then
			StrIdFSI = "ON"
		else
			iup_gui.MemoDialogue("tglIdFSI invalid iState")
			StrFilter = "ERROR"
		end
		SaveSettings()																	-- Save sticky data settings
	end -- function tglIdFSI:action

	function btnIndex:action()															-- Action for Index button
		if isFolderOK() then
			setActiveGUI("NO")
			local intNames = IntImproveIndex(StrFolder,StrFilter=="ON",lstNames[IntNames],lstStyle[IntStyle])	-- V2.5 StrFilter -- V3.2 remove lstIdent
			setNumberOfText(txtIndex,intNames)
			setActiveGUI("YES")
			dialogMain.BringFront = "YES"
		end
	end -- function btnIndex:action

	function lstGenDex:action(strText,intItem,intState)							-- Action for GenDex dropdown
		if intState == 1 then
			IntGenDex = intItem
			SaveSettings()																-- Save sticky data settings
		end
	end -- function lstGenDex:action

	function btnGenDex:action()														-- Action for GenDex button
		if isFolderOK() then
			setActiveGUI("NO")
			local intNames = IntCreateGenDex(StrFolder,lstGenDex[IntGenDex])
			setNumberOfText(txtGenDex,intNames)
			setActiveGUI("YES")
			dialogMain.BringFront = "YES"
		end
	end -- function btnGenDex:action

	function btnDoLang:action()														-- Action for Apply Language button -- V3.2
		if isFolderOK() then
			setActiveGUI("NO")
			local intPages = IntApplyLanguage(StrFolder)
			setNumberOfText(txtDoLang,intPages)
			setActiveGUI("YES")
			dialogMain.BringFront = "YES"
		end
	end -- function btnDoLang:action

	function btnDefault:action()														-- Action for Restore Defaults button
		ResetDefaultSettings()
		setControls()																		-- Reset controls & redisplay Main dialogue
		iup_gui.ShowDialogue("Main")
		iup_gui.DefaultDialogue()														-- V3.3
		SaveSettings()																	-- Save sticky data settings
	end -- function btnDefault:action

	function btnSetFont:action()														-- Action for Set Interface Fonts button
		setActiveGUI("NO")
		iup_gui.FontDialogue(tblControls)
		SaveSettings()																	-- Save sticky data settings
		isFolderOK()																		-- Only enable GUI if HTML folder exists	-- V3.1
	end -- function btnSetFont:action

	function btnSetFont:button_cb(intButton,intPress)								-- Action for mouse right-click on Set Window Fonts button
		if intButton == iup.BUTTON3 and intPress == 0 then
			iup_gui.BalloonToggle()														-- Toggle tooltips Balloon mode
		end
	end -- function btnSetFont:button_cb

	function btnUpdates:action()														-- Action for Check for Updates button	-- V3.3
		iup_gui.CheckVersionInStore()													-- Notify if later Version
	end -- function btnUpdates:action

	local function doExecute(strExecutable, strParameter)							-- Invoke FH Shell Execute API	-- V3.1
		local function ReportError(strMessage)
			iup_gui.WarnDialogue(	"Shell Execute Error",
									"ERROR: "..strMessage.." :\n"..strExecutable.."\n"..strParameter.."\n\n",
									"OK"	)
		end -- local function ReportError
		return general.DoExecute(strExecutable, strParameter, ReportError)
	end -- local function doExecute

	local strHelp = "https://pluginstore.family-historian.co.uk/page/help/improve-website-or-cd-dvd-html"
	local arrHelp = { "-hyperlinks-text-tab"; "-media-popups-tab"; "-tree-diagrams-tab"; "-content-tables-tab"; "-index-of-names-tab"; "-create-gendex-tab"; "-apply-language-tab"; }	-- V3.2

	function btnGetHelp:action()														-- Action for Help & Advice button according to current tab	-- V3.1
		local strPage = arrHelp[IntTabPosn] or ""
		doExecute( strHelp..strPage )
		fhSleep(3000,500)
		dialogMain.BringFront="YES"
	end -- function btnGetHelp:action

	function btnDestroy:action()														-- Action for Close Plugin button
		return iup.CLOSE
	end -- function btnDestroy:action

	function tabCont:tabchangepos_cb(intNew,intOld)								-- Call back when Main tab position is changed  
		IntTabPosn = intNew + 1															-- 31 July 2013
		SaveSettings()																	-- Save sticky data settings
	end -- function tabCont:tabchangepos_cb

	iup_gui.ShowDialogue("Main",dialogMain,btnDestroy,"map")						-- Needed to honour setting tabCont.ValuePos below

	tabCont.ValuePos = math.max(0,IntTabPosn - 1)									-- Adjust tab selection, min value = "0"	-- 31 July 2013

	isFolderOK()																			-- Adjust buttons according to current folder, etc

	iup_gui.ShowDialogue("Main")														-- Display Main GUI Dialogue and optionally Version History Help

end -- function GUI_MainDialogue

-- Following hex coded files are created by the 'Improve Website or CD DVD HTML Encoder' companion plugin.

doc_icon =
{
Name="doc_icon";
File="improve_doc_icon.jpg";
Code="504B03041400000008004F53A45092A44528181F00007C1F000014000000696D70726F76655F646F635F69636F6E2E6A7067A5B25554D48F17F6FB1D72E8191A193A0444A41BA4BB1B443AA5862E41BA19BA1444BA4B5A5A4A3A8690106918424969787FFFB5CE59E7F2BD38CFBEDAEBB3D7B363EDA79F4FEB00444541590100814080D27F013CAD00B2FFCBFE7FE97F26FFB79AFFAB9E7A012818B0066CD1418C001A14840E053D0D00340000C2FC1F06FE5F610198601C5C6C0C3CF4FFB03E0400303030D031D0C1F8B83898FF61101A3A06261636140033F0104B6BE39058BA933286E2929133F3A614345030B13C17949157B0EB9B39E11390D3B5B2B6F1883A65E51792D531B0B5F7F40A4BFFBAF19F2D3508404343FFFF7A0200261606361A3AF87F23C943FF8320340C744C4C101E01E8FFE909C56400B0887948A4B5B14919792DC998ACDC4353F865647574F5D20A1A364E285805E4E4F5AD3D0B8BFAFA67669F9601FCFFFCD1A0E850E035F07B889C4D416D8A35B0925FD88A589C305B0DC8D1F05E914125A028BCE679DBF41BF4BC12386CFDD8580BCB734944C631052200BF101542B7C637CBEFA329DC556DC95E4E1D51E99376E74F2744FE110BF21DACB3FFB927A8FB59A5E5F86CC2090A53C6B81F2C1BE4A04150317B5BC0A5A9A81387A4A9B493F2F863AD8DADA2F55285A80CD5457D0C680BD2218137349DA703B775F576246B560E79221F319137822FD1721827D7432EC77CA2E21A9CC8991C526DE4657C3567A44605B11D630D2EF4B3DC06D8390AF003DE7FDC7990BA2CA1B00E4EB9FEE1363B25B2996D2D70D514C6A2BD63524051C8FD33BD8F853BA6DFA2666926EEEB28B9DD29FF6AF1BEB910532B21ACCA9ED146ED53CB8EDA001B0E912790DD3555F64E1466969429E2AF054CCBC4196C3D0197B158F91237E6C43D236E82CCFA4555D51EE3413CF529D6BB35A23C9B4DB3F5CF89CBEDD866765A7B7B9F6FF486ADAE14E4B0FAEF1FA47A7F4BB79FB5F3805A25C279DB016EEBA48AE7DDFF06DEA7DBAE5E6DA6AD255E3D014AD6968B45BF61FE9A299DAD1505C5C3458F4C88E859A2BA8BCDCF66FFA27D6A0B0657775430CA318F18649C1A868324D5F45E7DB0ED94E3B9DBA96A361446EEBA97FF33397C2B58326B6D7C601DDB576A1440EC7CF772B2DEEBA38AB6726279B872A69D70BDF1545183DEE74FB8466436F5E53200476A416292EDFD0DE68BABA192E2A570B5227BED96A6F68F25EDA92546E38D4A0C61F63EDF13F0097E464E2A4DB24FC2EA58E29A13C552945D07F42DF9503AB2541FEDF09E6579E3F2FA9ED3A3B923FEEDBF8FB62D503D55D61C7A60F50F912C7B34177AB3F5E37DC84E906606B39CC21350C20709D206CE09C3778572AE8DAA24A7BBEECF162FCE9E80DB5B429AA0C9B27387D7859A8FEE38494BA80C6F49D37862BA539B1F747A8AB0D4B66D31CE335B9ACAB4742C95187EC4E8DC3FB7A4BE5FECFCE35C246E241152E692360D2B751051BC0C2130AB357303616A089A3CAE5576AFA02382E423097CE75BD7277383643D6964108BD297DF4BB70D2D0432A79F21AE26F41394F4530C1814A661781661824CC844DDD97286ECB86934C6E43046B530C87A620B1310BEAD484AC436E66DCD90B823FE7BA7023C7EA7B287B27A9BB45BF5AA968E6BDF6A073EF85CFB590A33CE68C3D2500133FC782441067632D08BAA564CED8FAE6178465840B6966DA791ADEAED93A296B8AB2C69E336F031725D85052BB6586E88896B5C6B5D5BDEE21C9FC616D4A9F1AC3D6204A6FBF61BC2A8DDE178D076E6FA9A1CA1CBAFE6CA1811FFB2D42A314117BBEB651C0B31228CBCABD7AB25BCF4A492F55D6232471DE5788BF186AA9AD7BB775E8A39F163F1F2090902E78C6C9EC29F8B057718CBFB8AB4BE56567DC17269B3DCC14CD6A6201E2B732ED00C587CF9693AF0973EDA013D6711602C5584BB02B06A7F6D1FD602C1EE4BF49B264CB56DA374D40D9924466A87A9BC57F3C179BF5E07788CFC0A456A900B3F806B2FFA79F5864CABD2E36CDC7847CE998299335EE1F2B0C9C913A7FDC609B68C8A9DECA4B588A884CB3011C0C5E5A0EAFDDEB0068F9995C8B8998C941C18A997557535D8D602AE1FDA874113C3447F72545D5B901E6500CA480FA384264B534314D611EC4FC0D7B5E090119D0CD35CBBAC389EAC9258F95C13AE4BD65A5AB6A5383E9879975E8D717147C9B54C7F6F98A296CC262692642378E6BEB0A52748BB90A5755F6DD7A553159DEEF73059F3121310AAE7EFD3A2CC27A63BC0828A53B407C73732452ED30C48DCF7C1E4BFCB79CCEBE57EF1847CC734C6D4D5E60B18E0510384AB4CEE3B0955ABCFAB930839AAE9470CB2E785B2D248AA4F284B9BF66FCDC2329647CBAB4AB49C7320D85C84B6AB39BC54B250DBA8A1C33CCF941BEB3C8952CF23D19D2E93F45B5393E0824D646AB1B73C7981FEDB623E692B5DDE91B4D9CAAA8DCF0F46589965E3262D9163B01E16F03B4D9AA14653E691172ACE9C1321A1CC893264F4F8A9AA34FF7E272AC9789E66640FC4BFD62B9DA7F22AFE66457C5AE6806C5771735512B12B3BECB788220F47A79802EF6CD9A66A1D7D127EA1C5C6B1FFA398DE1DAFA8AB8C8AAF0EACB7E8355B3660CD89C248FD57A859FB4BC97395854D2D9FC8B4E697FC34A7CA5BE74E2D70C1288B3D813CF212CF5DBDA29A9EAA6CE26882715689FF2A655448ACADFCAF1DB8B8F80910981769635C36B4254BD9E4DA848BEAD30B4A8D56726D9CEA2F18B8C476059CF46E30CA06961E36C7F0BEA35E7A020CCBF320F1F607D6D53FE2E67E895749DB6C6430D46544C9B3EEA5E17BA7F352B0F652B87EE54A8D1DA6D0AA49852FC954CE30C0EFF7385CE6B588FF04B24C2F663573D92357B2ED90920B456F648D23707C75904702942C79EFBA94DE9AA91279FE1297268AA5E8684A2965666E829D963F94192AD5F30FB439FECCBC63F7C454E589DD565AD6CF99AB1CA23F0DBBBC688D43A78B7E6663DEDC48EF528B6748A6EC76E7A4AF5EBFA241C5BC7858B618479B75C81F6E1AE8CD8EA954CAF33BC2831FA99D698249C52FFA0287A2A2BEC049668DD2F2B4456BFF93EB017D1F12FEA2D421FB619A239986A9D453EF8124E3B9E9A49D609296A30AEE2C01F73CAA6B3905FC5E08B9895F2C42451F4816F71ADE7145F89B33BD194D5A7FC1E3F87B5C07BF80CDC0D0DBEF168158A13AB86E52625EEC2F211984B7349A36CBA1FB2E0494F1D5A80347390791AD24726F523DA58274337688473951A55C5C85965A8952249BF1FC0D764A3BA3A45B51D181789F7DB65BA0D0E2D1CF92C0557B1513CF388E5DBD1A4C5F8A67FE4C08CA05458593EA280B7D3C66CD09F1E1719D7DBEDF55A5F22586BB5DA294CE8BE44C7C2BB422665199CAA48BD01762EDF2B68709EBDB08C156F8019DB0A53BB6D64DFFBFADF02AAC22851E7FDE16A253D1C87A7FDF5BEB0188282D1EABC5C76757255A6139C16455EE5AF83000F322C948AE97B6B6158590BA02D77B2CC7D07FE8A0A65A71BE5B74D34D42C69FAF6D5352566CBFF6492A0D1CCCE73B7CC8492EB4CA7207CE2144758080A09EAD76C5C5A9E6E71E13D8A84FFA2E8EF69C74818EFE18332BF84DB909625AD9AD99A3CA43944C575D15B2CB06F90E33718FBB23B4A4CD2DBF2066B347C78D91DBF5CA675E9A9D20D5E6E58EE690C24C16D1630F951BA567A1A9A5A84FEC65D22BFDD4481247B0B9AEB5EB1FC6FAC1AEEA703A1861C82E2B5BC54CEA3C153CCEBBA2FC1C21EC7551DF1053A36AEAADB468C112DF6B4E4B8E563FE9BBEE5DA3339CE80A7E27CDE9BD64E59BBA253369062E95E0682E0605D8A2B0EB38A57FBA83D7B665BA54C3FF62D498D853106FC362FBD72B93CFAAC5A3A35AD4629AD1788D0F465BD875D948636974B3BF68A1532E1362D1DA24F13D678F1308F3E4A6C4C028FCA70D814008B0FE04AB3741A8A3A339BD56FB5908525147562F5EBC84DA92A81F9115121211FBB515A7ED7708BAAAC954568427BCA92E27FD8EDE6B894EB1C0063676A40137BB8A1B425D130714B5698F72878314B6B6BA6E3A563EFFFB6496D0B0A49AB2C4379C73306622FFEE107BA08F6BB49A6EF80F6EE82C5C6823A05AFFCF941D45EDFC3266ECE39FDE3C23151B00ED4441AF22664F422E8AD63A217B8E492F375D63C6510331EF78A042B5443C9E96CA9B6BB95A3E73EF9F6027818D4961FDAA53E559FB34D6619806B1340346E61F5CB430B693EA0031F9BC18433D29829B67EC53179BAEA778E6F0BDDA36A35F1E91B2763A974E8D0D06760EDA3F33F55C96E61A867A89357ADD06846B8CE4F4110331F1C9E55F85F1C27F02BDBEC01176F0CAA97550F454E89C46CD733854C320047177AAD6301663C4BF8BDE8A606F155553E6335439C4A72CDA17AD3EEC928B69F980AF45ECB7B42DF81E51BE647010034AD11608A984EA80D9E4C1BAAC1690B615220BE486374DF576D720BB8C29B5C765A9C365574F6B3F1941CE4FAF1BE1DDD2D691F4599D384DDDD5C16CDC02F44C160745AF578C29869EF741AC2850963E694C98155A63494281521886B6ADC647666D1D2F8318F6E1E3B465CF7704CF7435DECE327FB593C059AF7997C8E09912B1AF33D1B6D23E746F285A9DF6597987C7BC7CF2B6E47A138CE34632C811AA58A7AD2528F104389BDA44889A5838888BD8C238D18AAEC3B370C34E292661B0CD4EE5B34C3252D103D25E0EEAF94B8C126A52F7FE523F351AE1BBF6AEC3AB4E9CD2F861673DD3503CDEE9D23D26C5317A4CB6CA22E6F1AF3157D1224A85D1A2EF85EA512A624B5504239A763EF61C91BA5EA3F0F107D9B4EDB449E876472B3C20105742366D4E432A550FC2A3122ECB65533433802FAB480321960D235F42ABFA34CAA7BA0BDBD965CDDCB1CA6D873B342BE42647A99FEA5157DBECB07340586326DDAF180BC029B1E030FEF74760AC75AF46AF6CD221FD4D79BEA997E74F00FB39F6AB73AC4618B774E1594B018BC95723AF9363015CF82A7941342893FFB43EE4925C8FF78812A8A83E5B6B2F7DF7CDEEF399326B41F53CC23195C5B5DC60F52F28F237DC38CE62AB184D86E06A4BA57B2F905D835A25034F0279C18C1AAE1CAD637EC695B62D572553918BC5C8AEE6BEFBE54B403EEE2E2BB81FAA57C2D057FC75C706E1D39042223B5A4719FDF54A9978AA7B42ED1116A9111D5F2AF78E08F1CD3AB3A5859E9F1B471FA235200446596C412EDD123F20557CD967450399676F88492388D5CBCE3A89B5320BD44731D5739F8188649E0DF28101DC2ADC97A34559D8DF6A4D690CF12847CB3D09053812ECE8FB7F098F2944F647F13E74E945C61B1989A86777887CFDBE12CBED514FC55C2D2D728D4043EF73B544586F075B364F74CE1CDB9B35BDFDF8B771D2C6CFDA314292C0D24D0DD1C4682701C948A2713BC3C1FBA1B07DEAEAA99041185E74C6FA098CB77E6E90CEEAAD49526B8D599A718B7586D61BF9F6676565E2F5C259630D1B5BC01935D281E91AB2EAB62DFEDAE0BE2EAA7F4A2F415FAD38992643964D8AE1115D909024360E933B17E7E0E4E377D61D4B214EA8487E25DC6C2EC572E7FA0DB8F5F581CFE94F71451F96B2DB5C5BB074713C244A44C51BCB2502CC2ACD0D4AEAFF85D95B32A7420E6D0E27BDD7378E527316FC7DBF5E2D45499D2CC484BDF377E7332745B64DD0E615DD518E87AF962F132A9FD325AF0377D1B777195E8CE002C072769EA81FF87DA1CEE8750C2BA8EEFB42FB4FC21D6315167831D810A7EED0E60181E5053CB79A1F8DC26B5F44AE8948CA66F94650172C17365394CDB1FD0CF2AEF1C5949038CE03D66F16347B685FB219E34337D57A3DD23108623CC9DC7262A2E9C8CD37634CB1CF978D25EA9E80CE4E03C2B722071401D3EC7AF9EAB31F55F58A1C181B4898170E071933BBECF4C73D946A41C6205D6478EECD495DC55203D92F294EF25C554E1D2645337B0573EF3ABAF118C35D1DC23B888230DEB85EFFDF8878A833873B6813CED34ABE996B99D2AFC9DDD5E9DD751C6FFE22295E88FA0978AE5AD3134E1818DC93AD48BA27AC933BAC3EAE4E6086902B40711C7F1CD6B37374F901A11693776F9710217C71E533BD56F37D9186C7E5E1BAF41723CC99599E97F2D507A36276397EA4AA0735E13A933374D7EF1DFF333581A3C5868DE616778C99718A0132A9839331D0E770645A370E6DA160244B12B556AA43698CE8823EEFD069268A37959437E17EDD77C5E56A8B5DA2C8EDE5DB99C5337E4327ECBDB955F1FB876C23F2633AFF7E33085E64D7765C8CA9E263C0A71BC2DFDDFFBE0FFDD220CE2A334B6B485ABC619B2ADB7BE48969DE666566C280257B047AC33E185EAF9ED82E25E52FEBA66635A3F1E97C39E71FCADD438B94B13C666161418ADB75720991BDFF9A144B93D8172397A9BC69110DF74658832206D8FDD40463EADC76551834134915E2E6B60BAD0A473F322E90A9A4BEB735440F3B88FF3E590CE7E0C2D62217AE18F8025B77178286B8603CE42E1169B9BE2FD6D28D391710C94ABC6C82F9931E2DFE20FE569176D4C3FE70EBC4457D68277C9EFDF025F0E56E8DD5427BB5871BDF48B9A91271BFE12EB84AEED00C7CF805CA6C2B7552A4B556C69C38C9EA985B351920CFD6742BDE5754E340ABCC68DC34943353923CBA37E039A7692CF1DC99A0ADF2FAEF37BE11CF050D86864A1E636BC89E944EBBC54D06E7FB911112ADB8748A770741DA9871F24AF2B8D80C21959052009DF4E5C4C6E37E51E3B2560C2DCFAB9DD432A9CDEFA9E5B4ECA0F4FD6A2E462F43E2B81FF10BBA8DF6ACCAD690B0064C0D4C8C1212509BCC6C40C3B622CBD91F7F8F7CA6BEAF5DB21BB3091B2FE786F9389B22C5B2D00868DC71C3E40CA2EB48A2F3623F89697F8CE4481CAFC0678795F0C86114C46689F858F8BC1FCA6995BAD11FDB6E636F27939F13CCF89168E0FEAF0467FF20CF4F24CE26447D0D0E98E24B09660EB03527591DFED9BFCF99182168E27A808D0E30C6DA446F2632DDCDBE975C2740F0B452299705CADBE521B32F58533B2AD95D68D079F6E33423572498B6CE25FA98AC07B5C5AE748C391D83399E673763BC82AB37BFA0695D2B8EFAF858AD3D4831F11E5BE4719F15B14B9C541FAB525F99A633E7C9255356BC5116D78F859DB57786EC09FED4CBC893298FB92A4DCBF9F399A40796B40D7E195AD781E321C39E4D9D7D6A98B81761ECDA5697709924DD8544C09BDD45D3009BCFE3F7A93A15A3D8DAEC79DCA53AF8579C226FB73B8455746C624139F488557E8F417B4879A72469F8D00B8E9195D24AB6B0629E4FB55F59A10CE3DA8EB337AD4B86AFA677C976824D77714D32BBC6AE2EC81BCA57531F1C36BE59A6BD349EC3A2E5879233310F51494998A2F58CAD5E552ECFD2992C5C74F05FD418B49433D4987134F227634961CCE42675644A7D59F7BE6810B38F45A09ADDA94FC653E9897828BD549609F3476E2E7A9292B7322F5722643738C360FD7FBC54FAB78A029334DEA0824ED67665A16D4139CFE1A0B650196BA7E31D1739D9E4C057A17BBCE0C45E27F19367CE244CDCC02E5DFC13701CA1703F545B47CA8C3E2F87580FCA600D442C6922E100F58DF3D58B51CF93E5CB274049B1FEE7D5C171EB5CE8E73BF8E64E4D00F5B27DD9C61E411CF6CCFE260511574BFDD1F79D92A005A484F861352F3B127EDD7C45E3738B015FDECC077EFF9D97887EA3567DF3F7BAB3D7A51C38A095E9DDCC4B8C9AFF1644E88393939F7D767A38EE4DA8601145F375AE051D7074155BC7BFA792CCEBF039EFBD31331768C1B6CE93161A12A4A37814F33FD9DF28B5000649D4498F54B00819EF164941C421AB8344F10E8CCF308FBB37DA2E9F13AA5F7F8749811EA66903BC69DE37D06695C9E8A6FFB6C7B95865656F53B0B763A1262C816CB485B6D0789F0E5BC20FFA5C197EA2C7DDC6444F7D80DE0E5D7DBC9C49906025EF638EA96CB6E09B39F7E6B8DC9BB3A7DE6B1BF0DB7196940BB1B01EA87F3EB513267393B652E54C53CFEBB4AC7282D655E0897DCA6C98855ADDB8AD9610A877890CD598CDF2A973F97E1B384846D3D6F3FA3964EDDFCE181E76F3DCFE7C2D03276EA75488E6194F00FAE1212A6FB2775F485F987ADEE809585875F3C4C3C383A1064706ED76C95C0F9B74990B02DD55BC43821D0398C6AE66AF3F36B32B131839D1E7A7BB2AC125A0365C64EF538284DA0C65E2A11C61AE5B5DD3572CB5829BCDEB2DB606181DF267C268AF3974AB738F24AB3B200F2D4F00A7BAC8ADB53586C5BCEF59A7C13B75FBA059E702EE74263C4161C6CA901D3D182C5299875D9E5E8FCB952FBD909C7B23ACF8250392EABD46015EE4890D54B5B90AE342A937D2F52E598A4EB7D77F1BE7EFC6379E2D86BB015EC526B2479BB72BAD486CAAF3AD8476FCA655BF5C992B9A3535C3EED5F49D96CC1E49EBD061F9B1E7D5ACEE380B4FC058A974EB789DBAD05EF756188500E35B007A473019DE5DC0D42FF772762DA53C49C2674E604E113697E3FCEA2A2B6FC07B593E2AC6F311E9D2DDD076DE9F11F04F0A23CFBCEDFB431936F2C4FA39F687A373F354078DADA3FF36DC4CEF9768FD2378798CFA691DBA27377A1D732A1C81D9D3AA5670F9E218FAEF1AB84BB5B579E5CB8DF0BDBE98A4717BBC2A8BD6686370D765F9D2F610B19732277B824B29E617A0DEBAB34D8BD6BB5B3606D01D4906407BD8D128C5EB26E65BE664565B69152CEAEC9DF3F4FE51DE291084F63E724976F77C597FDF28BBCDE682D270D3FEBD294C0DFB13B8754EEDA35611F9679700BE833A570CF920E6BE377669E13EEBAFD9537D400427789074D89B06592293098607BCBB71DECE5359BC0AA096A41409FA5B20C37474F189B0F799E35EE8B0BE8A01DE5AC4D46ACD5567A453D0ABC766E4944537FE629DE4CA41C8BDD8DDFD7F57D85AA4AB43B7CD644A0844ECB57E5347F4BB20D602FD1FAD2D0753472D2ACDB0B9CDCE133A01284EB162273A36666D73DDA0CB80945C80CB73030F981068B617B31EE5F2F2EE8FF82DBEBD4985CAF7022936B9476D12C0375C93410A130A6988909EEFC5158DF9434E6DEA82386B4C86809637EACF7A36976FC1CE0C8BFDFE7CD20C0EB278CC68EE7FF98A87AF72F0A625E9CAC5F2BA08DDA3E4AF6FC50149D8357793D190FB1C6572A04B62C87DDF16B344C994B0D339BCEB181487F5EFFE21B7DDF4F5073C4B0BCDA6893D420B6ACC81E07579C5BC2780A84CE2263AF9BC9B9CD9534D5A245CC75CB988EE1FC3E313B072B14998FCCBC4C5E0D250EC0998087A02CC35B95683F0E1F5F50D13A66F4DF5591D33FF74287C7DF1C0AED1E4D93A9245E774D4DD61E5A091E2DF102F78A0C2ED036D2D83337B4548DF58A20A57BE69FD4291F2C4E0C2F43146FA0243D55821975EE1C6AD46BAC7343F1CCC6555F41BF7B368EE6F3F64B2BCB9EDD158A9ACC49B806FCFCBCB9656DA619B2A97E744C491CA512755EB02213F155D44C34BD3CC949DB453458F6D8A3DD0E9E41011D47CA00526867A65896C1BC41DBCDD474FB9F6851AC378CAC6B794378C60A2FE05DCAB5B68F84AFD7AD038F28D148123960964D13F87D6F7B1E9951B618793A585A780E14B3FC7A37AB1C46E9292B1BA95E87F4952B353934EEAFC7358F0A815338DDB2700D529EE7D33183AEF522A0DA71AA20428A641BBDF128F4F5D3F9AF7FF2468462D0BA36648D392326B7E73FADCAD3D01EA937B73EBB0C6EF7CF315AF0F052C57A8E93A863D57EEC44E7A779D6B3B99DEF9BF40AC8CEF47BF7D1D458D286A59F3A3F5165C0C2132C81D2D7272E32FA6F5B9F34D3AEACEA4F77C830A313B4FE72B6933F3773C356B7D08C2F09F702FD970A79A252BF9C36818E0514F54F820896ED177B0ECBD95E0E0ECD92DAFDAA339FCB047BF7D1CAA6B52CBAB51FEA1AC66C542AC74F8031295389C3B31FF6FEB9D1B07619F5BA4D2F587B75363997DCEDC229F1A413515D56575C60D2FEF8357E9B605CF19DDDFB29B8B2C9095E6B3FC653875AA5D9310358E9CF02B61089C3CC9130DEF5D7C02E28F69F302F2EA8A0F5C123CEE7FAE5096049EFC3DA77DB43FECC95977CE7AE77F304A54D1A847BB75F298D7116C4A5823B48B17F3857F56070D676CC0E213148A161B1E2325F62087B6492327B08318281C92BC3BAF3FDF73ED0EB602D59C8E90D7E9653E769EE3BC32D7FF1BAD10EE96DF9FD1B02569C1B6FC812B389C62BCAE3B3F1675DC275D7048346D3DED0D3EFDDD87FC0B5942FDA13217666ABB1459F79FE7BF3820A83480BB2711CF5B2676D61B524DAE3F010637A3D18EC8062E8B15C06C038807F6619518FBA0C0E899DB9AC85042A45F956FF319ECE6E37AA3D0D771E515F991C1DE0E7B928BFD4ADCCC7BD6756D26D24174520C400A0370A534A29B2CB7DA4DB4E2C5FD6A94686C649911E9209A11BACA2D82014D86837FFCFE8525B52CCFAA03E669C0F05A0F7FB11E1E9E9B6071B34D3785228A8C8C44986F5E6EBD30DBF708CC65E6E8C8302AFEC42DC7D296DF2B5A6C3560A942D6789160B45A1A4DE21B49DFEECC2A8D8CD07839AFD9A96C9DA2C198D8907B9583A8DD23C99E37F1E6897065E5B7ED8D89C9766564148252270E7843A1D0453C3C72C270E6D832C37D5FF3FC1D3BF38D95E924DD3BCD3A9CE5EF15ED3C1CC51B844A18DBB2B484EE3BFDE8B983863C2068655ADE1FBA4C533FBF6B0BEF35CBAA10D0E3ADEEE7F0B25F59E863537878580BBFBEF4933B13C576A8D31F618909A193532629F12828AC90EAA22E3642272D5F04255ECDE45E717F80B52FFFEF396A294D77B15A9E5D559264EFBFCECCF3227870F1DD8B8C4C8C0FD8470D8EC96E4C2EB050DF8BDDDF07CC57A574F969F4776AE76F06D3553C942D46610BFC6B26223BF0DAF9028EFE5516A478EB47EB6F56257C2020E8D1DD93F9EBE2F1919C9CEF596621B5D395025F8249AEB5CD13103B9459A14BD75E7565BE6E7D49171DBAA8BFD908FEF9CE796FEC6C6BD2976E8F7BA0CBBBDA0EDAA59A1BB509BAF7BB2A7B54E3E4747E565B2EF6CE7078C7A3F709581AF054F9FCDA43FFCF87F9CDB3A1D7FE3BBDE21E259A2957E076C4048F03326A3F80176F300B1CF7A30593B09E3EB50EDC80942337B60D2CA4C459E328B8F64358924546C6D4899F8989A7A932358C89FD383AD2F4181F577E3E97EAB7CA180BE8C509689162EAE90316CE0040844C7A5AFA3F504B010214001400000008004F53A45092A44528181F00007C1F0000140000000000000000002000000000000000696D70726F76655F646F635F69636F6E2E6A7067504B05060000000001000100420000004A1F00000000";
}

pdf_icon =
{
Name="pdf_icon";
File="improve_pdf_icon.jpg";
Code="504B03041400000008004F53A450D80C72B9FC170000A818000014000000696D70726F76655F7064665F69636F6E2E6A7067A5566554D4F1B6FD0F433B7408D23028DD31A4E40C2D0C29A0924A3B74B774770D20D2A1D20D22DD30744B484B482A2A3CEFBD6FDD75EFA7F7E1EDDFA7BDCE5E67FF3EEC73D6B95BB85B0748D5E0AA70000402012A7F1F70B70C28FE83FDBFF08F26FF97E6FFC45D1740860F58015660102B804506029381EE7A01260000616381FF7EF7DF00E11310E2E26181EF61E3FC1520490100070CC2C6C121B88747F4CF3A16181B07178F0CC027671124A090D7712614320FAEA1A46195F0F04CAA6FA0A27EC066949C5E30BD71FA504C5CC10233C5292C8AD0D5337CE5FAAE76FEFBDF9E0C7FDD70C1FF61F9D702170F9F0084850DFE5B869301582030161807844F7C0FF46F4B328005975C108F82525E079F8AD5DC3929193345CD262AAEA0ABE7E6119C5253770A1542EA5B58BABAA7167C9EBE5B02207F2DB0C8C064C063A0B36EA93133D6C878F049AF204A8E3376752545EC90B21420CFD47D6A410FF4D1A72AC1224807713B753EECB5939C55E41DDF011A882DE94F6B52BFEA2A2C2F9ADB42748B180F44D29CB2FBD5529A2A48F1D68F693823832620C1412ACCA0C4415004F80B53985AB4A4DFD312DADBC9752539E184D0898CCB0EB60949BBE38E62DF2C54D55BB114FEB0D4BE35AF3C2D3FB2939A954E105E8996E02EDACECFC3F79BA23823EA15F177073FAF7AAC5F0EC5CDD9FCA83844D877B2C26BB8B96BA4EAB0EA7327A5A1DF64DBCECF539F351E38265CBD486EF7D0510FD49B3BAA7C00CFD7E22B16CE6AFE9C90932C6C78788F43A2B974B35615C86257FB565EE240582C88D27E5FFD5385CE15B8031052B2AFF2E019CDD2E7133788AD2F89173ED57FB2AF60B6F5E7F7C284EF9B20C56E88976A1D6EDF66549A7E72FA4CED44E81A5308B3591C22D7C42A622D9823A77CCB2C7134F52C2081703832AF3E52B092237B2EBAA3016CEC11DB7C5155594E686395CB8173904F1347B8CFDF9753C592228FE479B699A8D40B035105523ACB8C22504D3D860865A1FE724AE4000730C8C6A70E2F7A2406821112D04AED0F6EF0F5FC02AFFBE444809D1BCE30BD7EBA8ABAD2E77306261FA8372865C9B89091D2BA234F788620AFB9DE694CD5266341C85DCEBD55725CC2C51DD7267C9B891FFBDE2769DB65F6755ECD4700F34CDD88E5945B4687F31B6194FFE373A69ECBEB53E3897784756A0A554565F7666DF818260B0BF552D10D28D789ECD93D66836D945EB2351BE3AAC033A5198E77D9C3458427A484FEE789EF563D02F6E6CB3E1E95366704181C687B78E434BA4FC704EA7E7499CB8CC7DF4F454600D76A63852B62F2A28C5A02095CF65C8A596B67269F20EF5E93BDE8771EAD6E503612621360593FBE9DA31C1AE353E3D4880D3783FB5822144364D28B1A9E7887A40FF03288CC24AA400CDD2B894C772415EA35FC4C8A150BF1AD8D629DE0638D6E1B7700019393F4BAE3F184B4EF7E4ED81D502BE51C7F7CEBF39880CD899451ECFA95CB8F694F00C06BFA6389F7B14B463232AEE0DBA87E66738A08A57F57119FAB57A333B16E95CDAB1199522648A1429BD4CB980FD1F738DAC874578ED56783A82CA2E4BC5E69FAFF827ABE813804D1E54B7F67F473CDC3629620DD42E3227012FA3216ACBC8A5AF52AFB7FC70351F399541089492A36E6D810C448718778DDBC95FBDC8D7A2E09F65269E1C752B58AA78CEA6F882707DF967B952441E15FDCDC216D21A0C1D930C4B0CA7250DFC66B0F5781ABA8FD98376FF15034052ED512DB83CE1306B87B55FB32EE4D44D5EE9C6EFB4B3E51CDD5A20A173305B669CF4B551FBBB8451F881C2133F40F7F0C9018D368E41892AC9DA023B0A4047BC949A48D44E5AC5E923D1995DB4B814172BC20ACAC2C8328D0E20066C220EFCCCF5657DFE0DC36BD32D57F38CC5295A1FC1A11F33954BB9F931204620DD2E68CB688D29207845EB20CE3E218123AE32CD51E27CEEA0FE952281971A7DDAB1E82118A2F97781E08E0169ED43359AEE6A1765F51191E336DDC98C8F427B7E2BF9939D37B2CD41EF640089A96FA01EE727F2D9FEF8DE9AC2861815C174B2F22DD17DBB7AB308FBEE6C398A8FD53572BF335B182CAB4584F80DD1124D909301EDF7787ED8B3E49E4EE0636DA1249B9BB5315199CB5B0F675B529396860C02E681D36F18AF85970A987F8D3FB595AFE704FBCC958B45DBBCA36EC71256DBF747BF8D2374C21BC694E545E2B67B8ECD4FFA1A17726F76CD49EAF8D339F737C6D4AF4F1091610EE859F6083FB6E562ABE0490EFF2933EFDF2956571643A69C2F36551616909E6CB524451E79E5E2A7B629B7E9F38BBFC327CACB45CCA577F8674444221ED654E2A322526CA634C39A74A47D36DCAA85F65871C5D2C60A9BD49FDC4AE764B8AFF081F9CD8CF4BE503A3FF0E3035CBA023E885D1A7339E9BF60CD6CFAEB6B890C31BBB2F213582D8E46DA1935BB24FF702644C33CC73AB51B3A1B5E3840D066BEF2F2EF5D2D560D6E1C6996933453A4155C5C1D8967852BB9235D74A714F94D5173A9AFB37078784DE2D4FD614223F453AF1B3D3F631DC973BF2200AF2CC40290059D02E94E5BA447CCD8CD86AAD6847D7428FF57B349B5DB7F188B7A799B5E9CC651915E741B2F5F4546208A449EE88546347321C1C8CDD8D6251B1B8EF656E10D6D966FB2DCA816F553A2CBD4544B4A35DC7715FED4AABB5DE9D426CA4C1B04AB5D280FC5C274E27DEAD2595BC74A68C9BCB0F846F0E1089C478071E1CBE30465E5E729231C7A9AB68099715187843DAE68606115CF79A848EF495289E314BB858C59B818175447CAB416D4974FAFC6BBD643079E621A47C78FB41910635CF7A98199E20D87537EE22A9ACD6A8B929BAF957ECA30F26892D5A75A7337AFAFE470DF65BB5BF7237B9C929CD3759BC6910592A847D8BAE7126D14461AE9CD34D023B39D69CD7B8E8A44076E3416868EA56CE34FC2DB58D5B110369D8EB998F3C9B500A5565A2B98A280D1C713D56CDCCE1B6C5C5E3C10E8E34C78998BC8A2A89C6D57C91182E825F1E42C8A8725D63971EC9709F722A073D5C6F0F126AB28707A384EB145D9910D1D5560609BAD72B0B9C0BDA34071CB38A14037AAE1738CD7125762D2FA3A156F4D09D22BBA061777566D712F643A55E96B859FA10A9AE4933B1EBCED4B5B1267E6B587393727DD3F32A6B63FD2A34F2ED81FBCC85EFD24BF9B6F4E90ABCB607A5F353021D7650105731F75BC1EAAF3F84BECF4CAA0A7559E5B4277FA814E60034B5A343B0DA07045FB926CB524D613D877C5A2D7F2F6CFA5BB4D1D7918970A1977A382B7642DEF2A34F454C8A3E02EB4D95358A59AE4AFB96DABDCE23B4E2DB4C07A67C6D81A6221D77AA9966B2C482FB7E948A5ED50C3EECA2D87FED087B5A59DBC02B998F8E8090EE3D9552085DDFB4872B54474CE9360872CA28B1C9F0639D65401ACF58D967474F0BE7D74A3E19E3643C4A1B441F1479CBE11C6F9E44BC12647F3E5751426CD60BF9AEE4157E8E27B5F80DE8366D920BAC022FEF4F49AAFB6AB20D6FC256D135B142154EF2DD1C5040D20CB4BF5DAE4842232FEF54D8A4704DD8BC57BE55A27A90EE7D604D56A6EFBD63B59B6C7030115B479FAC3A375798076E19AEF4DC20A017039192DE012F65B14003D7A8D98C567E1F250FC4C2A3978B7B4BB7C8CAB2E38EEEAAD51957BD3EA627B024A89F830F4E7C98D3958ED6FB144FBBC643620BDA2741583A83CE7DCF7939AD346ECBBC2E73E6ACBDDA148B48E82A82E3B559861DB0C2F850EC5D5BCCB4902DC9D56E40BAE7C7ED0982D713B3625537577F7148A1567D86B5880A0B4936C4C6F22758F663603FF94DE274A4F886B96E6DE77DD1DBF48EC347F1E8C86234FC68888E96B4B6002AD885C7065C8E35EE4A17C8A41DB031BCBB52386B7ADDCE4E20FC204FA2B7B82B0929A6B9FB5C176AC619CD4E5EA608D084E001A4A9B209B7E97168B1E6F2A4BA8B0675D854B32D657D9192BE3964E781315CA62645D96373C3A121C56561DCE456A2E6ACC533613638A88F449699580EA0D9E84934C39BA4178CDD459A4CDEBA36EDE357DBB1BA53508C4B2ACB6BEC30E7B2895064B11128E1A106385D68BB2281ADF0746A3EC196D9554E8E6223883EFFD0232E97DC568AE11EE74E31266ADCC208BBCE513FBC1EFA7B019BDC1A1922EFEB264535588D83A14E1B5B4C0EC8D0B534A8E381CAF97C111982198B25F8887883187C73611FEDBD0239DF94A525A3F769B199FE54713AC5001D677EC4A2C132A804388F7CFA04BAF0B0AF1AC30014EED683CE5D9412D76737EE17B644837E788B55663E2489F666A392C2249149654C6711D10A6E3EA3512AC89D7D138DE308BFC9ABF381BA0C06ED1E43CC596400BF6A7E2E9DF5D55AD9B312E17AE198B3E0EAD32486C621A9DDD7090FEA132C83E86A973E98D1FC495A11371F45B114750D0DF5C771E07F8545FA78254C827AFD44B2C18BBD7EE0BC44F4A8F4C4B03BAF54FD6DB71FE6C20FFC757A6251F8A50DF71FAD236EE3398A69D2D480F174BEA2B65A95E921419E0E55D6CFA2DD0FF295577210B199CC3F0DE287B731CB7C35725149E4A0F847DC016D220EEC2406E4921939328A6AEA5DD3B3D6BC1C5B653CF92B3EE1BC78E67442F02236B79D0286DCAFD0C4A26C951657C65791AC21C448A5645D8C4AF4659D4C2B8F2265EBCFCABE9AB0214BB57A8D7E2A2B3B3B7F381BF550AB15E79CBE25F656068E26652A2CA936022B413F3136275F5EB651BFBE83E8E1FA313BF353DDFED4431D616BDAA19169545DB20E6B7434974B2CDBBE3819AE4498309FC743140733B73B41AE9E1CF5B4B2502F89F7DA75CAABCAAA5042CF2E16B5AF6E6C8FF1A74DAC5BE7F5AE62FAD2A39763F0CB0C96AE0E0D3D69E3F64A0B1076612C8AB17A1138314EFEFBFD0DA77700C38FEF1B87A7DB85F03872ABBC5249B754E02D283878FAF5932FBBC5C40185BE78481D0CC9F7102392543ED912C938D4EE8178B53B3BC3DF59A6E10DFAA9B0756059787CFFD727C73BC0287027FBF96AC025BDE3EDF81DD0FBCC4721658CE445BD9BCDA36CC64F367B33C9B3BC87E9892B115DFED9CF585A48827E89888862CBEA90F4ED0B9F173A742ECFDE6BF067E288D8BCC8FA89697CE17810B664D1A6F4ABF3B148CC35DF7BFE852F2726FA3708E75BA287719C4A801C8206B22B5D133C6523800F0445D0D345086EAFE699D6F54ABB8501294142EEBC0400B90AE0A40A037C927DEC747D1EE8542C1F5DDA73C1EEDBF475E94C521D29BB3EFC6A9A85E6916976848F09A3BD85AA39B26D59112E646575428B72B5F1345C2D29CAA2547CD5FBB20D54D685CBD17F06F463EE5D1C3E9852FB3A55076873DBB6AAB5B8B5CF708DC66A7E9D81F354F002059152E1CFA92C1341C2A4085FC58687030C7467976CA1FE139F4C02DA8DD1A5CBE8EED45CF13A86871F4D64B8B200C20D6C27E8BBB75DEB8E335F59BE28C838A0A4D895B2DE7F2A2F974D5ECDB7798FAECC0E7990BEFCA0BBA792CAA252326E8987ED84012BC502E458D45EB1BB0ABD403AE69452B6A5444793D5E9EB4884A9A654D4181B654FE364E5A4AF8F1C473F12835B01BC8F3B6F2B5BCDE74BB4EE97CFD8F86E3B3E6232F5D550B34E094D96FFDC4418B94924A9A8D0D5702AB49D174D78CE2E520057321B4B0ED5FEC012EF450C1B3C233B069D30CAD19FF7A8BE6F3335B21F70E2568D093432519BA2AE0C41BD9C4A1C3783A6A256E5C8B0389230F27AE8262380D2E1A865C6691B4CA5A765418367B4FCCBD2797399EA5B1A8E518D8D0BAD428BBBE6286B54A4CEE7844E0F33BAB7D2D808003CA1EAAA88AC582CCD746144128A81F98484631D3B17BFBC9EFBD3D79B4E3B45CBDABE942731CB48DE30F333C9243524B463080F069004DDD8E3FD474417FE37A2C19C9152A51CA90BF4895DCC663BE04452083EBED9E7512945E493FF90896E241ADC018ED866D73DCC970C8F4F7E1E96DC014D6206DF72E2B254CC1C46F54213E5DD984377F025B0EDA728F36C7CFE1416CA4B4F5EFE42C08BE2CB5D4DEBC3BFCA82BF4DEDFF73EB151494B1FCD73AABDCFBA9F4F87ED1C4785CEDAFD77A7CFD5E9EA7D3544B8F56BFFF2C7AD1E26E1BD07F07F82C7D9C924A38B51579CBAC034960A10F879D8D0B8EBA00D2ED6E47575C8BEFC7A73D8F33DFB1A74ACBB4BC713AE86CD7479652C7EEABEBAAA7D652F1BC3B997893CD706EF16728C1540B404C249B44DBF04017DB041C66353F35917864B43B23F51918D58A1A6F278C6DE48DB8E876DDC64E75421557B685536D8DC29A34755A9D80DA628D6F916E9EA325B979F3E2D8398F169E12A12D0C4B731CF9EBE96CCAC78AD1983D11735A07C769A8DC8CFF9B506A76401E770C5195AFA42774983A92B63F472B331355C61BC231B765EC6D5BFEF3E571E4E7ACC6E3C22FF4DDF003C9373B96D35AAFA9BE5F34492EFE7814C6667B227A2EFA413D84A9C1C43BCDCFDF00B0E88ECE1DB71A7E5B6EB30E791A2F4ABC20BE6CED3BEFBFE344A4FAF8C5FC8C8CE87D92D7BC54EF1B3163E55C16894D22292EC24161CF0BCBC01F3511B8522DE223723D9DF6C711156F43061C56CBE27343979F6736122F74542FF32E72111B88ECE7E6EA188B65B63628F0D1A18997E4EFA77C28DC5C7AACB1AD89FC30C72CD9A0DAAE050E32DB648611ADAE622078AF6469B7167BA560F8A7E3712EEA9E15275FCBA20AE39F32E4B7AB4CB7CB39871932A7690B00741088937031515B9D148E686BF2A2E9E5BC1A97B1D726E5AC7E4AB40431655B07D421B14E2AE478BCEA69561494226BBAEE99C4F59C286DB4A74DAB7B1AA6F4008B63D6EE5D82B01AE396AE2395807350BA53C8D87DEA82D325E6BD28AC971404B3464A72B2438E158EC5C87DBB0F736EB18E248EF412822B2D4D19AD71C6CD714EC1117EDF87D505AC6EC5ACC24142165116C92CD1525990133B7C11FB62587847C1F101839D1C345490E50C057F4A48D129992C5DAF6CB890814738FDF455B42FC560596D8F42B53AFCA0197CC36EA5FB99CE6DA4B76CC0017DECE1BF53B13497016F2CB7341D90321794FEB9C96F61465E5C68A5561044C43C97A772C04E6C58CA898EC1EE2D56D1A3270D910ABA6A65B91530019D850DCC0CE854D14B4BB509496C6D0D207531440345E45DF82EBF369C6F16330363EF8073277A97DF8A4E0E24FEB23F56C02DFD81E8CB8BB98EBA2976124BB4892A9D30BB4C6437BA0B3C421B05EF319F46890DCD1771FE6BE242BC0B0EAFE2E3548E74F95AFE7567144F91903281262767487F2A816E9FFC6BF0BE04943DEB854580881557243B4F52D918D8B931E7D2B1A656E877EF8F955B7D366083D7C9780E63455D65DB5BC975F2E6F2852EB837C7FA0718957C026542D3F832256918B19C6B2C3E9D4C6E97CC8D35EC26DDF6630CD45995F58751B80E6D849C6490BF2C716B5D8215DDD887983AAE4CBB631191DA26D2F966B5ECB2028B382A0E08D5AA160136789A398157CA44A271F60EA8A1AC7BA0F0654660AF5FE1A3EC55B2ABB0A6A2D6B0F6C94128D427F80F13DBC3D99E68FF8BEC48D6DA712342BB902132247DC9B809BBBC8E967E8A501AD5135E161919D84F5B4E556F049754C0D1611A8EE1BD6654F978C5304F41AC65663F3DB02E00803EF60EFA048A7C41F0AFEE63122F6E6D3FB5A9DE8FDE86DA5246E9436D04228758F40140AC9F00EC907B2D713693F22E00B7C9507F65EFD5C6B0F1CDF984A1219532EB13ED65AB2166D428C1F540D98EC46167063C3622F04FC98DF497BF3D3792361674492AC7767FBF325DC32A3DF349586C9AC54C2CB2C77C6C334033460CE86E8DFC9E8880C7F149078ADC011B9804B95BDB3BA0A7609D2BF051FE95E365203A41A7E04AD5FCF6577DE078E91DB07F9A90A15ACEB117F6A3EB2AF0A7DCA7BFE1A919890C7E03CEC377A6F738C5DA0DB253F361C1B7740B3102388959290E33E5F01D523BB75786CE0028201824640690311E4B4A6E0CAB457E4CDFB179A94F81D59714A42D3DD445B3DF991DBFC23F679C37021BE6709A5B2CF1D55849527C0A6ECBF3BAD233E4F1D935FFA8A2F0AF44619F2BFE38C2949355B8CCF3D25FD84C4ECE31E82367566D490FB22A990BB91E04E837372646A6DBE4CC1127C17EB3F2AC9A09BD02DD629414EB34D73D2817BE292979A0EABBD97A0393050B06BAC8811B303CCECE32F6AC4609FAEE6B1AF249BF73AECF8FA84DC21A4D1E3B3976CB248C2A4F0B941B50BD9CF2EDBD92FC8DE615DF4BF5FC76F19748FD9BD8CC4935DF01D4F9A2017176F6F63E5EAD55668E9BEC174C5B9813CA851389EB6663A73B60E71F4AE26E5F06FCAFCBE24B8A245E536421B2F4C8BF775C8427D3E6F40E3FA6CA6B692D8FAF92318FF5C5C7A2EB2807E79F624B8F277F7C5AB4F92F8229581DF851FFB3F2C29E51ACEEAC357F79E4F2227C41D132188CFF6DD9E6076E60D677BFAEC0BD1B5FD1248C09D461E27505AEBE3599156F1F3FB2B7CC9DADA4C03673470832030368F660CAACB9C266CD434A3082BADC0D4CA171BB0D696224BED5674210ADD47A70EEEFCB244383D19A064D4536C4232191294AA9F80AA3D0497746C5692D1DFE73EBCB3BE0ABA488CDFC8786F9BBC5FF01504B010214001400000008004F53A450D80C72B9FC170000A8180000140000000000000000002000000000000000696D70726F76655F7064665F69636F6E2E6A7067504B05060000000001000100420000002E1800000000";
}

txt_icon =
{
Name="txt_icon";
File="improve_txt_icon.jpg";
Code="504B03041400000008004F53A450040E3C50C1150000CB16000014000000696D70726F76655F7478745F69636F6E2E6A7067A5567550DCDD92FD6141828461D0E03E04D7E012DC3D7870080E83070B041B5C8313DC9D0CC1DD2D836BB00049700FBEF976DFEE7E6FEB556DD5EEB9FFDCBE7DBBFBD4AD537DFB71E1711D78A628AB200B20212101F27F16F0B80CBCFACBFA7FE1AF24FFDB9DFF158F5D003E06600F18A320D102C8F84828F8488F7D00250020A32001287FF8FE039858003AC61314B4A7C8A87FFCEACF00E009123232323A01E613F4BFFC48C828A8687FB61898F820023011290D97C71C162119AFC04B6D1DDDD77AC929A98DF026C40C3189A4869957D2EC3C83BEA7F7C7347ED7F721F50DC77F3212FF3B1BE0EF404241FEE3E0C4FF931B15050DE32F42FF710EE0237399B9D2486A24E4D5D577A3807834DDDE238ECD37A4827B4E1E9700EC3F1791F151F00171C005E7D791626BE3CD97C9D14FDB0BB0D2269506507145918E4B1948AD42E155310A4228C803DB220859061FE0C463C376F7FEBA60F429AA38CD99BED9F627D898CF3DC6D1227FBB2239A2C106A35403540AFB91CDA7A95ECC0556DE16C43627C917790428A0242F5236DF7FC07AAB7B37822C12FEF1D547CE633C0EC464F727A7D522FFAD922DFE02F676A10E3EA2017FBEA7E410C679226D196EDAE451625421BBECA9AE3A2D63B1C63EA54F52E52BE576626C5774B370848B5222F9BA04E80E3725D0AEA01532D0A38B9F5EC8C8C52819652A43207DF4A62BBB408AA5360DA47C482C08A29905A5114062915D91908322DCE67956B742AF48CD1E50C4FB6D4106CB72F5A143389BC94E6C6AFA25A565640ABD0A348B346E0E5A692392F9ABE984207036FDAC523D4C83B994F615D3486EDE7296BA538A7D83BCF75394F2C27D87336F256D97D1B96DDD18F7CCC2055599E0F1B6E32837F76E81E89BF3F73DB4967DDB285044B9971F35FAF8B3B79B4FD7715FBA541771AD792512AF5885FFC67E0408CB56BF875E3D37C3BBFDCB78048C4DF76F335879FD2BF7EBB7885FF71FB20A66121CE257EDC8EC7014E0F72E4A73278706B4DA3A34BAD3FB1EB06A5F429A0E1C113AC2B2BB0E09F424C3FCDC0773B557B73C1452ED3624595E3CD22656EF5D481822E938B38DEB4E2E3C66498B0E2713F3779FD5D06B5154E574EA5930FFA4FB12E63470FAC0EF5136C9DC375C371F0AF17FC9156BB99D2614408763D24C58D1DAE6D2B1C52ADE6573D37CFB42AB75F8E92177EFDD9340D89CF5A4DB48BFE30081276F96956CCC287F4B2CC5A070589E6791BC9761AF0AF8450583E7E552C41439B88CED0B234E9ECE8B5D6484EF9DE54AB4A156019B659CC77313E386C62DB6F84D917D0346728355DF9501AF2ABD34080C12D9D55C265854AFC95D9A8843BB34C21F56C9C6DD9AF1838E5D6E3F0B6E5D7FB49A4E77D1B4163E38DF00047E774F2BE2256D78046C0CA1AD8338FF20377378D2731B5DFB0820E56E36369065C468B56E89FFAEF13A8DF28028FB5FA850286EA56BD41A98559CAA1F6DC89A6D90358A440848C71251C6F14E83B5B50740C0F90479904F408E14C0B446F22DC392E5837176695001F52AC30835C5A1623C180F9DF318C31B555A04650DC76FCC218A2555B33B38B19C91B15908C51DD7FC3CA46E298ECEEDD90EF9EDFD23305D93BF333AC6D8A59D47F9FB7A61B2438C4A8969E3BE051D1A15D465CFEA5D4D139133F5923C01E3C39688C42B68E42550EF144EBF3946A5911E5AB3E0547F2A1D9B52E7E9F20A2EC28AFDE1A6EB1C5165D20ED17526AA87903E898A60CF97704BE112FA3012E9A2BE4AA3AEC2E02CECA9A1111506F36EE1C75EA3D88571BA54DAEFCF7ACF7111452BAF23EA0EA65C2C3319334AF6703193F110C8CD1FDBFD6E4D4F0EA6F79716ABA8729A22E1F775C3F36667392AB19F8696163A1283EC2E6987E9DF127155E3DB5DB84FA2E13067C848F67ED0E232A22048D346A25156C707D23B255A09E2661F6894AE99BA96A11C66DB1B8BDF3C7F8208B2835F1F652A59131F2947A10F0F15C22CF87B545A64349614282C523A8DDC3EE6A30304D01A7FBC819DFBDF2E5E03CE26F2B6DFAFF47EFBFBD15107D87DA7A2FF2C5CE927D6815F2BCEE78697685051C8C8BA42E1B5EB5AB995E191E9B2F0C4A026121B257643B79282D12391F4ABB8CB2A6E7F7F04CB7D72C8FAFEA2F7B5073DC9B80877EC7666BB4B3E2CB7336323A6AF7E90898F4FB8F9A05D51459FCEA0578F91D26288D0AA786391924F1601AA7F9360EAFB00E10A8F52B630AAAE6050375DAC1F625EE454921E8E23747C3F2C6A4339EAFA4CA92DE0672B63049AC99D86FE68917C3026529C36048B85250FE389204C027FC70200221C8C1A922AD2EC89BF9DAE362662CDD66DEB9A6C08C9A7F679317AA7E9DA89796293953758CEBB5B82043413A3F2B5721394F304CF90198EE542D5F01B29B65F0F1F06A279AA3AAB80EBBB2A7415DCAB7F0A3007A3A6DA7530EA9461A4F71923E9D18EA1FDBEFEEEC21B8412BF65F99BE7A8DA82B0C74C90AD673D9CA4A389B5ED9C429B868A3ACB7DFA13C47894867D99B4C09494B82C8197AA4D575F0E2FB330C906C6BE4A3FCDBE7978B49FBBB43F7E46FB62245BF5F061F8BE7A6C8D9BB6AD0CF16CE05CFC79E6D546F71A69BB0F4DD98F000181A3DE900E1EDFD357D2BBAD9DF581F60D026311352C1E2EA662ECC2FA2B4E86251BD101A34C45CEAD8209F6B885179A6262F4E5B2AF86260489E3F06B45744051CC8368CA8A8B26893DE9A80036230494E7FC08845D6A2DAC96D879FA4579E52DC5776C2B94DF69F9DA25FD6241D87EE19F724A0DE0514748B3D8280F33865BA44349EE6DF45001E6F429B8E12F14C5130BF102864F493BF1ED2F7A8FAE1E019F9B14AA02C7FA3575B2D751A4F7846C922F6BBEB2529FDCDA4B8E1052FD4DE779790313B1D50AAB01FD3F18EC2A0AAB0F63548DCA1234385EDB0C6BFF90419201E1BE25A8F08552A826F8A242E2A670E33819AEDFCD4FC2F12857C5C6AB32E8EC076BDD5B708DEAAC37463550F85D5A2D758D9B61A62F49D1B46992E525B651828ACD234880EE35800275B353E27398EB4D383D33972BF6C21CA22E6004BABD4CB58EEDA5D334FB738C426291361F3BB9CD22AF5E928727F570A279E26976FD1E7D7EF84F926D1DD5F8883439C990E00E82BEEB2DE83556495AA9CE4AA4614CD79C3001863D0FFB84F99C6BB5D48046D536BEBCAA6A54639A92021F6DD6ED50BB515B3355DB7096A6BFA970C62380527BB36CF415F54CBCA30D3BF7C1902DD08E245CC7BDD2846359A54F0F8FE94011F1A1AE91522CECF3D848F722898E3EFB92E84A32F8DE408A6B2FACCB2341E56B636A4044A584F228ED4AE8EB620C4606CBAC873056E8FBFA24BFF5DAA6DEBDAD9FE7A79ADB9A1A040C2ABC0679426E15584F3E52A7841B51DB4E45756D8F0304A7B32D87A221C7CA54DCD6E7F89CD9CF3C1789A91306E331A7F7225C947B00809183865272EDC82E6AD502DB11026FDBA2482BB12AFF5D75C80D870F113113C5528D4BCDCC46BA28A493C055E8ACC95B7C67E3CB2BDC9FC1E27564B03413F27B44916891EECB7C72E3DC27C5F427DF84CD1C288DDDBD2BF6B9158737CC6F7C4EEEA417C1ED205A8E7A04D4D8A9BEDEAB0DE3A1D484C237FF74E6D1F0737119A68451C5D77B646255FF083B9DF3BD13B8FB5CC81F67BCBE3EE8B2B03DB76893D53A8129924E46E7417F7A16CCFC63B6397824A8C05222BEE44757745E10651A16B23A38BC1AF59CF37FD4B28F89DC0A00ABBFABECABCFF459B1B66BB566AC2742D17A41546E95CAFE44672485F4BC3029E0FE1252DDE8A47B5C92E81951C53986BB819A0449111C092EF2FFE257B37B266F92B27175FB08B4DD2BC621E08BCEA5382FFAA31F60A9C16A1952E735789D6BF7BBBFB40362E0A3FE126F4D586DCEB53FFF25BCDA90C1832A7466ED00938BB38390C126B5067BEB48B1B0817F32835DDF7C32E87D79FF2A9130E877E14D9717DF03BAD905BCF913E64EA0BF37A9F81DDCE061860B376E1E9C072CE0EE3447A00B497BA373013B748ED50000BDA7155DC7C3880D624A7FE07C72ECE6821184095FB6470E8AF3EBBD56EB7B3584721E0160C471FCE98857411EAF153AF8540E299B62D9493858671BD0A23EB31A9AE62D6C3A5FBAA4583DE1E493AB1BCDE381ECF645D938D009E3A4CF1A3698F0FD69E9717AE572CC98B2DF67F15A5842551F8126E57985F695658B72AB8AE706EBFB574DA10E9E9F4914484A70BE33ADE06F85C52847DB43B387BB7B9341A078895FF1826918414C3B82DDC41BC535B7EFFB3BA4ED022CB2F003C8EC1E812FE486DF654B9D767671738F440AEE5493B6534BA0D070B5AB1C8D072685D3519951D8767685E3CD96DFC33F85348621E0793D15944E54E4469EB72D0C1CD7C184DFA79297221B2890C708708DE68AF5159876C94575C5141E010BA92F893E0887130286857B9FBE61FA3C6CD1D6CC2CA1C0B6D3B81321B55483D94CDA85871157D51F753A8F00D1D144D9C79A94DDB3BDF99319A85DB9B3439470D9C4A0B024416D83B827F288E85633CF059B0E65081D525059E484665EC7C721EDE99F8389FF4791D4FD0B9144DC9638EAC15D2ECE52F7171B65E4D8B35BF4F90F3205A483F347BF185BE0D36B2870A7FD62C91B911ED2E08A4643A2C0C56EDFDB5D468F73CAB59E1B77B83B8B7BB35D49F7B1CE41EB3241D3E73999F18F93A9B8A1FA688B9C25FB44CE98372274E6D9DDCB7CFA3F89F54AC123E9DC2404482FC3FE5B87604E818FF506134747D39E109CDB610D5B2857ADB24AC4D6EEA6F55B0C0EAC555AD247201BB6566041E472B1241D509AC38C2DC7409BCD532A554A0ACAED6E20B3182EDC4F66A7752ED3056BE8D46BA570CFDB4FFD841BC9BF68628D5655B4DD7FA6A7A5AC234DF86B06F44C55CB5D6924FE5CF47A776D17E497E4FAF0A6ECC7BBB3C9CE09FA6BC6ADBB4E1DF774B9E74BA5BC0EEF648B9476963ECFE916A857EB1656F37891F0282FE576F7F1C67899A7704FABE9F2464F1D2427F85A9908A91B7D51D776AB6B2E757A23C6048356138EE8397E332D9C37B45C92094E6DDB7B47E124E3FDA1646BCED40735AD8C7356C08E1F2D54F3931733A1243358871A8FD3D8F9D55A8EFF832BD3B000D5F64D4E78A7C8EDDDA65AA293F8E8B98C85170E277A6F06DD77B2D717E85A5FDE06899123A8A8A73A4B85AAFDF1027CAEAEFB72E957023FFEF2A5BC3B3B3A8B1453F8F208702008635678BBA8706DE3E2DFBE99A178CB96779CD3DBEAB5A22A30E651B530F05DA1C570B18415522A3D9B51C1EBC33233C65296624D4C2A60B9AF4D9FE227AA44D8A738D3CFF92CD84A21F2FE6F45F634F65B43648D972977B8C2DCEAADF63D2C42F3DAB3DC2F89708546A20B3647668BD741743A6F1A65F2D018B6358D25B5D791618AE04F4CA0B0880A3CDED09F2654819DB79333A5F7CF1D536F82A6DAF4267F94D9D25F1772281EFF35347F0B2892FBB1ECD034F3246573205046495DF5C5F9530C9180A5AF6EA130AFCE6CDB5BFB154FCCB16B9206B992E99D7DC654369F604DB71D4C5F877D3A09DB612F074DBD77FC329D86D3EEF18C717A253C9840D845FBEA6AFCBBA77C773D11A7BDFA4CB16B77E2FA27A38177BC751998FD01EFEDB1B72E70E5B592AFBC3C25F759E7CFB0A84671540F0F874443331ECC5E5D9B155D2DEB8A0C409769BEE5E8346C657CFEF3B586151ED7FDE087E48A63379A7B45092F945D56EBD7669851D02E5A476BD199B7D9E65781753CF0B58B05A5537794173C280F628F07DE0ED4649AC3F9630A56BD2069654F596FC608777E5F8C7B521F71DD59169659937375282D6494E03F173005D369CA2C3728518025F3CAAB97AFE8F4575717D16B1BDE8C3107B2F209B7B6525F12D95F87E26D877D6C41F42E9987AB258E121BE5529186194C5D9EBCB3718D2E1749CF35207075569C42526071D39227A39FB5FC9A02B57A58F1634989B23E0E4D8432473EFB512E22986EBCBA017A0D6DC524C9DA935921FC5625922A9C289381734C5E9E7098A85FB1C72388C20BFF04ABC9FFC6B258F0E5FBD82AFA89AC8E8C0CB2E8A5DF7136FED1E1E17EC8827ECD0E583C952CFB3FDF39FCB45782A8A17738263657A12ECC91D52F65CFEE23C5ACECAB9A9815F6D914CFE0BA289B2AF951816652A9614270AA2EE9965E09443E2D28138EF0A74DFB2618403E154DB7CDEEE0D608DDB7226D22B7FA32CBEA6CEF60CA4AF734B912EF857ACAE78AFA2B6D1AD2A1067FF2FBB1E4A8A83C8B44F3F7D891A9DE1B443674719F13C557FF4645ABB5B51ECFCCBA334DFD41CF166FDADB596245771053CE49B599799AC5C6FE10AD6452BBF497813DB7D62CD6305BC21CEFF6748B9C7B0534218A3A2924A5AE90E63B768584157D0613B4DC8BC7B1381C064F0F73EB66DA07090AD058198DAB66DB79EF44CE2DC2FBA78775C066646556A1DD20F4188A1106C606625CFADB9755607B50126D3A42A7E0E580EBD32E4344DAA28A051E8D9FAC624ADA011C33C970AF32EF3969C8D28C8339F5B86E835BB171C0F04BCC6921DBE4B2A034303E6E6CC63BAB6F9F786B88786EB87DAFC797EE756BA97EC30D1F0165B18EE84CB60BA422EFBA5C44E20C01EC1EB9078F0ADE489E87D7C196F9664870277FB4D1FA830F6DF79E97427E8D91F69826A66FCFF9948A1694DBD494F9C21FE96572BEF943CA98009EE354F200C7F77B284022818D950648A07F14BB31BAC60BEF42B9E5BD9B20E37737894A26D0FB24D205662601026DC41F8E1FEAE60B0EEC3A0F4402FB936E1BE1240706756E92360352C19E98F46F339DD6E6448B0C5CC7A548BDCB653666A0A3310E08BE6BE665E1088FF77D0A2504A921BE6F41325F904C04999834889448650CF11908D507EF039CDAA406962E4F5BE0F373FA641519F421C3109A24BB9B8883B8EC28C46A9F3CBF2B763B27625DF6437969D757E6FC440659512E191A3AB867C39BCB1CF1CDE1FBA5ECCAF9FB92B8DFF5819E397790DB654B8B1DBE2E0B56AB57F048368B137490EDE25311181EABD2E5B6FE87E2C57CCBE9C8F44A259D1738496FF56A38345223DEE9AA32D62FD2D219597EA301530F3D39AB8D91DE2578C732C7B7E9A80EFB1056ADB868A1AFABE428DB625E84BB7DF75C6933F8F38018A3CE0A4FA4FCEF56ACADF9E17E3ECF68B7BDE4284F888E72D88BAC7FC52CDA63436E796E6870CC134BF3D636F1248771538D72893489C12A93AFC6A2B952092BD8F5F3B77261B2857EAE9C2238735766010A3B24F94D83807CB5F4082C58D4AD5D5C98DCACAF876FDF62CEB92482EBE54F72D95958F4BA915455B421A90C19C2729D42B20A93C7D0BA7C947582DB5CF40687D8D82A33854F477B073A3167FF303D78A72FDEAAF557376B3CF9337FA81D2262DB20B74BD17ECBA110B5CAC4536282134835839E2CFED88AAF7BEB87A287620CEEF704AFABA15C7BD2C37AF91385A4B173927D06033128F1ABA8248CB305EE5392995234C37AF0D5CE5B2B92B4B9BE1113CDE8947CDF9D5057F72DD87851EC24C36EFFFB3D820292A454662525B7A47724E33DF88A9DB44EB718C40A74092BC2FA35B76A5427960F07AAFF455056E8B8E4C831A9459662AB9E4C4C7F0B9E9677E01C7AB8E9B8F89C52514D3BAB9FAF6CAC8A56078B495C7F51EA2B0CDC83C60CC6D2ED3F3EDB61DC1D02D055C7E13796A1C40473F68900A6A0697739132448C2270119ECF33E085584120F2FB073C827C848FEF53A42BD441102B3C1F58B96FDCEFC5B5CEF49FB0686F6082A8D4411B31B72B22080BE0F7CB5DB7D867BC05D1E0CD0C298A004221F8248391E17FF0D504B010214001400000008004F53A450040E3C50C1150000CB160000140000000000000000002000000000000000696D70726F76655F7478745F69636F6E2E6A7067504B0506000000000100010042000000F31500000000";
}

etc_icon =
{
Name="etc_icon";
File="improve_etc_icon.jpg";
Code="504B03041400000008004F53A450A0784804D11A0000421B000014000000696D70726F76655F6574635F69636F6E2E6A7067A59767341BE0FBF76394285AA1F68EBDB716A52B668386446C356B2B696DD5D64A116AAFA2A2F68CDAB35562D31A11BB76D158ADADFCFDCEFF9CE73CE779F37BF17CAF57F7F95EF7E7BEEEFB9C7B5D122F7F0218F4B474B500646464009DAB005CCE001EFDA7F5FFA5FF40FE5BCE7FD5E51700080870003850908101E420320A10D96517800700202727A7B82AF7FF8806789D8A9A8CE21A25ED952FCF0020A3BC0A0A0A72AAABB42B9B828C9CF21A15801A0862A461E2BF0596637EC022200FF37E2368FBD028C1F8AA0FF715EDFF615203A968C82828C9AF5DD9A2A0FF0C494E4649FEBFC0AB0A28C82801D7A8A8414046A65BFC5740B000CCFB721A4077E593832840807B800E3C86E38B9F02EA79455E67D511C57399C5E5F476157A4722711029EEBB2E20D08526CB8F57C57BCFF6D61DEC999A193B825EC7DD4E9873891D2C327C67C5029DAAB1874401655294E125E4181EAE07725D8A25220AE97CDAC0F4FD5B0528AAAFB81D5442054233A1A9BDE0CEDFC14893B93D434FCF13B19C37033C8E15ECFA66F5C413E08E47A27B4D141E6CAAC59EC06C08E287F5B98AD30AD927F4154F3C530854D772CF0A4DD3EBADF742E39CB0CBE95C60A957B62DD838DF76F57A6D51085FD89350DB955DBFF1093C1F9EC3FF5081F23CDDB8857C6650C45D8EE85FB9B0ACE45F41275C778DBC1C28E38F1E772B3050FBA0CBB49E52E1AA932DBB2FD4BBC1D003566A934B6031E1DCA46D13DFB0C8ED3D0D417F4A3BC72F5A4818FC31D7BC5EF6C3AEB72FD3F504F749747E679D5AB48D91E94B85DB3C7A629F6663B161B278D9537A6FFFA6F73AEB4E8288E02C92BB50BE5422A7D875CA68367A27F9D1F07B8841D21CDCD5EDB98F577A167BD7A0BF1F67459284B4FBFD3FF68D520C3D2E192BD6376177AA37DF2FBA8B1F729E0836D42B5E2FCCAE8A4DE2166BEFCC238D1D0CCDCF64EC47D4AAD9BFFEF9D715A16324BF5A3BE42312012A1EED0D7649272922D30A82160B1CA3AAD7CFF4735EB0B69A2944BEBCA9BEEE7296A92E77A35E0FE2DBC282E1A04BC8BD06B4B73373A56C7DC78CB8731F0BE975129607AFCFAD13DA3C2F01F9BD479D1636EE5C1B072EEAA97D768FB6D9AB3F19761BCE2B50E21A3757BEF2F3BD657F87FFBB009D57C1C3A5E0FFBE7F4ACE45394DACCD0F76DCBB0468F297C675FB39474787792DDE5BC0F2F07ACE033049B8F3FE0577CD1F97800C9634B9FA0BD51EC4C668EDCD52C14DF345B24B009D3737429D8DD0301BE784559298F6327DE5954C52753CD681F1AE1C777E713192B3B804E4812E9E991C8CFA46B99DEEEC104E67782DADF60BD2D838AB1A1A9DDCCC662CC0BEE21BC729BDA6EB72B786B89A902F8DE68503DAECEAA5ECE977F1FDBCD68FB3ADFF764F2B6E258DD9E8E2E4E2EF99C41134BEBEBA7B0C6CB1CED40BAD622066E48E1B68AB8E20FFA955D733E7BA85965288B235E0C64626785F74416A5CCC9A17794732C40CDFC46B3881EF0E34BCE9974679CFFDF63D23A9B3F21D9E323567E4FC3E4AE66A6F6723EE3386C4298BEE2D0DB83B9320A266F1465F5C40D667ABBBDA6DE1DE9780143589BE68ED590F6B2BC661CB07B16977DAE211191ED7990A8B36939FF9F43A874C2A4A56476EBCD41699E10848812991FB4F0DCDA5AD4C3054C896D5C53FBD4DC7423CC8D76439CC3126C63B973FAD2DD8630759FD1E88D59575F8D8FFAB26E6A7567C51E09DA807995631BEBED6BB67621DF09190142DBFE8A6836AE9C27CD60B61A4057305E557D300D18229F4CD44271D99CD042F306EA2E84DBDEA5C64CE41B6E76836E65567BE9089CB0C4CB8931DB43EED76E75DBC9CEC43D80AD4894E30D2CEA96FB37E7A68ADB970C630B072C022E0E1699A4B23AFD5A6CC0FA99844F63D39F0A335E00DE00DCA483B2E797171DFE8E8DC390D63AD3456269522EFAC559F4652EFA6CE0CAAB7D5556D9ABFAC8BCE0F55B68C19793C88F87540EB9428FB4EF6E0878E294A40F1F3061A4B1FE1A1C0A5A90D5661AD856B6A5EFC2A9996B904282D8D7C1F7EE1FCA35061395755E8858A71912E9DE8F3A5DE3469F7443A909D56AC4826A484916E0D008813BE8B17437F05BAA37AD770CC2F620B88C4D3582FE8870EBED3DE73ADA9963F849F8D3344FFC5B9F376DA0F2A0152E546CA6A3146A07B1D144D71D760CBA368409A5B4282606E89D3DA8A82F75CCB52E5DCC0A9FB9F44D6F0C2866491A66EEC8C79678FB0BE239F1DE4CEB2693E812B02E2356EF4B0EF7E37321F6981F2AA96F473DBFDE0E6B5A7131BF5201AF1B6B0D599A058E0CCBCAD38E5690766093E11549CDA57352C49E3EB81682530419D4C818BB10C3D71A09E783628A5F34F573A503EA6F82B80C24E290C984EA8B5B767C36343CABD16D56ADDD8866AFC8906EC696B498FC4A177B5593BFA3E758753EBA649C2113E1EBC8CB2EC53B4609DA5F77C6C2D627487B23A9F50C656EF606DA50F2375E39E8AD9F3D628DF02D2BDEA90370681FE9DEC651BFA6C15D4733DB9FE70A85CE5CF4F135C927C2ECFB32E3AE8C885E3ED7F467E8241494398E904AE65493AD1F1333FB2E5D0C6AFC26270B6067EEDA2571A047DF03F1E7C29AE0AE98F15AF72F3543A17DBCFBE516E4C32E8366993F8A897AC08476842D4B45E838B1E4F03C34D2E012BE8E2E22C83510DDD960C136D945D675FC7D07E102D67123DB09DD4AEABA19912368B6E7F649408899279BC1FE75AEABBB2D9C3C5F277F1CBE6AEEB402B3647AE602096F1F029B85482F8D7E763FF8E90B65ADD79F0B9F811A172E1DEB6DB1CB4F2DE64B05661E5C410559411A6EEECE38028025D5CE501E7BF59293F66499F45AFCCA54D647EFB333C5A894408B956B13D63995F7B3241EA36E74A4BDC2E773EC85C46DC566E9873E76E5196C4FEE8345978A9F7CB3C4D1061EAD44703EA1F6C6FEFD2FF9364610F2A1EF7296F3412C0822F3496E8D917AC64BEA52DDBC8F4FC2E2E39130FC6161D69FEFB11EA61952FF5D364D066ACF7F5A06F5BB83F175E7D2F32BB096489B19E5BFEB96AF061E13C69111664057F96C2A9378459A15A27BDB65EEFC2D7DCD29B4065AE5FA4799073CF92B599B605F4C4D8F1955679062A55A252FA9B4754D55A640E116D8549415505861E55C56AB74C271FA599AF1A66BC9C17B12205F0F7BA250880FF5053D09EB34A5C021C9E6D4A8C115A4A4A5C035839A716DAF2A7ACA51C335B741F493F691175CC5C29539AB07437094CB013BED1284795B78FFF163AF99664F06B35E84116DCE9382461CB436218CF3B1D94CE7ED025A12BDFEE8C5F0BDAFBE47FBB3EC1EA7702359F4E04AD92F705D3BE67C32BDFD3CC4123D3CF738CE2EF9D4315C2DBA7251236A327058817E92B704DB7F40EDA137368684EF3BF3383B17FD873F15042F6643EE1A52B57E761B876601765874779004FC9BE5CD3F01E6283A712D98480218276DA9EE654F85F342BCDBA254B3D3619F5A51B3375A6A399297C69E5C12BD9131F00774431434F4469A979427020C67B5869E37AA92AC9C5A120EE228C5DC3815127F83A12E1D3C6C94B69986E698528488ABC0BC9D64C86E8B23FFEB732C2B5757B9D23025CE3B5DBBE65ABE5514F7C567D5D8705EE878BEDF3B6D3C3A163945C1C06E3B9A16F6D029B1F2A8F0AF03C171D686C54EA7FEC71D825F33C7BE4DD29D58507DD57BBB3ACF8F487D116E4645D185AD93036D7B0D3C711143D4FEF549C3AFB8605BD8EADAC2E0BF803AB224E8A3897A27746463CCFD2D6CF2BD346448CFC386FE7BA351544E1DFA71C101067A11DCC29DF6C24C3289B15C0D14B8FA9F74F5EE6196269F48E8252613816ECBB046078FE09EEAE3F87D2BA89F9D7C6CA300F0B41268972AC562EB9835DDE1BE95B5F6AA0BA0F0440E67B3A71B0744FC3283992CFD5695C98DE3515A16BB57E40BE12F76B2070B080385DEA91F28DC350845C71BFDE74FFD1B7C0B6E5232C7172E5D525C0E00FCC41A7945076B1315570B231FBB765A6626E96B1652EA3B1E512D0182098719304B52936EF7CA17DB54775E585994BF63101D1151B95102DEA42D949585714D9DBB617B0C690AA55D0C668A9C8CEC5BD9D75AB6645BCCC8799F03B78C7C6C5A1F59E38338AD43E89EF4C051B2412F3CEC69075D64A747670118950A4A114DF852FB5437CE3A0937BFB0387B19EEED2446C74E486EF54ED9DB92D4C8A6697825F21604C8727880D0DE4F29F4A27A76783838323471A4EA1EB3B471F20C09E3768B6F84D3058E0E242602F7DDB2AC5FE585A2CD1A9C9EA43A0BBFDAD4F9F7B652A1CD5BA18C437B11CEE7D378E7FC73F05183AD3C3C5069618F2A30FE5C66FAF186C3F5EC0ECCEFE9B4B27875CA80E4856FCEC94C78D4A6C7040A2E209D94B10CE010B6D8E76DAF9AEBD00C0BEEF6A60938557999F7A56132BEAB8A396D00FA565A975DDF6D5A4D27E8FA22BAD1D3459AAEEBF0D66E2C43B520F77CFB5FA9E0033C3B4204564BF190E22C2F51A47B214BF51FAAA949336DB1D822660D8B809125EFE6F1B7DBBA175DA62A0953BC55895751AF5F2E4498FB0D056E5F60699A0543A1263FD06C5E24818FA04CE6F7EC2622E22B087D40FF58BE434E1E83E804D7B138373CD262DB5386BF33F1239E6E1F7CB539713D5867434654D13EE2A2D4A96E6C3A1AA43311A7D4AE4B131623F4BC3C09D8F5B35D9DBAD4563D68CC4F3216417F38B39C578BFDDE8768333D88BF310B6FACC5DDB847453C893D4AED5CCD520CBE8EE4423B6EC8E4F9A7B48158E9D7094AADF4E016DF7B6EC7A6BE6885841662A54D28092C023681F9B2B102861E4BEBA07937C7BB3A7CB79D5C1B769C8AD3565DBA2602FCD6EE3D086AAB238EAD6C34459A043108C79FBC2A6BF142B323319AFBB10EA7334D9EFDA71B4E34AF82DB56AE5F9BEF778ED7539BD8502256FBFB55FB5A4D56B51468E2F12E163475DEC944D634B3C7C2C7E63328F6737B7D5FD3C7A5F53A4FA3C2F458AC7BEBB04802AAB761C3DBC651DC22B38390C3BF820B8A77914424A7DB1493A1808C46B1104523D0F0E96B1D931DFF2AB3F65D924450634A0BEBF2258C54C1BBF8ED0DCC5D83D3D4B314E31DEAD23D8BD53CF3E9A1250A84AD67777BC040073FFE6D2E423CE240F5D77A0FF469272F738C9DF05085984D4FFF1ACAF9F4A44AFF5322E1951257F95089954A9A292D388BD3E295E2A7AC13CB4E79369A868195DB3EC14DAEBD1525CAB6449B1CFEA2DFF04C24E8597F5DD30E0F7CFE358F7AF658008BF2825547BD8851A60E492EE8DA997F1C63196F6ED89A7A150814D1508D28211A349F67068A8865E1F852689E934706B192AF084330A7C413E6760FF3B38354461B7EDA0BE7F039B440AC20D1213133FE288C5D1BB052FF56D73D6B04A1D269D2FD05A8545C3E9DFB4301CF6F412F1086B2B33EF5C7BBBA563F81172DB779F7186BBC77D39612903639F825B92B648EC12603BE04653BB98193F813F07D234F09600A2CDABDC31BC889083E978CFA1BDA98C556F42EC0CCCFE4653A55732BC362C8DD8D7BCE77309D04D15C25037A2B325181EEF9736A79EAAC56D05DC73F29EF325928DC37D0F254B47185946AC60841F96F850AA1A1F823ECDBE70B59C684246EFA371A4E88CF78DFC554E2BFE3A4EEA6B52E6A4423D765D0B8BE202BBEF6CC742D50C04F24C79C1429C3BFB5BB62E75D4730E42400ABDB87B8304FF436A8734D54713815A02099BE3369B623487317DAC439B1548831B3CBB22EA2BCA8F2D129DDE6338B279267BDEC6A26CBFC5AE9F14BD6DEB8F4211E3F7F9415C3B4267AD3CE811B5B7C1CE2CE73B9C4573723D5545E95FF0ECA6B729F5E30EB4CB8227DA24D0D1DB1D2F4F7C64AC0A8694D39CBD31953D4FC78DBE5022B5805387408F7D2D1C477431E16071F29B797471AE680CA1C67A873437223FF7BB7155F9B64DF7D59446AD984192F59ED825E86C076809EA58265001C7DE7AF35A9E2658172FB4B19CDF7809205F3EAD340B109F46A96FD7D77F9D6105D62A01897C929AF49650A8689E3E43838FB0D5D3D5D7544A85ACAA3DF15C369DBE86DC6FC86B2A051CC2C1B67AB2987854A4F2ED86AAFA6E9B36AE0EEE90B2DD9205F394059A5DF495B2C160119D6C91CED051E71FA5978054143D87D20F611DFE1EC5264D2E7FDC5B174607E6DEAFAF014CC3760903BBB16CF8239550074D2BB914F40A5EC82D6D5F2DC4439C826F8FACA989DE2D977B474B10FD983BCAEE981E663DAA1284B011F28A0F79C53016FAF782D82C75385DD13B6F59C3CEF5AF6F6168A05FB4DF379FCB5CC526AFC72E9F6626F3AB79777DECBB059D8F708841AD4B6C5F80DAB573BF7593899DAC749CEC0DCDE5BECF27B3DB9977EA4E222C966E73E5DA3D54BFC69E64DFD31349212E9028640D3152A9D016281CC516ADAA5E0254FB4F903D9B0650F74AB3BAFAE15BBAF5A050E36ECF412105EFF3E60AAE40356DB9DCA1E7EAABC19C2CB4351C858EE1DE458D4E951F4341B72BFF287D6C99A61FA729695876886B2C0C8139FCFDA7372FE536C3D222C9D93E9ED9F7F530E2992C10A6931E56CBD9CDB8D416612F2C8DF129AE40B82598AF2034DD12603058201C6E9DC2CC7AB685918B4C7B565C05DA3AD1AF57DCB3104C0910E6743D2BE54C9FF8569D0A62B3EE1E32A25F8DEB307403E591DAF731358BDF52F7DAECAA1D6DD764EDD13582B79EC691B5F6A8587F45F3332156C578B465DDD98893EA3B41447C1DB3E55A1DB35189E5B703EFF98AAEA11DEF1C0D07C319FD92E25C707BE55ACD2DF9D59362DBE48F8FB73825EE082B49AA512B091210082ABAF4DD64311730F4ED1D6F476BEC62EB4C8A0F62665139A5B4252FC5D273BBAF173199D48E10D4BBA6ACFB1BC7F093E37B242DC04C126D9ABC2237777E56E56FC3E8A1D1594C1AEE4878E45C160F073A0E7D2C844FA6EB6A5413104682EC1612D785149376079B1F826D03FDF6DC14A62CE7FB0EDFF71307A44082A0768D3FCC23762988628CC1D86AF68B1CD171947907F09F5674D8B3D0CFE6B924909241A5DA69A18F826B4DB1C3ECDD4C938D4579A19B07E9AC091F5BC011CCC6D8A14FCD1836C63E415E1713FAB042EDD41FE5DEE560D62D4D170C7AE10332088766A752BB63142549A6AA54E59515F934CFFC12C01BE1DAC48C08D23A3F7F119DED56551BB89CB6ABDED891DCC4C938AF3CD1BD5D52175715F8439ED387534ADFB77496D3B6DCAC1892D7BE0A8A65FDBC53786611E66B12BBB53B6E3E71935B5F4FEABB8D51C2331B2862F78760A78DA3749104B4006A817E9DC2F7D38C21E8E802C3A1C4EAD01799B7A0725BD57AE1B7E61C95465452F6F6EC470F6B1092B6C8CCB06640B5B2FA54187C27E7D7A6832E400FFF57E54F59661567AC88AB2571380A61A34CE87730DF9CFE95F88C68AA2FFAF5069DE883E00C9F95F44F0C615C0010D0FE562C5BE464C2B69B79A58E0A5ED2B327C33225A55FA251810217C40DF695C0318F75C1A84507D587490AF55D0AE39EDC014F8C19E281D907BF7BF2711B0ABC382653BC7D8F543E0BDEDD77CA03EA783DF766B7DBCF990F523ED19E9A4295D57D22EF0291778C65840DEFA46C563E50C720E0AECE8483AB4F7804C44702B95B5CDC917C0CDF7865BC7A6F7238F548F1382D650D09FF90B49CB16CDF1A33931E0FA108A97E3047E74E0111160B8E7BFE36403F6EB2E7B56E84B3C8A3A092B5647A0FAB8847E0C9EBE89251ACB8CC2AB39AE185747AB77D8F01D46EE608A14C669B767DF6DC4C974263462D9247695EDD85B202F3F4B97632DBA823FCD3C413FE2C6E7A6B8483C483EEE407FC0E1DC7049A7E6BBAA5AC750FDE17BB926F4D46F6C9DFC44ADF6B32FD6E4D5923697BAC1596DE89BEDF3C2D1149F866C1DF94EABD28AE253E4588FF9BF448D8273EE0CEAA3D27FD5A0EC112FEED34F57ED98224556B4323CFFD559FBA1A0F816F14DA3692D1F162D480D86A91C6B7178CAFBFD4EDD80B1B6C8D1AF41D7678E3A23B1559CCA469D3EC0FF6B956EDC85F0EDFB3B762E85F81EF39C7F379217DA3C70DCE8E27D72F01DE487B6D8F678FBDE90E08754CAB0433A41E63A47EF03175B0D9FB4FF4AF4CFD47291F30C71CD193602DAB3165FF7ECE94D49DE1CC37B242B3EDD9C3916FAC9F8E9B46438EF37D24AC37263C6166C863BFFDA91F4B4C1DE15A2D15C2D221A7CF3B677F27F6A09EAB1E121C953D032ADE015D6567522AEDCDC4BB7864D89D4433635FE042EE86810374F89B211351BFA4A7C60EBA8786781E66814AE6FE29FFDB8C4E6B4E297DBECB9BDA78AC4C709D7F62541564F28586992D43075165CC2DD04A8A56E58E67C3214FDAD558C738B6864F7B89C6ED08E8A2B21E8D4E6D24811DE887D3B7B8419327C1A6DAEB37E95AA50556EA5F2F6B055540103E652D105781200402BE5539B65E712F5E0BBA793A7D77FA40123B16F7C0E2DA88B77AA1960BCF97468FA040372E254316EC5F74BB86E87CB3C59EFA9D8623B10EC76BB1225F8A8323A92CF2D0DFCCEE7B0723C255D8B4F379BA50D6B2C59987553109C6032D62CFEDDFBD0C4675BE3D63D18E7CAEC52EDCFBFE6334030E7B61EB70EBD3034A0F04A9FFC0CD62F9CFA4CEBBDF3BF33F477D255DFE9E7BB03C4696566F0D1367A104C7160F38BFAD7513B4EEE568C9B3C639720FDB9E0840B96E0E2F748EA937B0D4AF651E69F7D1F3F64BB7ADA4F23C7B92748AE0BDDFB8D47240A7852D29E23EB9638C1EC1F80F7BB32634CB46F08C6333DD589254F4A8A2A232D62C958569259A4B1406904FDF2FD07BBFF71AF485EF7D919C0E81D2039930F46C18ABF10B1563E77BA8F7043697EB8B6A1236554A5726C41F97124232FF95871D4C6CEAE158E74CAA3F52F6F9866906659822E9CDCA0D399745849A329E51FD491AD5C705B1D0DC33B3C099762D5F02D856F95DD2FD3BF004E7EFA9801FB19CE8A4AE3EE74B006AC3BB3CD0E2DA3DC467A91CDBCFCFD635B0015D1585D3A8A9A57393EE0A2AEEE9399CDC9EC37ACD52AB4FD2CDAE571F5F51D270BC114098DB78D07166A17F478B376FF959852DB2D5CFDABD60D362D5670C63C3BB2EC38D271EB86502AB971A0AB14DDB0106766D3A01F29FEED638EACAADF48A19D825E06F862D0579478FD99A6A5EB356887D0271572D75450FC6DC10850D07CDC67A7949BEA3448D489BCD9B190B31D438728D5E7FD82131C6E6FC231F6A9BAF757579B66EB94E6F459F207CBFDB4E118894092248A22625514180BD3482B23851CB749F1C62902340BF1C84305F2B152FBC7ACAF2B1AC9F3A79F3AA26091FDEA0B5AD6FF8F67080B99E3097CB74E880CD18520C74A48F5460C3206C58B5F3198BD64F5B10FAAD91A5B337D4CDA79F3C6D7DB3B0915257202A402D3A4B355B877DFABD82E35D0AC3725D8E6BD9121F7D9B8C0E3ADBF947A1BC846D10A9BD29A267233568A0512E62E796813AA2D6F5C4D38D4BB9AEDFFB3EE2E18B0312C9CD6A1A7C34ED5B2962DB485D97F547935A6CDE0ABF50D1834AB9AE7737CB27D50A744B5F5BAE98DF88BC97DEE0F41210E3C2DD8B464FDEAEE050C42BCEE52F7BE27FC31D6E8C932A15D0DC10E2BE54DE7D870F91CE08F3F5EBBEBAB6077E6394EB3289E18732379DB3E94120A5D6BFCEFFD7BAE55E4EFD0F504B010214001400000008004F53A450A0784804D11A0000421B0000140000000000000000002000000000000000696D70726F76655F6574635F69636F6E2E6A7067504B0506000000000100010042000000031B00000000";
}

Str_lytebox_js = "504B0304140000000800DD90955349E13AB0964E0000E67C010022000000496D70726F76652057656273697465206F72204344204456442048544D4C2E746D70ED7DDB76DB4892E0B3FA1CFF435A53D5244B142952962D4B96352EDBB5F28E6F5D76774D1F59A5054950844D126C00D4A58BFAA2FD8479D873F687F6173622F29E4880206D5755F774CDB44C24222322232323226F81FFF75FFFA7DDFEEEABFFD7BEF387767BE3E54D16F6E26B76B9D7DAC3022A644FE6D9284E0ED8AB20F9344FD90F2D7612DCE02BC67E0A7B699485076C9465B383767BCC11B4FAF184B1BA281CC4E3708245F27583E365EC598075FF67309D07C90DEBDE6FB2EE4EA7CB5989FAE13485B74F9330C8A2CB903D8D2793789AB227599644BD7916C553B6DBDA61025291EB8B0A7D0EDF8A938BF698C3A4EDDE4D1BEAB489836532F9FCFF4080C3F9B44FAC0AD9D67B2FA6511605E3E8EF61930527C07383FD72E70F1BC80E7B194C2FE6C10536763A8C2EE649407539AA0DF8FF0D90FAF3E9C5384A476C9BF50554C88671C26EE279C2C6120314F4E769164F80100B52360DC34138683181E4759C852C1B0519FC09417A97C1781EA6EC2A1A8F592F6469184E59EF86CDD33081D2113C4DE2791A4D2F587C19260CE49FA170115B368AD2D638E88563760464AED89BDEC7B09FD51B87F6DBD35A7F1CA761ED6C63E388D59EE26F567F9EF61BB51CE02C092F6B678C00DFC2EF0868B3FA8779B7F37007C0B101BA781C0E331624497CD570F14CC3EB4CE2790DBF058E2EE0605C0C54984417A32214B37170A35881DFAC9ECE827ED80B121FDFC11C1BC808187F974327D13493D0F43B07124DA02F05C80BFCCDBEEDB078C8BEED8214B001F078C4823E8D10026EC23B28CAE22C18F39234CF25C7C9B9B470B21CD2998B732651728D24BD7DAA14519A104365893468D9248421BF8154EBD9CD2C048AC21EBCA777778F809DF974100EA36938A835D81FFFC8DA3FD77BE3A0FF69719184378B241CE08F70BAE881B22E2EE2F1601127A0F061E39B76D4CAC234AB9B281BECD82671C06A88089A098D248ED2034604581DE806F371D6683204693220463FC36993213978007A4DC609AA762531B23CF83E4E0661826DCB927928C408C3334BE2318D1FA096E0989CC634E2D865145E4109A848CA040E804FA638DCEAC3600CAA73C4D2BF81610C65B956CD680ACF0EC90D3FC92C66E928BE229A548DF5A81E683B52E51AD21E659331D50DA799A212CFB375A850351222AB438333DE139CAA165B98825D7A3703A384B8F75DC48828C5B7A898C43B293F55432354EF1CA5E3F80A7A9C05D08ACECED130485101B49026C1F51B187B5176433AD7DD11344630D8B12FF83B90F200FC1A16805D83F1DD6488D77C3F46EBA0011401DEA477D00E22D0E90A02D1104D310B061FC1FE12F3B3603040AEA3293D3E7DF7AE4920646DD130A300E7B3414036394AC11A2751D01B876C7B9BC528E1AB28050D1C87C1A58008C6F1346CB5B4010E66B3703AF8D33BE28514E85072833DD7E4C43814C8F16F60EDB3F361124F8EC410411E90BB3FBD6BB13FA782CC55948D583FE0DE16BC4894B109D8C03ED936B204580D953A01BC46070FA3EB70F03686E8006A92FA90E2A6AFE25E340EEB3834B9961F08C53259158383384EC249007283FF0F1821653381B5A94543ACB0B40FBA3346414B37168CB13307C6C0810A51B6B14C9FC540850E09B6513CDBF10C2982D8131C4684043841F191CC8651025D0DA43F71462F6070CD00200D33612939FDF3F3513408B97F4C2B32117368F024F3FE08FBE08771908E9A10365D064D1666FD560307DF7C3CC01603FE01386BF2D8869D89A1DB53830DE8D1F8471A8315B9E09EC420C447F0003B6D1C241768044601A7D9033F9A52FF4D07601406D10488A3F80C0606F19329E024A916B1F0E4E54B18DD028A85C3219743D40A5B723082120DB047DA60759AA69100FD05432D1585A464369FB0866F38127BC028F26F5EBFFC2BB7688256BD079EE282DB4D321A53D0B58664AC4996C835F5B1C9A1C101046CFD9062A0A7109C7E62058396C75F018FF0FADC50F4A942CC65BD4938364540C6FB1DFB1C47816BD0CFCF937008D219A1D377CC04A1E7C34800B16088560F633644261CBB810C2D3E852D0E2AE45C79048A7104774D31E4E11D0E0303D534B87C0F21018DCB5DA10618836C6294D7C6204DB630A586C733C6A33E9038FE4054FA3FA8DC2DA80CA3136845175CA5202CCBD5DCC52096B373DE615BEA7717062036A80746A761D79281F97B8AA4B3AB9849732174893B0161B6A447CBA26C1CB6FBA04D28666C89C99988AF8D381D43FC09594F3680D0B71FA64D4157616360B107518A212B7A4E2E28C48C100676A13BD014981FB4806FA8875579BF49B3816A17C050C7DE1F4713B4782D41F1AFE0BCFA30DAF50C83BCC590B47EBA6DB389F3883ED8860B4484C8BB538C75A6032E8EFA01578B06D146DDA9739FD07014249E6D943B12AE83CC55416AAAA13C282D900B05FD864A4AD8090271D170181D1B1A0C91BC8B59220614475E96788F190CA122BBFC80BFB53A8BABBDC990370A3F79FFEA253EE2F0676DF62A1C4401FB0B77056F846EBA11FAF9F95534C846D4A0DAFECEB762822148317A89BA2BAC8AF02CA66B0B515A45F5F9DB5204CA7F130A745135C7243BD6553B7C8A88C8D7CB20CBA6428194E1C311F9E2264C17D3D860601CC7339CE3A19D778C5A110BE1A4170E30789F908C810F4402CFF5F46A082EE1326AC2A8BDF4B820E000696D5474C0A0115805C7B643D441FA1C5FAE86143D6C1FE42730CBB640243315E107CB828B22657B3706634EDA5AAC5A29C2BC404B77198C81B77B3B3B321E27D3201620587D02911B0474681E52B208D1141774D2B03D08F90F3178603AD70BB32B5CA7D824ECE9A6E39B5E2B83E7F74FC252D21A401B7D85B412ED0C570506F304352B95AD2BF65EF896DCB02375971032CE973D96F943C4F82CCC8268EC06472E4E1EF20C382CABF783198F78C8AF34CA29A0FAD12A4539095AD468D34F6946715D858722555A435A391DB89A2EE9D81AC851CA65041E83A0E020E81551280E32D084FE0867E88AE6A7309C51986B1026CEDF4CB18329CAF2EB0141110DD5D73A7EDE34E307A44CD19731A550545083782CE76D653915AC5C4E05CD8A1A69FE86E0288FA6F3789E821C111E7043B47A311224A5B4D4B4A968443FBF44CBF914FA032DA16F3CF742F0F5E1BB2C4828FAABD5446BD57227B213D0240C01CDA9488A95ACB908F67105545A178A307162A46AABF1047357183C3AE00D7907345C2EA516AFC024A216B2CB0B1AD53C8B66AC9EC5F1187E80C9736CA824CFADE4FB68F6749EA460BDE55062B606705B4AFE8FC341616D148E673563A8F06504E998EB349F0D21BAB3E39BD933B0C289B49FB501C41FE1C075C8648B61846C0F1430ABE36A56026E19423A15EBCEF8ECB8CED12CD21834129CEF347488BECB6E202A2219F761C8A7519F2FF7C24C9A53936C23CA948061B2848870D8A4B3B01F0D23706197E0C072D3F7167B1B034A5C5811EBDDB4BCC6E9C0F4713A8C9B0CA5D564574182B33BF0DB491227368F3F8663DA6170EC999AB46147AA250819F687B8EAC2EBC9203B1C873033CE5A58933AC7A91AF4404CF32C84D16C6011F1204ED5281CD7FFB5F5DA13346B04EE8F22A3942FEC43F426B58C7C3F0FEC6709D8CCC4A2D044FC5394388FEAB3987377E70FF87F5C0E62567412C03C31BFE8EF829CD64E700E7DDEBB39CF685EC557B449765EF067DCF5B815B8CDAB40A0BB14DEA500354A39B2F1EFAEDA005F05BE4EF1D37B086592274982A12017253D189234019FA25F47C01DE7F549553C274578B8F110B3068DCD8F2B0F4C184D7C62D964395F26A0872F72FACBB168300F0E8C179317CF0482020C024854B7EA2B9FAD70F8511870452DE1F55949FD528861124CCA21C4CCE7F57C8200F3F158BD0970E10717AC0B6A8A8E78190738B970C70F045CFD4F3F207953EAA90EFF73232E4AD1C111C7F99768ECC36C836DE4AB857F09135C3064626A3D1C3A057D886B262E141AB2C0294B83619044BA70BB6350D1E86DBC16421B534E286025BFE7CB9D2FC07B98BD805E45EE5523CA7ABD2EE9FEF18F1CE720EEE3BEF82CC85EC5038001A7F73D045C4FA9A8D6608B05CBD5D1C27974C41E3470B1817BCAD720E51A6E71D153AD8C13032738E4FE9CBC90FC2159D947F2856F1F1A9491AA8792A1063F86C1E0C6941DF82973279C6F817368DCC6C7ED47DC1A3F54A5BD7870F366CA27FCB86723F9C2F2562C5E107834E4ED33B698D863D6D9011A2CF7E2085E1CB2DBA27A8F58A7A89AA87519242C0AF79FC9ADFA23D6252EF88BF4A768FA9F6F51E462F52D4E5AB8A4FBE4027987494F7F546FF3657270CA19DB6B75DA11F57B55F82EC2DBEB4DC6BE3BE7D960AEDEE9B0ED5C7B1AEC3BAD14C7EAA754B4C7D0DD507C1F08B8AF484F648D72750630535007D6D3360AFA80ED36F0EF03DE828226C8217BBCB431DA6C3C02E68FD92E3640F6096F4FA74B143D944A84689A8A322EF6D6C32C2C4D19E6EE4E09EA32DCD6226509FE12F43874B90A42C843FBF6AC36EEBD202B5F1303598C7B35BEC559101C31B710F6C2342437DE1D7F4464C431816F987B348013F9062D8A9C80D5A3812CE795BF69F5718DE0341A9C41FD23A6EA6BB00D0B461B958B307BCE63F3EF6F5E0C08330C4965BCF0BF5BF12F4C9CE6C994198804C42DFF57BC00ECBFDC6A19DCF903FCBF58E36841089EC5D854C79918ADAB739ED1A6CCD123F9AC4316BFC48DEBA7416AFA67E5D1E601F4C720BC7E33ACD77821C8F1B1E910C90D9A60C3288199F2B50BA73CE15D9302F812B32E0772AB4A8F6A4252990B48CEB9FDDDBFF7FBE7F1F4EEBF7FD7B63C87415774264A269161CD8FE1C5F3EB597D9343B4EBA73BDB0FCF7EE9346F4F3FB4E8E74EF3B6B1A9D52C095BE175D8AFCF83066A33864C961EBBD1C62C48525CCCAC0B4AAD6F3ACC507093C9E1B08C4121E0CFE7D00C9056E02E2A15DF24855EF86CD6A2F504475A51C61D017CBEE49CA071050EB98697B178C9D17E3E936E14BB944B343579F3A2ED71DEB4101D7E0445547C918593945B126C5DFC7D4C211C01A2A7D74632FDFEE67D7081F167BD86F158ADD18AA0727DA7610D58ACF44D1D7C85D876AF3530B622BCE0672630F9783A8AC68342601E71E5D1BD0AA229E1DA58864B4016217A19804C4661528D31039A232429C952535274223514C2AAD7021E9B6F2858B4FB2A6AAED7A241AD69E12F83E606CA8ABB9BE08F7917E6ABE282594B2EEC8353C585337EEA9037979F0FE2CD55D5B40E88CE2869DC20BA945405B0BF75AA5B4B60BD6DA3C28C0E95A9F1235D06CE671CA30393A4FBE63CCA287F58751ED6908351B34972543BFAB85B29D6EA6A6A18BAD055A52E6A69A1CBBD904A4297A3DE2B74AEFF0EE04ACC895A8646E0693F5C0602D4A55A6F2A8655A7403F2C982A3557D316EBDCA6EE5F073FC9E655FC770EF6633088E629CA687F76CD455450A557047F6BC9DEEE770B9196F0FB78B6A27CCD1A7EE99A10CB6B7D09C9DAD82BC8D5536189549D9EB0846B62B344FB2CC882CA5245E04281E2CB52D84A62B4DBEDB601911AEC8B332825FCA7B3408D78095ED002F1D66D82CD8200D23CBC9E4FAA73C081FDF4F9BB52EA1CC4EABED7C165E5DE03D8C2CE8377DE71E07600C069FAB4975FDE7AA51112D6CF817CBB049A8E0CD584D2D8772A4A2B56D3BC02A22398A300931F83CB20ED27D12C3BB88CA30104778E682D51495C5A587452B0A2B024AC5F58F26DAD5106EC9395B870514AA59AAC0A88AE252B89CB1854E175555109D08231C55F96C3FA04C5EFCD9455AB26263FC5B5A42450190A85072A2A4A49C216289478BB04DAAB51FCC24F69C56AA22A20BA5456BA5E4920E7553B51D190286EC2551428072D90277F590EEB9526CE08CECAAA5594A597E27251CA6AAB4A92D7336D5D785955901CB4C8D2D1CB7258BFA1C3FB7365D52A0AD24B71A920BD42E2A8B490F88AF18AA1AD53C92F3607A8B06E493797C5920E1EB745250D89C422B9C94F59134A2171F1DD822D06A5321E6B438D1D8156CF9CF5753215AFFBF054D2995B8B8D1211BBDDE191B1215ADC395F5557AC3A0572B66064CDD2DEB76A680EE5AA199D502C5181C985A462D628E1AE4A6F15A35AA5CF6C79F9E6FD0462B4390EE85E5BA5EE10C0FE968A97A5B0959A52DA7702AD6EC0F774A87E45BD722AF91BE40055AA5BA9814BE6D9390215A6DAFE3A9F31DB76106A798B33CDFC7D35695B55CA646DCEBF4B2A5512724E2456F32CECBA7134395EDAB4DC8CBCAC650680BF69F9D9B9CB154C9A57E249C1174C29E4EB0AFC28585301D2FE4AECE80A7E7EF4FB0A0C6960CD111DECABBC8C20A1FDCCC8B7051EC8E245C2BAC6A8322B0ABC6C5018CC94AAB482D6EC60C0064C560D6201B438888597E5B09582D85CB56A63D94F716910ABBA3A17C6C21B637CC1BCB4A2980468C1C0E22FCB612BCDD5D714939FE29A6212C8B498F8BD970A422240BF88E855195CC5F5B175A4E323B754367A88E617C7CC81164DB32AA221C0A241862B5B25701597C3D6118D8FDC52D1884AA59B4F5EE151457BF855911DC2150FBC12A84A436E1DB179682D955A814C1095A14F74D3A8824C08B0409F685DAB04AEE262D83A82F1915B2A1951690D7DC28A86F0CAB7B7AD05B002D119DBDA1EA84AEB5E6B892D4F6BB9D4966F4FFB85666D50D3DDC92A3203B8E218A104AA5274B096CCF2B496CAACD02E85DADDF1851E9C3689397B4AE7E6F1C081383A390B12100E3FCD9F9E1AE729CF508473941C1ED1AC0E5D701E472E39B103DFF1461F24B6012FF2D7A9210CEF2FC03F8F649B5AE3707A918DA06C6B4BCC3A714ADABE89E7D9BC17CA3C4C02FA343A6BA5495F9DA0B08BD9161E8B6F7F386E17543A66B53FD299F66368C116AB5D4DE2417844993DB848F48C14FF2764FDA3386D2E6EDBF80F43E5CF3A31EF79CB60DA1FC5C9EFA12B832ABD28075B01DBC8887C551517490186F4EF4206C0472531109CE41E8F43BD8CA69F5269A5FAF1A40793A0BA104593B74FC14F6E101A809370AC4C033D5E9A8FB98B1578E150DEDFE44FEF23DA05302F53F2677ECF917EAA25C368768279B88E58F02ECC32BEB046D73AF0DFBFD0FD78F8F19C029EE0CF09A5DB13D77B90EB9E44D49317149971E3C237A4955C3C835AC94001C1B024D57284F22EC37BF2750E8FDD61185300C5E371582B27AC927A1EE32DB0A0A9F15222B3ADCC4C8A37F1723D242F5088D3710BFC172F2ED10F52C676C4C9280442DD9F4F66D94D9D0A518D4D0954420A0A4B9539725B4DCAE497BBC12AA5E9E0B0D8345E21B3E5FD7359A30B10461D8E5FE85789AC5B102F44E0DE8F6B52665A334F77CEE4EB1640CEE259BD913FA0BEB1A154B6CE2B43F0319B5ED4F0C09E2AF838CB15844EC94534B40B7A13B969461AC37B13AC15FD10CA8ED75A3AEA2E805E5ED737243001A1E3D6CA744FDF2B105019E6C54291D4CE7BE360FA49ACB7CA2B10FC0E1409802E62E92E903A45B7010FD08D895B41C43F0AD792253559EA5D2DCF473CED8BBC04FAB6049E70FD66DC6BD11D7A6A7953DC5E16778898B8D92052D8DC16B0BE363171E1B90AB5CFA340A9848A08D03FB76A447173BD744482A5B606A2B0F2EE2084621C805E3C3CA495430F20B5B63A46CBEA6AA119D4DBC405AACE5D3F65F506AF7C8347C9EB7A2EAD008A51B0CB6705228BC0914822A00497F3681C9D557CA84095B353505422004C77A52164E1A1E639DF4E69E6B4163AFE570E28618C98B40A1BDA1F7EE4FEF023F843052EDDE147E50E09B776CB12F2F4A33274071AF786F4DA755945D91CD6C1DB7AD42B493451EF614C3B0612A35E13A3F4FFD55176CE7248AE22D41EE2CE68D7461FD3EAD4504DB05B6A07EA85D979F5362966D45F609E8405EAC34264495850920411C4734E51F105CF072ADE8161D88340EBD3A143996B214071753319F06B63BD8DA37A41833947B62E65055A8B6078F390AB2F1707FCF5602DE20DB892791B4CBE4CA55D8D1BA4AF6A9750D519359C0EB1065EBD9DCBA851DA0FBA728EB4BCD266D9466E2C2CA278E14F6403C9597F73EB50EDF338F55112C42D754C6776CDC4D381587A900A2B38105AAB9448D1E4A2426DAC691D63741DF12925A663E31E5EA403B36584D9B4AD064F17E22DFCAA39A2E08849650A119F707B588018DF162216A3A618F74F02A010BD0028A440E3B118FF737A5D889D5E17E21656208F5D94DB685D1C227D4BD5CA395514415AE17D78DF5D0FBAA45CF5AE87D22E1F23723470CEEF5AACE73DB1D258C3D6AACA5B501935F0F90FD1B5426F0F3D9A78E3B07A1BAB207F0893657814C1891C29AE645C09C85B30D5240080DA40F947B879F5459947BBB732359D1535E9E00A662614706EB129E8E55D7DBFA847EF1EE5B3281437C7A42E39DE62B547B807CDA78F479B3528D1FDC66A9B8FB1A4AE1404ACD8A34174E980F37704FEA80DAF1F4BF7B3A5560690501B293D76A6065F82499E1DE9681333461ED4B6A42241A4B1559B5D1F66F10C4AEBAAB873A641BA670D82F99A0DD5FDBCC6241D95D6BC25A9B5D3B76E5C733C0AFDB5D60C331E21B3256B8663BA10C78C754298E1A57AAD30E59366CB0820446B9E8C69311325236617AAFC50562E98CE13A098FE7B91C8770A119D03F1A221812824BA4855C51312DE9A8390AF8663E060D5375E482C3D9D12E6885993581199BC31383626DE62950584282DA63569BBA32FE04A3B4B2BBD025674A4CEF3736A9650369EAD2DBCE60F3A82698260625FDFC43923EFD5FA2F0C7AE30007CE16EFC82DB6596BCAACA1F285EC24FE9284275F71B1F3178654E46B122DBE65B78DCD26EBECF0EBB1A28DD43A63F0FB96EB72ED91EB75725DB53F0E8344B62D2F8FE84CDC5495B755C5220FB6D659CD216558753DC75A84FC5A2B3AB4E3E4BB65FB8D7D2997645B74C5966FF250C3CB01F30B704D66A96F794DB971C575A34205436FB01AEA0CD5A256165DCFA6977CE543216F1AA3B0A9D699ECA4FBB484E1B77484CD3474319A571B694FEC2848EBE75DD68C5759D55C7951D387BD684D934B29CC44918551BD37D359810E1B96CC936347D478291D13D5E03B231EE8FC0A063D189934A5D54361F645F24DC0C907F7A90BCD17E3C97CF23429BA0A0E18D9736A8E46F4250CA74DDE0BED87B041CCF28CCECD6A4F08D690B991B2F8E2621CBE0BC798081F861708ADE65EB337BE7CE0D413A505F5D6DC6CA246DB15D0D8D399971798C14962D7DD776C24B2C110C63A809DCB5BB33E26A93A2A1DDB86507650645964245EE87DD4DF29B0AD9D75895EC0E29DED0D13D2BB41B689791A36AD3C0D9A8E88F145C66E814A310B9122BAB1D9F5A6B796718EA0A606097E03E1C5145C6C34206948C69BF2332B32B394F95908A57481F5B5069ADFDC958A29273576B62A34112A4592FE104C035CAF14D5BFF675FFFBEDEBCA5D3DFF1E2AD754E49DC22578737A6697F3948ABE7C8E363095BBC03AB5A30D4CE506702E20E6A601BF28231DC4EFDCD39A4D50361158DFE05FCA7005DD9ACDD3515DE7FFF291E25B6C4DD78316B6596CAF600396C100FF3E1089A1598CC00CD600CEDA90203958B3794763FE895B7D67F954A6ECE4817D042377FCE01F62FB7CC93905B4B0E6F694778F8F86FC012DB2E42C803EA1B0EA318A4AEB2B87360D4B3EEA1444F1898F4A34EC3311EB1C3858E7C4C1AF71E4A0EA99838DAF7F02C0753DAED5291177CEEC94ED872BBBB31448EFBE15599E62144B4DCF46E909856526F89F5618B6008A3DEF3FA100F8BFCEBA6F5180E28B4EA4F9E389E09ECDC1C6F4613292D61D3841F26A8467879C77A756087906C31777298A3DBE9A1FCB2A5B5B726E6E68B75A9BB038B7C2CC12CE359CE03C4B6EA4A2188DD060A756B4BA42236415D50868459FCC9B92B9D9366FB454DE160D97EF05FDEE543FAFD6005945F7C21D63166F65C2F72D05583DC9540E6563A5E9D816949CB84ABA25EB74167166ACD745A20CAB934839AFAA10600D10949A5E9FB2D2C09BABEB055F08382D7859B2E66E0B6D53C638067F5B6C1397C9BB7BEB2D931770B37CC5BCA88DB9C5F3F419181CEC111D477A6C8AD9FDA6B05443CF4E77CF962A45594DAF96DB50EEFA23FF802986136DF1FB801F5E911B344ED31AA612184BA822F6CC83BBDDE493574707AF95E4B6B382A4760A6443E5C651E23C5D6E7D88DF9FE88B77A0BB2772214CAE1408636980386DD3A9DAE1FDC187C156FDDBC5EC7AD180200E78003D320CA0B08902A3A2558492AFCA55C3995F72E61C1BB3084FA7E4CAC0EACEC6413FF4B5A72984200C6F215DDEAEB5097B5ADD94C23249DFFAD43487572DC38A3553FCC09DBBB66AE6CA248882F54D323ECFA2CB889F4CBB67AFE1E8EFECAAD54CEBCBC8421ECE52BBFC6D9E6CA97E7C834BD8623AA364446225492C32D31713EA0DDAE02756D5022F0C9DB66A53A361ACF6F29131D3B6AEA8921825D41144E824980EC6B461A7EFD80855407FE088DD661B01F25CE3C7B2B660F2264FCFDC6A92D53F16419217BE20180CE8C3672FA3146CA7CEA9B151F0BE5EE388E4C534ABA1522975BC26B16459D01F11A21C01FDAA5E936C9662CFF7B471306753E6A4E55D6785573EED58450D0A6992760B82776C275091CFAFA2B82A5AD37B27733BC1ACE48B7FAA5D9D5DACEDD4E48016C111D6B392AE54C2CB8F44224275BB32B7A3548263C9B24EEE6AA3B583E67C6BDACFB6DC4A328ED7D796B1E9A963DEA0A313F9E17450F71EBFCF778918FB1E64669E7A5CBBE18B46D429CA671B63AC781F82ACAB78BD64AB81D70EC1A4CAC51B30C33BDA83211F363DF114E200B6867FBE860923C70A7725B4A118CABB23C74CFE6CC19B03784A93BE60164A742453C78A741E914B91EF926107B8BDBF46C7E88C9B46E77840CA3581364C7FA2F6FB09DB18754ED442A22221C45AEAE7B0AF52409621E3DBD578F999E0EB9BBA224C553655E6C3CDAA14D723A76955223416D918572525DAC289C9665624B8163583949F8E11B2EBE85FC655A9F9455B7D6021A5676B1AEB72EA0FEC0AFA2B07ACED7901878D2553D5D4F966DCF239AA51C33339FD47F4553C8A165F787E05062FC2C8A06307D3B42888793565283CA5AFC27B9BF6DECA702E1A067141D48BC651461D378A068370CAFBDAA5BDE59A1A075F3C1C423BF9FCA35C3E5E468AD4C7AEEA646C2AAD6DD714A74DAAC3F3A32AD52BBC95499D2AD750F98D72359670B54EFB553A41516342BDFA9E82C9DA366EA9E53A5CCD24CA31B956A2641581749A2F021E316B926365F7DCE030940FE1083F2401A3F6C0B82F8A68AEA4EBCBF08617FDBAD2B36E8418E52146C6EC18D96C7FF8565C0DBA52510C4DE742081068F5507D57E64AAEA39A856EB4DD3DDBDEDB697C27AAB7D58156AA75B555B3F205DA0C8C963120D71346650CEC9E6D77FC1C60B59187038E40CDC94D26D4F735CC06B26DB6B773A8606EF230BB08D391407468D090227B0C788FE17F07ECCA9EAD8E2CC81142DE00E40D408E2C48C13BA9887D224B3D8D0E0D982BB124A595047BC384E033C948E7ED54054A9BE267312AA3A820161379E886C6D72E7F26E268AAAD771150DE88A735500785F88B0D81DD7AC9A52226B4F882E6EAE6E865E27C4CFEBD98B36900673945FC345653F62D5E042EB95CE091890987ABE3C3717C9583E4F688DF36E4AE058FFEA1B6992B14F9653AC2C23FB4A76C9D560D63B037995D2A06786EB595B7777201467A8C6BF8E8CA71938FBC82D808CFC140BC863F582E098A306458572E77A231B3EA127F8736B05AC9CC418F94DBE45D8500F941A94625BDF60F4A352A6D187B50120D837F18938AC686CDEAAB201BF1C4AA75F3C577AC7E8D2B0B0A87DE60B4E4727DC864B1242930C0E8C6FE166FED5A2E515E0E346F24CD13A3A33D5CDF28B27CFC98AB4EC54C7C260F452C9409FBB3A5ED8ADB69B66143E878A03AEB617B5F1E1CF1CAE25178DF9CAA42B10D272DAA66C47EAF8CB2D1220E81B8DD51AEB1342D29EB1ACB87A8FEACA46750F36655D932A16773DB68A7D2E6D2CE998CE1FD1B944E8B4DDE23D970D1685213C318CA6E8E94988D974A89222D636E2A9FCEF3D7427293141EBFDB88472BD474885EBFEB07FC927C3DD700B54EC9A75568A0F00BAB1001B599E2183FBA0AE18B4278E345281ABD14E3C8C64811E4B388BEEF59D742DA663E24F61761958428C6B4708CAAE2703BE819C4EC8845B0848B6AF892A6ADF5912E34E775235149DD04B374C1D3514D2D89669E19B9DF6CF32D00719D39BA0EC73F0672025B80A5C0F34A5EC55542733B8CDA2EEDA129E6E2165CB9B4B956ADD6003F12F3BCA6E80053FEB4847895EB0F23B86A88031294F8B14E5BF54C8AC37C438139BCB9E35F5CB4A7927690EBF49A5CCFB751B873CB4A28543B787FC938D1ECA2B22D622A472B2B0F310861E60EB1A0BD7560CA0CA68192E56231155D5B734B5B18D6E412E1E6F4B15E022A3B86B0A32F14C9630210D56AC1F06C877F7A270580689DFC7D50D4C827ED4BC2BFCDE1EDF930892747E24868D1BCECADB8E0E1E65DE29857248C0871B27ED431C8190DC4F7CF27BD70A0930680AEA3D6033EB9DFDE9A0D868BD624BE5CB4AE26976DA0D3B0548044FA2E9EC31414A40C150FCBBADE38C6E2B43E3236326876154F13BCDD9A66308AF9A194BC3E6CE8003ABF9643D5DF61751CBF9BB8673C0EB37053C763943129CFA3B325AB107A39D2672264FC951F07AA4545338C424E8A1811883471230AD222E50A8C9D6B7628F5657019518742D7CE2EF04F087FD3AB2175B0CD76D1C28CAFFF6502033A4022D21F98CCA8832DBC51C8563AEFA559423F23F94DEC7F2305EE34519FC4EE53A3D1D269004460D69B47E301BF3DB7CA8491D03634A3EBCFF63F77921F8349917D4D055749043E8B24671653126F0BF0739707EE5A9D62F06CD6C49B92173441791A8F791AAC7F1B0E87A28F73E04390D00FC1241AD3F2E05FC264104C83263B09C7976116F5E1671A4CD3ED344CA2521CE4CE71EBB9F5309CE44F3778352EEF770A0C93A5D4B2943C92B330517031580FD2FC402ED9FD888675C7E3A051E2657A1622775A61F66E8C4201368EE3998B561A5A7743C42DAD7C1471070F1DEADA3074C2E43290CA684CACB507990EBE1C33B85D5953A0B5726672FD6E28B6BDEDF50538734E6C6EB9DDB9D5696C6D56E017FF1816B0667E3523B7C62E5DA35CBABB6BE67D4196A15A74C1D34AC962DC14024D3D09D2D1698D709FF76ECE5179CFD55D1A0173C644260B33EF94CD9CB10BED678E06047DDCC064209E55445D0DEFDD9510F37D233CF4568A5D7C2865393E6373BC185B7EEB55B1EBE8A4437039E9EA74EF7E39C26AD7BC22E9A59489149319E8CA295727BBBCC595E9CA8F0D1690163456197DCF388ACF197F6FE98E5D9EA5BBBF214FEAB3AABF2B49F1EF58FCC6922ADE075FD7CAAF64CEFFA853B09937307292A3A58E755AEC25A0B698D43AA9919BD3C848A767DF66EE4E7D5245AF315833CC5547A8A7BDEB0CAAE5682A8E836A88D6E1271FF45690953E3350512CC5158A05505EA7BC8227445A1A85540D0D0A638E325163FCB86294517C846AA9BC3C7556AA50E8B84BAB94C2FB162DD589C812478D40CBC3420FE66A68970C0F7ACB73468950AFEEA15772C045B5DFAE411B5D65A772726BA64E18E241B9F4A48F17A7D3E092E55A73666464D530E6C80536579F8C4A54623CA356D1802D3E506528A09B1547545A9A14A76AF61B5C7617196F8AFDB2D80D5D8D51AAF335F8E4F4667CFFF2352E57F530152D9013CA2B372A3C9D190C61BA59359196065E358F96278596D282C265136B1832EF876654DAC6DC120AABB05BDB31AFC6F96F9F96D5E4154BF6793BE2DA1CBFC987A90CD7E5B4BB36A7DD4A9C7605A74B0F013DF0E50A7EBC7AAE60633CD14F754CF5986755CED4275CD9812A59C5451561451C064AF919D442DB29F377A824A0CA26F7C671FF534D0D308376CDFEC4EA32DC086BA3CE99FB555B6326BF2D6C09D634922C562057D425F974C4E5C8F40771392A782E45C42D014C84EAB6967EF6E166438B7877BA6A5454D13E154D4FE365A7BE977160854ED62DCB9C0C6DC4527C72A49B2FA44AB8CEDE731720B7A2FC58E55D11F7CBAC9CCA58477C578E4C4BED4C5D3DAD7DDB915BF1C6DAF516A03340BAB5660161D3FB6A967D1345EFDCF2D7E039C78D97E7EA93D74A2CCF3E87E31C2FB918C743BD66E963EFC960F00EC2173A9274373F04FD9646375764E272C8341A9EE0D6B29F25D64CD94EB424758341287AD44B543E6F1873DB7C27EF60A7753F9C1C6EB2B691735B278DA543026069E4412A27BDDC57768B26E5DD87EACC929EC11C63F1011E34D92A1BCAD68AA7AA43C64D2FE35436021557C0700D8A966E90CCC6CA23C0AA577DB4FBB9D05BFD4AA25B28D2EFBA2404797CC756BAE57747EAAED6DB13555AB7B2A36CADA1DCC114CCBE0A11FE22FB4C37E431763F6F9ECD3F5430170BD5B14B2D02E7887CAEBAB53221EBD77360F9B37D1CFF362B60C806EAEC59A7F5F353132E347F233D915501A3F9EE2C65E3D636E08225D3BEF99974161556EB32F561D4B57BCDB3A4B4A63C8A392B955BE5EEA9C6B77438DC7C44D71CEE2D3F8F602CC6A893EB12F3852F117084377BDFD31D26FB5887E2C34D9EA0C6E5128BEFFD6ACA3A265F73A8281E576656769B7BCFFFA0320635812171F1EBE9B3BCF2949EE9C5BB61A2198A23F36681EA0D5FCE0F4513068992DD6F970364E04D7C2195CCCC9241DA4F2C884BA73CD156693E0C0FC87A29310661614A0CE3D50A29313CA6C5D295E2E413E50AA654E933535194AD11819562AB1DAC11AF8CB8F9EE91B6D1EAFDEA3B5D5CC8569C649F273126C57A155AEFBDF009B1DC5559F55AF05A44FC8B986B60F2DF5EE7C8D4994B3ADDFC668A559E8ACC1ADEFBED586651941B218224ED7134590E4C6C650828DAA5505F60DCC81FCAA112AD057888CAB945CFABDEEA9152A01E4BF6599524AC99BD3D76D4B16E41B43489927EFFDF44EEB9635B6B0CD15F672C6278F46638ACAD3D260BF240F8BEC7AA8D778155E365FEF3824B2CD6D714B2DC07162B8062877705215711AE9FC83A06CF8B69958187557E87036FABC2C0FB7A064F5D42F97A06EF1F58EE5FC8E0B135B57B95C1B88AC55B6128955BBCDC12B1670BBB34CE5BD92EAF2212218AD5691428FFCA88CA46C952FD2C72C879C55C99AF5584E8E8D5CAB4AAABD56DB1BEF0B2FC52A679E27E65855F450A155ABF92A75B19D167A95291A95B4D953E5B882BA8D20A32285225B35D4BACD0FA967DB9ADFDEC0158C5A0AF64C656C754EAED976A5F9599C5170B70BA15A774DD65214EF75768F5170A2FD6ECD555947095E86205155A3A9F2A7606F9FD29EFF5ABAF20CCCFB6835584B89237591DD3E7E97695D0F92B8E68FF9CE5AB8FE82AADFE4223FA9F77C270476C1E85D3A0370EFF23BCE9C54132782D0E16F99798DD3D28FF4AF35DB55F24371F8ECCCD07AB78DF5FFCB05175EBC8B32575977F5A145B8ACA4BDB9627564A07A5C0EF8BD33242AFEC1D4A1CD60B347C26CE23B6C7C4F7227571432A93A255B4E76824F9B12B544C315D77B936B7246F8BBA32D7EDAEF60CE4E64F3CFD14DE0CE2ABA994DE2751E9090183667909C0E85F8702988A02843659139998E2624701509FD4047FC1DF30ED073333CF8000D800B985FA33F0C78C322A238DA7581D33255F8DA2FE4854C12FA2F28F4DB4300DC5D35190205C5D60F37C2A4C10662E9DEE0342FEECCDABF3BFFCC7F9F3774F9FBC7D7E28064E9D7806195CD7F896AA7CEEEBE7BE1804023F941A85DD07D2EF1A9FACE5298CEF586B04469DDD2E0E2104740EC16091757A462D24F04525F78E70A505A5FC4A916739C9B7EAC48DA365D52B11FC8C152C692AF39F91B704C9BF015773BA62F7414E5CEED61B46558E6733E7423C79456E1459B92D9607BE398FA8F9C9E5A4F94DF8F94D48FB3B719AEBC4876B762215F9F719BE589BB6BE48F75251F97ACE57E2741953E5F38A2FCED49D126739F35D28F1073F3C16F16EB3F37705BB4F8FB96FD50CCA8652865B49FF3A932909DD849C60F21D20F3CA9126EA5E784039A8E44DB7925517C838B465F08333CAA5FC28A08AFC6C3BFCD8AB47EA2C925739BEB2148BAF8DFC36522CE12727C522D5761CA8A9D4E90926E1183459FA0EB37B0C8A959C0E1C0970F11909ED78F1ABA3F957EA94D1AF96D7DE08AE053F9E79BCEFCEA26C7EC1B41605E234504613F9A65364C11B2E8428322D98B9097DBAF305B3DDB8196B8415AC929B46C5923E53EE41EE19263AAECA5D0F318421931F96CC5FAC4C60E9D3603C9667CCE8DE9EFA620986E0E235F582D2124CB54C42C7991BD06BC8DEF4A9B7CD201E74D5141A6AB2ADBF33E1B960D80B41D74394A9106AC9FD4205BBEAF542A2EDB963E8F2682F021439D2C14A270095EC12083C4072789ACD68EA3C89CEF1D398583D9E8186F6E984450BCB0E2550125E1CB53FFC5BEBBB6FDA1754286B1DC91FEA46078036D9E62657A81C4676A4081280F101C83BEE6977EBA05EA135C06BAC3027D7F758E5078C96DE64E5DD4045A1A84426B3C205572A9E04D76F3805869717C022CFC21078D86B32C1ED81BC32C7EFC1522D6EDADF85E3B09FA5757533CB56F311E8384F01973664D64D5E51949A153D5F6B2958A490079D6BDD9D1DEF87110AEAA9D49B46453D24ED8C9269300C92C850B0AA192DE367EB26AC4356B0766BE0E4AB1328AD77CAD0E592D5D133CF55577B34CA26E3C78F46613078FCA8CDFFC181050FE21F02A819358D7476D2DCB826EBD774AEC59EACC418D205EA6AB65082AE6A0AD7BA69DD1F85FD4F3F083DF2C4F7BFC227C210838111274486165BFE5232AA72054BCD6774C8DFE481FA23EF715553EDCCC81C8555D71AC2E620D38DFBFEE6C5E0B048B2665A6153B6D1D379829C36F1BCF3447BF081C8168DA5103A4B30348A54B4AD8AC028AA9FDBF4529A0DC201A6944ED3D3C3A3239E2F402D8F63766199F89AA7FA7D364FF8D13FEDCD391EAC6922EA3A88F62A23EADA88766D44DDEA1CEDDA88EE3988AA7374CF46B46723DAADCED19E8DE8BE83A83A47F76D440F6C44F7AA73E4D62C67A160E7835258986A4BF644296BFA62A06665C2CC21007E630F57187161513C1F8A1AD13BF4E1CCBDC64950E4DEB1E21ED4D3A959CD778F69D301DFFB5ECB6F144B1A51FA3A785DE78F122F7F52ECC800C3D70A11DEC8841B3645F99253D46804CD37765DF92CE9A6CF54B895A72B821B5B84A25021F88B79FF3C8F435F4FB7D1E87289291656CC0E20A0671B4A482FA6FD44C268F9A1AEB5455A9385B4D40B151F2E727B3F0B7BE74964A1464AC2BC5B848819D0E46379FA6A680489F7714F01DAB487179DEA465C04E5BBAAC8FE7A0DBCEAEC501DD169396A51FA2A06E1409081E8A9DF144CBE4A3D55135C1912A391D620DF118BBAC043D6C0213C1D71B993AF973BEA58659BD12757FE79383416B2E745101A2B1D56EA0B16437E1ECA011E46E38C6E816F06E3D928A88BCA47F8517A43FBE97BF4525914D6C747D2A798EDA7EBF8B478E0CA44E50CA1AF7D3B9CF00B557ADB7993B3B649B9F375725E1DB2F9AF141AF235F9A41AC6440478CE77FBB2B033E67018582615E34EB38A37F014009888CA5A3A30677CFE26E545EFEED1DA9D60EF167FA9AE2814162DEFAD222A5DC12B283DF792BDE54EBA084C5F42EB9C31E3DE59A10C9775FA976B87BB165CA8801B05AAE357427FC6623B6B150E6724070231E7FBD62887DF86AD425035534738E18DA11866E9F04A2E85E5D6D0DCF6FBA4F81BF37CA7640A25D649FE152C09FFB56EB824BCDF3F6AC0B49E83E69DF01D4CAEBEB673364680CF353FD2FBCFF64709DDD40742E4D2F2B82CE8E544094A3DCF17867C0875F714E2B4522E19150CCCCACD24B828CEBD407593A99CA971BACE5866CA6D2D3B0EC6C97AE8F9F6853074D3288B82B14A53E0DB5528742B19DAC2CACB5702DA758C86572995CE17F227C6F27125E3BCCDEA7244D007BA8ACDB3B9124CA8A599E0F8B5C6C8F786154010D3BCE796892CE1E584FF259B2BADEEAFD4D0F2CFCEFD64BAB0147742E532D34F4DCCF2708DFFA835ADA6625EFA39DF4D3F733A390DAF7E523ECDDA3338D694D00520296EDECC4B812AB709E2315304A02613EE47A22AEF4A2ADA12F02853BD1C07819C80844926FD82BEE0680F0C384339148DC7791ADB92C6B649E3914943BEE605391A77C45AA3E80777C499C5252AA83E8E662B1F3E09116CF227DE62FDA89956657543335181C4A314B7F2F1F91E6AA0453165444DB872BFF25668E7728D5D6EECF262D316AFCC8C53F957F82899F8845AE1703AE1C3E9E4B387D3C9B2E1742286D3497E38A959102AE789673C9D88F174A275FD448EA713EF783A51E3E9848FA79365E3E9448C278BC6B6A4E11B4F27723C9D88F1E4A3618FA713FF783AA9369E4E0AC6D3893D9ECCC7E2F1B4D5DAE93A638A8ACAC795F810951C5827E6C0CA7D3E71C9C03A597D609D78079639F23C3B9CE2C4FF57FF1E63E120B492CE30EFE6561A8E872D4CADF8D73774A65CC855AC9C0BABF183C8B72BF6970C70D03B1783A3E16AE4CA9D253983304FFB3BEF449E9EF7F1AC91E3A614DCA1AD36E3705BD5D332C4657CC95B2258264E9E76CB1126AADB35977493DDC81F5CADA8AFE4833EFC8F2C0ABDE3491EB939D27B819C2D50F7BF0AE6AF55572AFE398CFAEAEAC68D02A9FB7BCF24257ACF2832532B3A153537B29EC15F51AF1BE215341F3BB237EF32348A5A69A0F135B5989CC157116EEF4EED266EC16F365A51164EEA3BB9CFFFFA68AF80C7B800A219AACB9F8FBC12E2039E1D17BF846E11285C4DB829C52C7BDE8F5AA9CA8DC62DB7DBF2DA434236B4DED5C386A38892718D49CBD81C2FCBF0142A749149F098A3A277E015220C248A9B58689978CDC2262DA967A8892352EB91962DDCCE332883540C78AF68EDE712844ACEAE315B62760BE45569CC5415E20AC8FEA1242BBC0BFA588D570F69131E915B14AD612BB1A8C65E3B48948D31A5605915E13EF1D43245437585AF693058E2F8D053949D4B1667D0AC89037D92D69D15A4CBBB9E03F2E382BE985020124771642C88BD28DE40ACE75B7F131C61776EE269BA4D5A36855F83704A178AAC94E882EB10BF1B5C8169822BE699A3F1B0CC5F7C298E8D39E30FC67CD1C7917530CAC398B198BAA1BBCE3E4E055C8B9847198FE55D6A2E157EE4FC7CF4F4EA47CD89EED88F9F2F26B5A29BDBDFDB709BADFA7ECD561B3A51D068472DAC360BCDF8AA4D2E5D0CB08EA5968DEC54812C19241CB078940844A636322110F1EA773E50B424D654195342053AE30AC9521A29A6DF4E6B66EEED94E855341E47C6AEE234BE62FC06CD339C28AB65A1F03AA2650C7C0992BAE08B1AF506AD53100E84BC1A45E3103A0FEF0188A5170F3EBE14646179AC08349C23F6856DE9C7935E34B55A133C99F64771923659F0240903A35963A8FE329A7EC2DE3F3D2B527159DFA3480A416B364F478A12AD5C08B5F563443EAAE04338139B880A14DC61F1B2209E9278369F8D235005EB461D43BC4970A3E510BC0E657FF05883AFE01D00EF9AF526C3337A81793D86B7666AB64056B9E655508511BBAA700D156EE01F3D02B0DB11E4F41A6F55D9B7BD51ED03B918947B8B4A8127C9A3E93C64B199608BF01974CF9881C7912582158A71869F43F889EC8025412DBB2B6943ED2F26EDD306337F31B978CB6F9A8589D858D862DD1D3986467E04F70B108C78B869621887C38C1999C7EB302F0FC3692BB80C223E8B6F77316176FD0AFE5563378B6785957804296A8DCC5A576F66642C37A921B4D97B452B8F9C2F2A18510172458FC41E9600452A40CAF0CC09FEA70DC30BFF6AC20DA2040C649C44617AB4D3941751E02758E2792F48E017ADD4E12D1BF8CD1725A01CA153309E73FC41E923387016C763FAB5291B35F01AB7ABD7FCF8768D7FF70F581968DBA480FE9CE0C4DFE323F0C0367758A44474C92DE9633D2A343ED52EFC0C5D62407C4D4EBAC985DDC855690D815AAA79401CEE7A32D154DB089BCDCE0EDFC52F5173CD90B3E2A6BCA572C18A13D56E3054831BE5AA6A9855641C66EA4CBDD300A227F7A5ED57C6058C8D9CA464A6097BDB645519C8AD69ED238B0F27034EE804DAE930C3295126E4835CE2390E26EF2D52C94512CF677691B86563ECFD53B17151481A83F373A350011AF9EA159C2E5360D6068D02344B3546FBE694C66A952B7030EFFDF0A979FF4FC03B2F5405E3BA9A06360A15A0FEF88C0253450A48640FD220A24001A8EF6828085962E13001F8B37ACD6F07D2E707358C51A825A73E5368484D95D9E89E4F072E3228B2515930B2448B87AC1ACF0B24C5238BB48130577DCECFAFE45A0957326B1907F44BAD7B50015E6AC52BB4E2929000324B2D2D7C6B6B8B28B1409EE36CC886A122DD26BCF604BE274C2E83B1D12EB3D8D28FD7FAA3409692E8720B9CD4D186A4220B487FF8D1001385B6728EF53D6E035415DB6D9FBA2D37FAD24D19AC21DD376E95B732AD7AAE8A7A6375A8BE666BF5A82A46609A0E0A5797FE2518CF4365B328367C176619D73B697DA9585B45690C5B29049B59BDC66A85B34559CB13FA1A742414CD1C39CE0371474F325A97E0E6779BC4725F964413F51E82462783104E9A2436D9DCEAE83A670DA3FE55841E8498928EAE0F44588D6C7FED40BA30E90AEA82FF230981FBCBEE1935E4096779FC978F79D104D603AF4B1D2EC9A2CF100B2F489C8F7BCBB9D4DB380D5B90FF91772314C5BA1408F08760FA5B7F963BF251461DE7FBA58AB0E5ACD6A6ABB1F8C80EE240F934204C751CEFB73665138FB7C9DC458A236A927ACEA1AE4DDFC6E4E3809C2E054C7D1CFA9285BC935E9B0707958F09E1CCE9AB81B2EB6DAFBF3675F3AEBB87325A308AF1145D3388589BAA42E2A309D102C6857A68EB90A4DE3EED6CEF9EFDD2B9CD9153B32C59A48889EA3E5214B9C01C48B5CE086ED66E9CC451D4B6786637EDF3A8710C3E5A3C084A315452EDB343AF2576511331AA798729865236212B74AB4CC7F888756183C2E9C0690E8F042A13D1892C8A9A62923002C7CA14D4ED701F0198C4D40E98540031A7598EDAEF8DF44C5C0F50238CADB7D1B62F6EC274318D736AE5B2AD6A165382975F9B1085D47A84C880BBDEFE30A87FBB985D2F1A4BF1531DAFF3A6805C235701FB2AD84762EF2F8F1E03BF9908E5A5A77082FEB5C7B989A7283A987127999B42AC4D54E2282248BB3116453923F92C9284C447934FEE75FFA9C9FEEAE408B461693886EC919814C9EE732750A8282BF81EAB7A91839DAAB995A2EACEC4566F9F64C0C254C4010538968B9713BBCF224C488A680EF804D0A2AA678A9F4557A0290C6840A3694E678ADB9C7B7E167185A870D070EF628C99E9E78F18BFB3A156C6D3294C7645F8CA2B79A6C76B93CF7D9DA7988F19CCA07D7C9873EECFE543E12A32D02A138C69A1CD59FCDA1CD849CB4CF2C67EDA467E01B4378FC68337F278B85A01BD6AB25193CD93B1DE095167C8F5E20125E6A61B8946593C087B416AAF32CCC6F38B689A8A0983B1FA00EAC3C4DA85F219C7A2751878902014383652825BBEADB84AC6837768496B42EBC1EDD624BE5CB4C02C2D5A5713F835995DE09F10FEA657C3764476594CFDB1362E319010783762F5DA01EF57A3A9A32C9B1DB4DB575757AD00FC30ED54B6FF960520CECBF01A7E7111B4FA414FECE53A32F123988332E185A1B6A86448BC3F4EA3C1C14EF7FB1FBA7BCFF6B6F79F761E6CDFFBBEBBBBFDFDD3FD9DED67BBF7F6F79F7CFFECD9D3FBDF8BBAA20337A0EE23F19BD04583A34DDCFE90B8B7F0F68FD8FFA9890D2028913B4035B10504455200A2BE1407BE7B5C239A1B1BF0F0087C5430619891E768334DFA9BEC12F598D7829E29AF20830BAB16294E6935D40FAB0A294F6915DC6CC4E0304C5445D42ABB02851D0C5A61B35F4D60B22D4E238837874BA6B9116CC8518453710E6CAA10B5EC519BD8B3186EF3BE7E2CB4406DF25C84D99FA47A89EBA4F5867977536A0C29CC20BA64747EE1685364513FE88493432D1BA235EA3EFED39F5F3CFD8FF72F5E3D676F5F3EF9EBF31F1FB5A1D0029A3D963B3E313F3F4E07DE581282B6C39C9105B8591726EC52DC718D878C18C5CD9F167B3B0E51C7C89443ED90D1ED6E06B1D827D60BC7604541A803086C70439505E0DE404259301E13F01837CB3389BAF5A83D73797B1430CA99B7B964406E32982A820C8F36CFE97626083F9A5C70C5105589B3D4A84D9739DB5761AF170CE08D0000E3F0800ACEB14BDE0F619AF94CF0DFBA8886A03563A0F23FC24C8B6193F1EB0E479B3B9BAC0DDD1E3CCE35A50D5D263B9D1F1BD13E4198323082DC9449D336BB709E43BB000CA6B47DEB19A20D71A6EB5FB6E84BD8222139F452479B97B838AC1574930D822C58C348ADC212F9DADF4A5CCAB0B1626B97537970F1451AFCACFBE0E9B3EFEF3FDF7EF2FCFEB3ED4EA73FDC7E78FFFBFDED7BF7EEEDEDEDEEDDDB81FF7E57AE142291285C4D81FF360FF0E499AA3402468AA1AF26C087828D67C1DF5C0DBCBBBD7D0A1EE5EE8BE7678FB7B78B95136D60C44F76B4AFB72146ED7FBA0A2EC3ED21086AF4655415587974F7142638D1F0CC61E56B4A60A963DCE27EF187974FDE9DF87CE2D67A2EF1C920EE85EC07941FC338384CBEA26FDC2A768DC80639B78BB80DFE8B3A7446FC54F090368649D04FE2493888823649F4FC620E364D7AC9CEFD9DEB7B9D73F083E7D4EA73D1EA8FB30BC3459A62916C94FACA2DE52AABA9B53230D554AFC81E1927D438C461C96D39374E63B9333C3499BA10A768F8924B9CB460529A3CC152E7232B4CD4B854E8B63BC8141DD154B54574894934716B186FF6E45EEA0D552B9751742476848B2A5827898D29A2C5BEA822CEF4F1D0554CA37074B6A2E920BC7E33ACD7545C54C343A5DB1D15C0EA06D232D90FA0F79985229DF752FA384DBDB32F92D96CE813B5BEBCDE14FE832848DA9A85491A21F5BB284A7CAD96E57473C0068AFE6BE02DE77B1E2C57984C592371DE76EEF722FC6ED3D1916E239F72936366C6012A7D02DA7889E73F693EFA9F7CC26F08AE6588901088E3534C9D9FE2E217D8D4E1CEF405372076FAB0DB0D1EE6ADCAC553CC20CB4B5B76A1972B2B297775EE0CAD10153431D141305EDE09B5B8DF702B4903A9756707B362A0476AA16FCABFEF34D96E0E8DD21051641C5DD3B641BC2B340E43508EB7B175782D14EDD707EA43EB8E70D917C1486E82F429B6EA3EFCAFAB8ED41AA751D5E9547ECE541F7795BB1A54A29EC2B1FB85B0FBD2E0A8576F039EA4969818C4A213F9D15103C34B28E0B2A403A4C61B71CE0BB4441C490FC72669815F364636130934B1194DC1FC59A1B4656E47BFFD9D077EE37BA889D5E7815C868A205A68470D695D1BC8387EA8CA848897428CE269580E035E3E89A32588E25998046C124DA37238F0E3FD4FBD30496ECAE1EAB324FCD05ECC82F184C529FDBB18453310F222B80CA6D945BC002BDCFF14268BEB289AC60B40FC777808C778E3BFB104799444E962F7E23C5BF0A3B529EB870BD104E81FA3F490A59320C9484C875679144EA82B97D14299B087ADBDC5E5359E2F5D8C219E5A4CF6E157B87F7F67317F780FFE5CEFC35F1A5763209284E3304D179C9700485F40ADDD7DACFB690E7FE60F094FB7837FEF3D803F0FBBF8139100E0839D451A4CB693C5E4620F7EEEED2D2EF67717D9FDFBC002CC4116934F0F1F2E06F73B7B8BC183FBBB2032AA3146A493D9DE0ED59EEFD2DF7BC4F5E27A109CD3F31EFDBD4F7F1FD0DF878B0031F5F677BBD0AAFDCE22455EA6C85BFA0070F5B7F7E1E7F9E8C1C3070B68CFF6F522FDD4B93F58ECDFDBEF41C115E838B0086D4B5024F71E74AE17971DC0904493FD451FB819C693E06081B1DBE21AFE2EEEEDE3AFFBD0D46C6F677771B5BFFB701175B1A174D46371B5FB701F184B90EC64AFBBD75DF41F74B06959A77B7F71DDED421BF67677017E1FC88CB268BC7DD1590CC737ECF20170BFBBD35D6C5F773ABB8B690C633209169FEE7776A2C57606916BB88066EE257DF867AF0BFFA4C1F4260611EDDD5BF4F7F7F717D36B64648AFC4FB24F0CF8DF83D214E82FB27D6823B6676F111DDEDBDBBF5ECCEEEDDC8B16294AAABF871C6678D1270001DEE390C0E7C39D05B61F259DCE81D03EFC0F244E8A743E99A48BC9CDF52240395FCC3B88A3D7DFDFED2CC25D54AF494AED0E1FEC74E86F77221A910E882D14B8684F40D526575D449180835D0C006294F5610CC2DFF32C9EF7478BDDBDBD6B90E9CEE2D304310F1EECDE5FCCB61FEE753BC87B3F06257A706FF189034FEECDA132D195543EC1EC66414309D4942DD2780AD175D44FE1076F21287AF71E76EF2E4890346F1A7F8A028264FDC90014060C633C0E16F359AB9770ED819F383F594C26B3457A33E9450160538376318906B3C555305B5CC68360882571773183E963982D3EC1781E870B3E9017B374B6C89230B64674A12987195D3408EC74EA76AAC5247C8FD3A123757A526F5BF4FE82B59971CE9B3648E41578B143E149D0E8C9C118F24AF896A26C913250151F145E3E9078257D887666733FF54BB985443909456863BC5128CCE3D71606149A1701BDC87FC491B0FD185E84D75E7409BE51F87491AAFAF4A93A767519A5C162025A3E09AF1703CC0893C23F691F4FE62D3EF67B629F8C90F4FBEF05A3C62353473AB998281D68514323F9D6DB5AF5D6B9AA249147AF22BE65FEF387C1D6372667E048ACED7A5D88DF25D1F583EB82FAC1B5A73E169AF57B2FA6FDF13C85E81AB0708E55C13185C000EED964B44149559DDAF6A66362284DEFC9788C39AD269340120D74C952AA1A569335EA2FA3FBD328025CB3A01F5AC4A9F81D1557E3405770D83030F979C120D61ED87C241A1FD815E5D24234F83749ED3A5CE7DC2A7C0C351A766CAEEC8E8CCAFD635FF271AC932CD37807EEF92BC9FE5D2F4D4E52193B5E2C36A5396662C1B8AB234F4CF3B6F0005E1C3E184FE713B1F2AA51D6737D78CCDA3F9F06DB7FDFD97EF8213D83211059048173F53EFFD67BEA01B397AE40B8946A3592BD30BB0AC3A9244AE35AF68F3958CCC33BF4BE25BFCFD4FED06C5F346B9829FBC005121349B32D2F8C315E17A4288F1A182350285122B29E214A059483E120BE56F5FB460F1AB7B585CE7083ADF3AE6AFEDA3FD78F0FEE9D628FFDD2E9DEC203FFBD7BDB385EEC9D76B6F7CEC4CB7BB78BFBF07AA7D381722CA23F0D5575B17B7AEF8104DE85470486C7BDB3C5E9FD7D1BBA73BB80B7DD0E04461D0C9576F73E0C9024FC85770D695BA54CCDF6DAD7CFB4568B26AA722118F44F522E76BB0B1A5D4A5B629DF4FD381D8155C2859ED38FCD16682564DC0317A02BED908AE8B967F713B0D5E397EEAD568E4AD8215CF0232ED195258807E130988F330F5665A5F1BF5BA15AC688C2F8D33412221E5557550BC6FBDD3A02EA252A5A10ACBD0E5E53CE7DDFBB17530A7709ABF728EF20BA8832D5A786588C28C4D77C5E3B9C04D1D853B92E0CF5F987D687EDB3C6D6877FAFCB22FEDC6A6CC902E8CBE6BDDB46CEBE7AC80D7115D743EE747BEBEC98D4E1BB0F2DFE43316F9BDD226BABFCA2F7FC277D5BA2D0FEA9A8B2C004CE6076F47186FF0B2F1617D1B0E1B4545E856AD51AAD593CAB3B36D8B549DAFA1754B70354B19E6170A9C3A2213F8D6A53331B3E95D256CF100824453D9053198F57F31D8F530E533D5FE0596C87489D47D8D2951DABF68B8D8823EEF6C8C9D96F0C8768BF907ED1777610E7A0BE61513FAE0B13D1383EDD6667F251FDBE57EE6238FA699C85A83D390A777D619CEF44693AF57583F0341FB68FA599543FCB3D06C73A4F3CA3F943AF8E4E0C83A0D30F57DB675B07F0F8A1FD4BA7098E580CE26FCF1A8BABAB2B68FE0E949EB6CEE40B1CFF5BF04CD569A47F683710DDCF1FD27AE3D1E3B3ADC507B00DFAA9FEC178FA00E1EF77F0670B292E055B60C9FFBA5B6F7C38FD70F6CBEDE1416DB3D57CF4F8F8FFFEEFFFFB5F9B9BB5DA59A3B1DCC6FC3D9A79ADE12F7BB7DF2CF8BFDBD4CB25D27496F2399EC3A20589E023CDFC0A1623203C1BE8A934EE9ECA8D340110FF18FE6DCED72BE4E92E51227659C88DA8DAA71C2126CE903515A61378FF24A1AB21C80496AB32BE19056F787DFBDD24CC4631F750B815BC98C5692645ED4235687A0D5038C3765FDA68FB417F1472ACB9F99B03D530CC9AFB4ECFDED04DBA1591647E26A4A1329E79802668F6EC3C0F233D80FD26A1B3266E1203EA8CCD2D2ECEADCDB356D08B134A67C0F2880F8546C92E6BC5D3041333601A8C907F3E98E5B626D49CD129A6E62A4C8995E081F626D53B9E6503CBBB3BFA70A095A1D0599AD2ACCF671890E8CF736D58D999363656C020B251BE7FF5D2D05ACCE23B8BA769F83EBC16DB42767E24168C431068D81A84693F89E8EA3183717A6B793AEED06FE8DB989A743AEFF7C3145B7EE4F948A6D9C10252C9B36163172940ACACC839ED9075945A38A30E07ABDAE03537A757E9C4BBF94ECC357B08E15C853623D8AFD960FC7BAB5B6B0C103530481A8E31C9A71CAAA161924D2293F7439C4C58719A17A3CD00C8D9A615288CB267EF03B2953EF344AB48A90422EB44AFD13CD9EF6CEBE4D45304D3B7783689EEA8089EC5D90C71993D0D13F151905FE80093695A91F52653480F4CEE6FD54D02138358833EE0F229AE6BF0877D0D9A36A16BA5775D0B0CD11A04817F942E9337867B823FD6F82A2DDB3252F518B9C2F4AD7C6DFC30A10EEF4BD358CE31C38E5A9CD3E0A9F2882721A65AAAD7C499AB6D1C00B566CD3EA30671CC368A6C1BF085533C9037701948F19BEEB24BB68CC6E7D6C52ACBE638E754F00E8621A1E33544845ED69110B3F82D9097FC627D49F61CA12CC5818BD6587979C5DC47F915C78FB943A3D281FC9A5B34649B340362838AEB872F9986C2895AE84D7368796082C2941A53918282684F8DD4151B66F3F3F5447352D3DADE294E72A7907938A315710580C8F9351C3C6A8BA779408B6AE89CEE5A30F40ABF5AB158100B0518926010C52B571F442926101BF09577EB9514185A9FDC4B4D967F6E5AAD6A8BC47487524E76FF5A55790AC8EDC97C9C45B3B14E9A35F4E492B430C44E3A1533B1648E9C00A6449344104F3DF1634FDA7B2B6B850B07726862D3E566179819343079016DB1DA119E6EE2B6F0CF3FBEC04343303BC60F4C14B071A9F6165560209CB8B194A1CC82610CA4379305E08B08D781CD179571DF952FE764BF4A7BC58D3CD5F5C6244FD0382C39CC694DCB0CC369661D44236C043FD8D722A2FACF572FD18ECBA88B0B517C48535402DF6043E189CFFC793EF374238F00AD6379F4EDF4398461C3688AAECFA0449235A8D9C7F9365FA5D7937197387DFFFEADC89C6AD1270439A65D34513F89D3789819983CCD707B0011168A5F98F51277653B29D55C555EB2B78E4FD237281534A7221622043BB459179F5BC38444F2D227D755FC94AAA807CFA8154E19B925FC3A2075A455DBE8C242B1185EB44830BFE5E106CFBC5C80AA99B6781626E148EED9DBE50DBD12597F543FFDF9F1D956E371A31D5D3465E4948BD96C7530D47F6D85C869445E25B8952C578A5371BD828F96B39A7B5A41C02E6F7161AE69A0F83B1D27454DFCF943BAB580FF7DD356ED2BC8221CCCA2CC0D5C99D1449B90E65470AF76D1A9866280B5EB3F03FD06ED699C35DA17ACA9E53769CE3ACD59B7F18BC03DEB6CCDBA3037FDF36CA6CECDDC16B33C0AD2A778A9A880617E664600E465CFC340F3B40D961CFE0EC6B6F11D841FC38BE7D7B37AADFEE143BAF8B981CE5734097C31157ED3A835C4FC480E6CBA694509DA0A45170C06FF94A243FA01314EF99F791BAA64E913750A02776E69A5BE59CB008293A6585B90882066C255001918E4BA06A32F6008BAD1A8A10C5DA1054A28C7F5BFBAAE7AD77DF99E3B62F94265EF0A06AD89DC1CB94D5402C35C83A526436D15820D0713FA4D5B392853478C381806F5F34B60EB659466E1344C781B0A5ED637F1C21B7E266F1A6542D19A3A0B8F11094B045916F44784C346ACCBEB9BF1348FD5406754E390A63705AC462D34FD50EFCE1F94925B2F21D29DDC882740F2CDB8272266098173BC2693CBA80DBA11535E43B5FDFF03504B01021400140000000800DD90955349E13AB0964E0000E67C0100220000000000000001002000000000000000496D70726F76652057656273697465206F72204344204456442048544D4C2E746D70504B0506000000000100010050000000D64E00000000"

Str_lytebox_css = "504B0304140000000800E0909553DCE61E14620A0000B532000022000000496D70726F76652057656273697465206F72204344204456442048544D4C2E746D70BD5AD96E1B39167D7603F9074E1B8D7407965AA5C5B165608038B61063B20CD0C6CC63A3245152A14B554289E52541BEAC1FE693E617E672DF595203630549241679CEE5E5E1E5258BFFFDF33FA7E5FCCB036ECAFC197D43BB7A5F90A2AEA668553CE1E51522F56E8A0657A8C42BC2BE7CED15D5123F4DD1257CDE5EA1C762493653940D063F5DA10D2ED61B227F7D7FF5C38946EFCFCB7CF10770CCE1BF7553B7D5B2B7A8CBBA99A2D301FB782DD60D7E3EAA418397E1FAA3518C00573106DA26D08916471A64D9CD24405197119BCEE11360A89BBC5A473866B3EBEBF1056BF2EA0768F3292F2A6BD4F2F9BE2E5B828D01B306C81A3D0022F889F4F2B25843DB05AE086EA06551E19E1C49005816FB1D1836ED6D6BDA9C3DDE13308ED921ADC851B15D53ABEB6689C1D66CF784C09662894E57ECA3ADFE020636EFEB8A403BDCA06F27DAFE069739291EC0FE40EF1988E8CE7030D83D69C1899FDBBC5917003340794B6AED5A8B500B51983AD4A6BE679F20BB2B391B534AD587BC609F583BA158BFD9CD4D071D17AEDF7030B84E3494FAF5DB4D66179737513BA58CFD76D7493EADE64017B3C930CBB42EEEEB9D6A7886A0E0BA26A4DE1A4A41C0B1829F30C2FD8B09DEA27FE1669957F919FA80CB074C8A057CDDE7D5BEB7C74DB1EA54119F1496E0B3FE186FAF1065E9ED8BAF98525D420930D730435765FD38459B62B9C495AFB75DBE5C16D59A4D9B90A8D5F4CBC67A5EA1AAAE30E07FF79C001D8E71F658609E50D1FBEDB8C2432E3C3008BB7854DD0CCE2A05EDFA854C997E31D55DA032A8CA2FE59A396366B8F62B4BDC07D2984003618FEF0A6192D7445AE53E9062062D848545B5C506F284197FB7CDD79CE26ED5E45B731AB03117AE66D58C31E395BD3095F9614ACC390EA05C23DA3B21298B8624DE5C3A50B4B60353160D4C8A5B7859935B012A8B0628D9FB16DB9DB7E254168D53825F0E99A4B7C355160D57BCB9509C01E0C5AD2C18B724821DB73886398D5560C8D83AA5E3C050C27CAC735A8389CB4EA3AC5865CEFE1E03B3C438456D53FEFCBAE460BF3F6E0A02CE2856AF7F11CB3B08AFD7E01DCE898A388239101A1C34562186A6A2F8071AB23EE70F91BCC44B28139DD56E1A84BDFD779B4F617EB72DC969206D098DF3C6CC6375FED9E007A8071504F3F8C2CB634D8710D0C57E9737D07DEE1C704A259D62784305F77959D34C499906C13C876FF4B71A4DFE70449561C607F4B762BBAB1B925744E955D8CB076BBAA13D6492B3CB1F0A70BC930B8BC1DC41453E92BF93FEAE5A83D9941E8D063F39A369D2D158126063C55D64B4D2315C10790254B4B48B09EA1C43C46254B85750DE45C66A1D4347435A70C4A0B88B8C563A868BC6BF50CF68711717AD740C170F950136F1A08B8F57EB6464D3F533EC575E62BA366AF723E62B2B5013563C3E68C60A93BD196B97279C54414567C632FEC8B0485C67CA5AC55D6CD6943D84CC9EB36669179539670F617227AD5DDEC5664FDA43F89C596B1577B159B3F6103267DA5AC55D64D6B43D84CC9BB7CE832E4267DE4629D53AAB820364FB7A060FCFAD8DFC05FD159A747497356069D8C521D38EF21839B5A08D27397A5D14FD09073C0EF065B5F251A1B063C1AD572B1F7CD1367BBA7F58E255DE960E9BCAE925937724E6AEB469EB690DD77851965EBF8F375DEE27248D7B36E72CDC69BBA1826B362F4AE602C71BADF73186779C23422F09E87439AE023E67851DD9C5F11D50FB282D4DE7C0D24D2BBAE4DE625FEDAC2C9DAC1C6FBADAC32927B947A76E96D2E178A8E1F99D97A5739FE34D37F68F9229708CEB273DE90EF03A6E1754695742757837546AA596819788D094C788D082361EA1751E14759B86945EB350234E3312ACC37D26D95484964CB108AD12ABB4F56684362153B61F1FA119958CD0922612A1659A96B6DB88D0065ECAEAA323B4F48F88D08677C2115A677C9D2ED711DA42ED70FAB1115AC85344682DCD708416B24C446885E7AB3D1AA115EA5F305D4568E5A44884E60E4A456885E7F93D1EA115EA5F30DD88D092291EA1195147843650DD2E2423B4817D4437E491FC4D4E72C6C58FA6E94F20B1CE94CC577ABC441C3E8A63267E02F9DD385D1728B2DA9C15D2F71E13FA2644F457573562B6B048C56CE7283CD056854BD954844BFDA2967E422D8DB70DF2B7D1EE7C689D4ADB8CFA85842E31DA3AAF7AAD9EEAB716AAC06C998DDE5EDE06598D371BAAC0B4D77EF96BB434942ADB2AA5CAD68137679FF3074318FC3CD45EA44D61882239E48D3C3FD1D2F8DC6E0195EBBADD72540AC9DE8B91E7124F5141006D211BDCE0FD425573CF537895FB829458A2729BA1AE79A43DE88F84E6BCEAF447149F99F528329439B85AFBE67D59EFB93BD9372BB3391FFF5F321B46644C13491CCF6D16B4464772C351D50452A0B184836326330E0E296796428C24021C3095092813C58C336D0CAFD1CAC8C4222DDDD962D79BE185533A33B1720A43E524D57646163461666A45E390C6EC55A0F18586C3A6561A717852543C3767DFEE5F20396744D6F909274E1DA0408DCE13148AAA24AC406312E698490973487DD82010A3A70D14307DDC204C54E700DAC6D8418030327912C0DDA936E7CA9BB1DD397766727BCE0CD59B66696774D7CCCC4C6F9B29A4B59915A0A9DD2C854D48982B18823547842F2FA25F75E3CCA44DA8172A7489575E49B310A3D2A58069E58A1B6B165C4CB7142D295B759DCDB52E225A615E4AB3F2BE9BE3C18862B903538295D7E16C0B6372650626D5AA6FCB598809AD52CCEE689BB7226160DF5E44AD94C894AB204EE895D6E8122C43D58A95A051C932CCB46619A412AD448CA9960126652B4D94BA356C8C08571A9952AE70678B5D6F46B42B9C99122F3754A957D919932F3733A95F06690A58822614CC60D312FEF50DFAADDE6204E97E93CB141FD515221B8CF8E60ECD5BF8AFDAA37D0D59FCEB3D801044EA1AB18404BE89BA54B57DF4E657279136F21115D7A961E89B25FF73297FB60A80591F9F0926C58E01BE411BB22D51CEDF3F397D355EDB8AD6FD52B4F56E72702BD5AE95CEB9257CA79797E5FD91E158EC7E967801BE635752D43510850C8415BB7EE35C888392C04516282574C732A4FB15B6B3E635D50D40BA7BA6D714F9DD417E6B11365804FD78DFE079BBD860823EFDF6E3197AD7147919B9C168068B57F6459FD3D97836995D5FD13B91F13B5E27EA69AFC99745BB679706F9C54176A1D77F080F1EF1FC8F82849E019C7EFAD4DB6FF225BD9C4889E9CDCE11FC854D243ABD1CD33F5782A2BBE22175805B86E1B1B8F9B42A4A423B9E97BB4DFE73BDCB1705799E5E4E7EA10FFFF1E1FED3C72FA28C5EE39CD0D24FF557AFAC760BBC4314280BDCD7D4EA5132569A9B5CA9ED7A0E9F95751B75EA0B12798A14985C97A12DB55311F4F6EDC4B8B89AF587EA2AABBD3776B1B46AE99FFE39556E88A14FF7E1BB3BEBA2F740AF79BD211D2E8AD11B9D1B4BA338860ADC06932BE96848AB8BD1E53F18FBFCB669EA4610BAC110D3673C0ACAEA77D5AA8ED42EE0915D1966DC2E5279038FECCAFFCE9B0A5C14A9FFC89F1A4DE8A841B3F7ED9E9F58840283F89EB17F9DB440B4BFBB9D154FB1E64E1315C9A4DF1C4B4F67B3DBB7376F753A62848BD96C341A8D3D18EACF33649650A7B9B837C3DBDB591877787D3DA0940EAEF0A66FE06CF6EE5DC4C07737E260F07F504B01021400140000000800E0909553DCE61E14620A0000B5320000220000000000000001002000000000000000496D70726F76652057656273697465206F72204344204456442048544D4C2E746D70504B0506000000000100010050000000A20A00000000"

Str_dojopop_js = "504B0304140000000800E090955301B5AE549E8F0000C407030022000000496D70726F76652057656273697465206F72204344204456442048544D4C2E746D70AC3C6B73E3B6AE9F4F67FA1F18B5D3CA8D57CEC37939279BA6FB3867A7BBDDDE7DDC76C6493DB244DBCACA928E24E7D136BFEC7EB83FE9FE850B80944C49A4E46C8BD9D95814080220090220A9FFFB9FFF1D7CF7E517FF781627F769305FE4CCF67A6C6F6767F804FE3BE9B30F0BCE9EC7D7317B19AF22DFCD8338621761C8DE2172C6DEF18CA737DC7780C6C58D1B84EE34E4EC2670D985E7FA7C1978EC65CA397B1D783CCA387B7AC6F69C5DF6F61DCB81F032F68359C07DF6C3FBE72C14284829E37CC416799E8C06031F1ACFE338FC14E44E9CCE07128DCDE294F93C8726B32FBFF86EF0E51724C787459031F8E7322F5E264108B46F789A21D7F18C04E9B3E92A0873593F09E3FB258F72E6463E8B622A06323EBFE1619CE01B877D88D99C2306E37E900B0105CD3E4B42EE66287016E423A8F83CBE8DC2D8F5D9F4BE10E0F6F6D6F1629FCFDC2873229E03D63FF4B27DF905BC23BE626F856D0B75236B4104E54BF10CFF809F3C88E6A4C42C5EA51EAA0D9560CF56918758768FFDF1E5170CE0C64DD964979DB1681586A7A22C9831DB86C23FFF64767E9F70D08D7FFD2C8E66C19C6D9D310BBA9ACF8288FB16FBE69BF295937971C2DFB849AF87C5B6A0852069DC06911FDFD628F44A4E4A6EF6801BCBEAAF4B1126FBDAD2A1B6F4004AFF78A8971E52E9E9BA94E41672368450D050E736721600FACE29FCF927D472421ECDF3053C6E6F57644020398E89FA38B83AAD31B2C7B6816BC4B1D836E08D77AEE0AF25D82BCA768BB20ACE293C55A911C502DD9910FF3FB94B0E35BFAD90FAF6D4AA33B28F8CD82016C8C5CE41916CC4ACBED52B5AACE30F5BF1771BF807632273858AD0BD3F1C53B17C5F69EF61FD93DFB8A18D4A63164E0929E3453ACFA0DE98641CE2CBAB53ABA75050707F4E61B4DDC91A93FD362454F87A9A10F17D24DEFBC3D2577BBF9AC96A0F3D7BCD4CCF800E430B793830BE7DC76F10E150223C68E62C02CE5139AF72B06A630BEDCACB20E5D3D51C86721687DCBAC28EB28AFA5663949A2BDAAA221F180FC18A692A83E5A20AC070E511265465A221E070F722EA3137836521B7FACCF260D9A01F3E364F3F8254FEB95B86F5898D60F1348D09679EC6ABA4FCF122F2F1379A42FC9BA4F10C0CBC96827C276BE4C192177F8BA2D4F5A8ECD64D232D89309E5BD5E2FAE02E0D86A67A1ED5906F17C00F18DD1C15E44563B02957BD467F2160BF6F493D8FF3E84A8B8460183775204BE5610746386CEB264285A2D5898713D6261DC0D25394F7C0226CD62602B6EB02998B3475EF1D3749C27B1B4C3673D3392D6E59AF851304D75945D92298E536B00F9C8FACAE1A05FFC4F895ED3AD77180531CD6A0969A0F60E354B1EAE3BAC4EBD93A320FD522E5F1419DC3680368B62A2BA376C609449D76D7A67F240CA56EE0AAA66ED45C39EB2868325BD184F56B45019B366AAEC695F760F310A5A62AFD6A8003C7070DA0840A86AACBE03AC83753A6C0ECD626E2591BB157EBD3BBCDF81098DD7C20DEE67C6CF9CA5AD968D9AF2DA43EB9BF246A5FF06E588F7D671EC6533794565F5DC97005402FB1214A903D470B0F53C985B5A43616C8F85FE410383C8BB33C93484ADB867ED6FBA40D414BFF6D3243735554D39AA84282F1648646AEC0C5C7DAE45667B2A2015CCBC3D87369512CA8C9128502B293D24A6F7D4DA37FF7F078E7887D6D39E0C67B0B7B70E96F0F1ADE4C11AC34D4BB74AFE31488D414BB0C222CDEAF1527D844137B16BA73CD4C0636036C75440C9FB36DF883DEE888FDE4FE54C3CDE3F7790AA1C7A86325B80DF285ED17F218178B94E7AB3412D2917B8BFE1509553CE9EB21909080865291274DCE59214C5BCDAAEF56408B21D70FCFB7098F2EAEDDBBAEE159E0398BD5D449F93CC8729EBE0EA6A99BDEDB8A6F883640E78AE8A345F05E4AFD3A45B7D89595AE665427BBBBAC162089D697C15D8063AEECD2787ADD07F47DF34CBBC389A6C340401D4163E33BF44FCF58A91A741B65F916464EFBF0CB383480072220F11ED56108C884EF04D9AB1718AC9A58455912D148A9444D534AAF27559F1B8927280EF05B528042BD5089107C57C5A4423DBA7519150DB17517B33F2E237C3B8EDC3CB8E10CB30B5797D1C3656435C9B4E977CD45A702DA752DA7319054475F7D9C9986D95183475ADBE0AD967928AF0F63841A4B95987EB7CF70312B5DCF75680F917EA88FF0117C393704A7657588F8EB9EE067296432E7F9CF699CA83A99ECBAA89329FEE769D30E427E784B690DB9549FB648BFD367C92955C3AC8D18ED2EC960141C3B406601A00EB930A52F374ECC933629024515BB7B382108B180BD80F406EB105A8004972150CA74FD8C7DCF46FAF64B53D3F0F83FAB83329EBF9D5E732FAFF4D01E2874B2B78BFFEDE913437B98CB023C274BC220B76121EB690C3BF5C4DEBE93C489AD7B2F34E297C3045ADEEFB33C5D71D1F4A949246154CE995D6A0CD8ED81224BF5B4093DD70B7D888D1EE17FC70DA165D315560F55E1D755DB5AE677B03466D5664FFA4C6708648B5BE00197FC0A6CE17F52A596B6C616269D3081A23636354B26A69983B540B395675171C4CADFA6761D9F2729F7DC9C537C03F2263C0D28D31BAA8C2841A812741AE27D43B8E40B736BFBFDBA4813CC0771FF4DECAF429E6922B74910BD0C31BFFF0C9337A3468263B270B3775CE49D75D5974459C497D440736823B3DA1708517B848B009A5E218EA359F17481A81F2FBA9B5B74B6E60C5679100E1075B376734EE14E7BCB84D4D5B640D2B45A2D3274C6BFDDAC480928C3DD37BA44CBB521AFF6A6C6969753D15E2663207A85E647FE7488FD862DAE330953F88DD24C85C9D9DFC22439700A6AA9106AA1333E416966529ACD96335913AA75092FA6E3C734848132BEAABF4D20607E0D18FAC05A544EB5355751CB4B7CF5539C07B37B11CCD5E2F1669A1D2BFCECE68B8AC1DCC745707FAFCFBCA6E5C41E5AA5E87FD888E8780B37BDC8ED9D1EF9CF038B82012897E1F06F97B7DBA301F4C4795397B40D41BD3775330E9AA2FD88FDDD9A66F3F45ED78FC5F80446C1728B4180D27C4C031B1814CC8FAA2F2E22FFD9827B9FEC263904AA56085EEF5FE651606A73EDA892394A8792DC76636A204886A94FEAC4953ED276D147D278D943A57C354ED6D3613DFAC680ACF7EC2443E87998F94120E767FFA89C9630AF3FF0BB5CB081D5EBE292A30F35DA9AEDD003825614E4A2C9711DD54956D90219D4B1A6D11C8210D1929B47478DDD2004FD9ECABAB6E225CB7DA98296F246245F1B948BD0F64DFCBB913FDC80BC4C2FA3C1E07BB945FCF1DDEB33E41864DDA4177173D32FDC241BFB6873057953A870DC9819D547FDA8320EEB624A3686F764DF351AA098D03503C8602B085F6F22FECA34B7662E9D45409A186ECB6E30E5A82C4A9F31AA3B22E4E612AAD525ACC1204119B1551CBD31E8A912B636342DD06B8EA869F6948B47DB342B162F3D0EADE16128621CB95699676B4A39EC7A30A924A468EBFE0E027AA05906F87786001770C677578D0D1DA35D51C5D58D273125D702E3B109A7EA4897E1F49A3F53D2C173C3F035F5461B878D0E942B7E7B1756B45EFA08B556E4766507A7F49EA2D7E6D698894F67124779AC72E8A629856B10BA3513C5B44068CA11A0A2B0DEB5580FC16C7E91A281200219BF21C6EF45C26F1691C792516ACCEAC944C42CBA3225211066F50DE0024AA637DB4905561C1C0D3A190B78D0BDD82C9B4DC3C6F5FDB7919CA6B5DCDCF0A0C19DEC417B3D6765EF21F25F98155B7E6DA6FD7D93834264CF65CA7E4D29B38246DC7AAE46E2127B8C082C88B2DC8D3C1C1CB4BB8D276568839B8ECB207F56EF0A226F0DFB405E69B1BEAF248393EC75F734AEA9B6C5816A3771924EB54F9EB29DD6550D4F4DC0A2063622631944C42126ED6644604BBB4BBF0927E6AE6DFA046BC44E25C9599C812B1A2C79BC121BC731658C2808115B30725CAC32FEEBF378E9823CBA1C3E7A5D6F139EBAE6B31B442DC82E5EBD334EEC352F1B5A016579D69E414078E843A7E90C81D1122228ACD476A26803AE6CD33251AF75A9B131DFC47F6B48532606DEDF2FA77158CD0D0E9B6183B0DE742E6F78A424206B6D56D2E380AFEC073CA503804F9E68FB43907765A50CCFA2DA3B7D16F4E44993664B0874DA92B2E9BB747072CB9088181A461502B4875BB26794841287D034E7F710DAFB5B483055233435F3424C180618EDEA4155DCC11A36ADA40AA49DA4540FAE0D0D075A8569CADD4FA671DD3DE8AA8F45E66578DC6A42440277122F835C76C5C42BE28B9A83574EBF575150CD8A0F9B5B3450D661BC9092503A13695B27E5FF590529AF92F6516DCDE802CAD6BD679201732B439DBF3D19CE2A118E121E0CFDFA70123DAE4FC0955A6EE4B7348D1EEC34079C9CD12868317D0674D0D472AE334BC7FA016E5FDB5BA4947368D987D55639D4ACE2D6E2384C5CD9C0451F89687310226CDAD2291C215FA4F12D8BF82D7B21023A58274371621CE9CB83B8C0D1B67E105BDF9EB2D0CD720883F0BCBB4007ADE0A9DD86CDD0ACD0C898623A824C2E52FAF0FF317DACB4A0EF688486F819755EA7D808D6B778201F35559C027067394FCB58F8DBD6431E4625216C6807D411DA988D491ADF047E75EA1D34CF0A40195AFD837DDD194AD952E912AFF57DB04F878CD43DAA03B987D76B351249E8E678E4FF9DC6321C0CF5EBDEC101B138045F66B98C2334028D7859201E12E2013A3D9E8B3C0DC7C03B6E475C91E980670B6F2CACC2DCBA12748C4BA8127803E1CEC05B30402BF4C1A1FE5C07999D83633A6C0C9AF27268EA4C1E24350E515FB5ABF2B8295AD083461A0AA17D91ACD0B24D248C83AFD199D2BCBF9A55BBF104D96B2EA442FC133A3A4303C5AC465CC71B5D8C503DFD20CE39684E3F18FA0801888B38B5EDD40382667DF60B89D57E6866D0BA3576819682D4E6AF95D8C41527AAA41F53DFA338A0D69B5AF4EBBB46305B7D3A5DD014486CD421295D4FD0061D345113AF6D7A4B615EE3A9C1E07771AFA7C2F40C983EC4F5EA10B7580E9BE70C4A85D8E2CE44B07B1C358CA44FC5CE44D35CD135CE0222481EDD180E66D7C3E8986C11AE04EFF8FCC55D52DB20B17EB3EDF16FA3C1F95757DBBD51EFDC1E0CE0191FBFEBC1D3F837FA655F5EE26F59F895EDE0DFAF95CDCD5EADD5A0BB55A07779391EC966C7BF7D0FBFBE875F5048AFAEE019FEFFB3C08326ED913DDE7972022FCCAD0B8FED635ADF9FAF32803C62071ABC9109460CA57A3508629F6C3C71F12E8DC9D02A5379E276CE61B1A6D3311FD31407FB9A07D1A61B9A24C8E189EC079F94625303B424EA4C83A8E256AB80ACF2AA93315882669C84E631DEFD128E191465E0DB2E79F9E8AEF2459C06F9BDF1B41DA1FD67C553F3B25134374BDD395D0484E8C69C1C440081D6D8788F675D59230E824699084299404EA7FFD6F549F46DA9910E764BC55163F2C1C02A4249BD54706B0308D5EE10ED94CF2D4D21A81DAE6C126FD1267167CB0862984D65BB44275B4D45BED6261BEA76132940D4475FFD55E4F3BBB7B3222C81D87D7B333285341D822308D63D627D5AE42B069D175D104ABB702D1CB06BB40B875E6918AE5B16F73A883EF0C6D7E24299B399DE0BC0DAD75871DD3C7B82FA7A040D848283F64B4A75689F2A2640566586E2BACF1A3161175C3F79F2881A06035087C74B2234FF5426D04527EC1ACD611BA0EE7744EF5BBD475350C78E43069B4AD893C79141D8A5B3E148E6D1E3A71C87B63A101F470361D79C866B83BF38A410A4D650098F9C05088F1F3F05A8AC63F37DD6385DBA0940DD33B6F7C88A1B4E0E840D513740DB0065ED84907ACA0C5587782D940DAFBA139C08D24534C6CBDDDE00501011DD1AB76FBA55A961A068A5DB2B281BB20603AB5F750E366CACC22BF6429BABD8EEE1ADB93997CC08FCCD18A9FB871B34F3956CA6ACD2DD52ED915277A2C391AC187A8D7EC2B53F656725B63C4907115A1D93304A27301DEF514EC74EF1BB01F2927FA4ADA3FA74E9785854DBEFA826A74D3A3EA80F577A4DFAA7F74705C5C30E8A8AC39D8E4F8A5AC7E65AB4F35715C1E8D9974A2C71A52A83A62A1184C2339E1237FBC48D6EBB5FEA22CB6EE3D4573468C4C5509CF00E090FF563241BA7AA325AB6569BFB0F108561DA338F716B54BD03640E708BB35A72A89DB6901749955AC43C399CF5612C87DAC8398CD101F6757B0387B39ED1F2529C0275F57D2A18D604E49AEC3A10697AFC305CA8BCDD9F45DEB72954696F861CFD23FCF009120D8A869AD6B7E0A71E09D1DD1DA270C69ED0174DF0E169855C933D9444EFCD144A97276A21C0819276190A9DAE6379A822BA553320949B0BCA36BCFE13312A8372FFFC8734BE1553AC76724C8CE1487C00C59A0A3455FB2D7BEA74108435EE4A2088AD7BF1DD1D3AA7227F63EAFE45C82973F3C3FD07778E7BE3E694ECD190C8B7D4B5ADCC4B832437674C8E308F4FD73DED4BE7CEEF9D5F3AD7997DF9CB9F5FF70681A692F6F33547C3CE1451D1609652007A341C0757C8F2450E0661BACA91D5D4337A3C34FF00A1D5596EC93121185C22E46A093C0175698A41296D7C2C5B99204ECBA33FE519F2961A08F50A929F4A6A6129E65E9B53D8E210A298DE6C6E527E7137BDD5E744D98046A7346264612E8EAE2959F61F74B0149BC7BBD30FBD4ECFB676F7F7A8FD084001CAE11A799DF7C8D56FFBA8F0782F1AE16F3D46E02BFD5E1F0AB536CAF4AF7B13CCDD3C4E35EFFD15E541C96FB8988345D09D0E736F08C74D92FF965F186B22E58893B869C65F86B19BDB5049B786407BEB65868E2C81997D7A6638D8559E6B427B7BD3BE0C34A85FF8F1945FBC7AD7D500A0304C6177A83DC87E5CE44B543BCAB66EE6C73842CF314ECB76CE51192330794D12BFF0E98F745643D514302D536CE2352C8EE002F760316D32ACBB2A59107FB648635A7EF4C4C5EBCF214E93F4180F4BBCC12CE4D2BDABAA40B08DF729D5E2267DEBBD3B73D300111BA7B628A23996472EC55A2B1836F69B20D6187585B872A84A7935D34F9ADF9210F82E754A645389AD6D76040ECB3FCFF4B378B87BE2E82FF2235498D5E521DA677C6360FF8B7B9F6239DAE411D56270164FA2478CAA7B13FF1E84A138794A4F9BCEAF96DB1DF8EEE54BE3E8C32F7DCDE23BD11D7445BC7CA7D79AF50646E22CE0A1AFAB63BD5F00C13CFE14E35B3D0531CC8DA35A275FE121B9E15A97E260A549E4572F8C23F0CD7B78594E37231F65E3821AF4EA71C5D32B7E400CC2D1436D9E7D6EF0A3ADFB79034F4C45F1B50AE125D3476568AF96A2352F0EE94C009DBB1DE9D3A3EA51D680BF8C538F5F78F891885F7F5D687C69044DA0E22D55D1F04B9AAE4E30D4C27FAD82F4131ECBC43AC0DB0FAEF7E91955A0B3B5B2546021094B7CB48004FD6793FFC34613EB4FED28A2C9423ABC2B689DCBA5F5B51BCD57EE9CEBCEE64710E489B73D887A5FC7B73C7D06EB79E3442A0437BFBE79FDEF0F1F7E9EFCFCEEEDBF5E3D7FCFF0A3766FB2BB65B8E7C857F8F1B8378197C6593CCBD7851A5B5CADE70C9D9D8E0FCB41FB778BF42DDDFE6F3F1F2CD68BBD3EFCB7AF1975C2F096030BD4B5D53A408CE3DD705BAA006081893D5E1432CF133CB5C4B3DC7C5659BD3CD5ED9921885DC9E3E64188027451D0FE29DBDE0E5AFD54A1C203B2D0F56E6F7ED953850EA520AC1523955C1C023B364633081D77CB54808E4797BE8D98F9957005CC2A2D403F2140882E37BECD214730F0F6378D88C6A94529041D46748BAF158FE4F757F737C8D32214C70A8FEB0EC643ED196F5564CFA5157D5BB9B738393E6C99CF783D14309C2C77F35586D3B6EEE12214870E111F3FABBC432E0A3EC1B8DFD9A19590689DC1E350EB86224894DDBDBD7DB2A75B5880B926DDE263EE49B92821894756F4C8F91C35BFD158D7A7500E9E1CAC2D8FBA239902F98475266330A2D3A6D627C7E8B6D94884F47A52A4029F367D6ABFBCEAACF6B2B89D7AAC4F908826E866241DD415165F6B31E5407785B32233B8C6512FEFDC5396AE4006298E315117F47ACAA7C2361BEFC263924B86E77A0BFEC32A6BDD07A18468BD436AEF51396B47FBDCEAC9BCE6398307BC45F58DD57ADE42CAA061CC497912BA1EB70797BF6C0FE686CF6A14A03F84A45103F49513273C82A8E0C507AB2F3E01401705B45B04E6B50109653CF26DCC4DB7E6D66A06043AD16FDF99C631C553F4F3A4C1FB18D1E7CAF3589C52EFB8765C80C584E51909C3E84B43D4B66241AB85B93A53AA74D4487996C451C6E5C4C17A6A514B6D61DA81860147B782742FAA623D6C4F689A37160A302C6A92E5CD465BB9C8B46A446B216F4B03A97B7BB25359874E7661102766037542A7DE6FC7804871A1EE13452A14A85D8E2BC22C91675027B71B7C151858D914BDCE986661160AFA58DC7E669A9D75DFA920B55F3444A0A47571B1BAD68086CBCDAE5823B45DB346A80797DA7E3F20AFB82E225D6CFD45E1559552DCEA3DD17F9C43B9065C93B5B80E7CD2F862048258CC4ECCB1B560B59E255CBFDDB1AD3812F7D6E91398D55EFA6CFD1C9BF563D48C2959516A66D5D089F6769DD449F3BB6A0508F63A7432E51002F1B56670F15F7D9E5A6A9FBA167E4410053926974813BA1B7213DD1539CDC1FB0635C3B7212627B82F45077EB983FB87E01D881FD5F01DDD0512BA4603D5BABEF48057863977B0DD004FC18BCF91DAD888EEF39B961F2F71F30AEA0A15FE3F7BDFE2DC368EE4FDAFD0BAC7CA635BB1FC8C3DF1A43279DCE63699E426997D94E27551226573228B1A898EEDDD99FBDB3FFC1A000992680094B37B77555FD76EC636F168341A8DEE46A321C3DAA8B4EACEBE19875C75766265A507C6D2BBF80CDF23EEEB2E292F3B2869C561324BE3E56B81FC12673D92E0555D1B3324E92C2DD2A859D43D8CD26F65B9D2CFBBA7EA97DC43EF0357BE0C7D831F7743E4ADFC565F75176392BCFC227E78835B22F3D4EEE5305C70EAE8E0BBE870EF90BC55F2CFF278A4FAFDD52B985DFBAC61A59B83D3572BEE0AF594D432F1E1457EFD5CF2D81BB5C7B84C25796B8C9311EC78FBBD17EFDED6BAD1D2A15CB00E2599D3522D4A8B32CBDAFD9B12A9EAD3DA34EF19E52ED47F955E9DD9421A8CF1048CB16970029D0838E6A5BEA4C4FA5EA545B938FD7A1200683C9272E857F863B1581F0D9013B0E2F3651A27F71F84DEED60120D75A2B07E3A00E7A3D98E864119018CE55C5FCDA563D2BA7C83D73AA0A4C1ED32C3C9F993D56409E3A5972DE8DA694A410E679F7A8F1E9D7EEA45EC8D53B18B121561BDA493AB787E998A4AD954869255043E3BFB9D9E85DF6DFE9D6D4E52B99E51C124FA6F9F7ADF119A4F1E498419ACC428BEF3DD12662CCE92320898592D845DBCC252E9F7BE7009277B62F73AA560C178B573AD3DDC3B62BCA75FAE675673B93A2A10242AD20FC5FD2CFD7095A6628CE8EC47DCA2EC7DF9F4E9F41BB6D3717A157FC9F2E5E9CD72D6FF1775F7F45FFEF8F6CDE6B7A2FD6C254CFAFBD36C3ECBE6E9CE78964F3EDB525DB756B5DDCBAC7EE41EDE213D7E11D54E1C46BDEBF276E1AA679A0AE0D5EBB605553D49709262ABB614015017ED0B8C422B49B729EBE449EA4A35AD47520FB5AAF9F8E5B30CB5CE55A7E6EDC18BA97C1F68A0FE5B4EF36FF6661B0F3AB49B6FA753B1077235D080374EE715920943961777498DE942AB25B57130356BB7268DB14AE96326BA1D995DE11CA977DE1EB5A70243037505BDDFAAD0423E5BB563352DA7CF6536B8E6955F282299BCE376230F5E755C1EBDA7D2E64F9DF50ABB9D2862243E92889818B62241C59E4DD9918290CD28EAAE5FEF44D6177D9B5846BD187FEE79FA7EA5FA8433D41D1178110F3D38EA92B06C4A542C82B03E96A2F152408B861AC5D60AFFD64A22CD0232C2E1A9176330729D70152E9211386DB33792F991A21FF224854675CEDFC67164E904389C5BF11098B784F629BE98736B3146853ADE4A51EEE4AD8DDA3B148AD3709A4E0BA1C161967560E48B32799B3A356C0203977A23210BE54DF639F50C8822C9226B006B8DF76C23962138D26F8EA6F59F4AA42D1CA48A89F283429E98C8D6F56F0D43DC4A3AA4B1E8C917239326DD44EF307D5374A0BC603E4ACDB2741E3CED4690933937D60B6E8F3EFDFDD3EA9B4FE6AB1A9FCEF197DF94A65DD1CE89637A270C909ABBE82246AA87B8ED2EFA3A8F54D0AE21B3BD8B9EAAD0FE755EAC100DB8C6767195098D4A3D28658C0F3916E2B6AB07435B2CCBE88D8B2297B35FE265B968461279BCABEB942C8BF6ED2CEF77CB5E8C873C0E368D1695907602883C8D30C07295CB9C4B9B2381CF39C92A9BD4D3988101A7DA6F2D1B8129B10DAA94D957C643E7D9676B12680E6AF41FEF0BFA8FDB6961EA1EB0F2FCD27E646EEE32D53CEB3C1139DE0E63696631DB376C0801C4DF89B2B68815F1D7C89A4681F70B68F610BD31DDEDCBEE1A3368E95DA1BD3F128DF16913E4414E5FE97744A8D3888CBCD1A75E8F26C2E14FE97D127A20122261DFE953B533554D4CA2F8BA69B16C00E7E53DB000AB1B10B43A8C827AE09A5D814F39E1205E3B0910A075DA625DA3202B927689B9F73D1D56A273D00113E7828173F35218A6A50C30FEE0D00DF597E8E3DBF7B603AF2681A58B7F6C3F2F116D5492393A6BBC3CA381944C323E717E4FFD327CCAF503307704D19A44AA13D3885A2E02D735329F7A3D3E318595A2121E381A3BEF6E89214ED4646B5129DF12ADEEAE510646991FD74E09DD1905D18445988C2D273D63A4E399D87DDAA814D3A1BB2821F1B590BA962E4BB427A37A286B96E8C29B350B60A63BC6C3699D26346E1D95B74E45CDDDB1DA7D29B6D2248773CA506020F4B96BCAD03746863E31FD9B6A21D3D6C70D8EDB5964133CF749133A5EE2FCA4B6294EEC69D2E45C8D207F9B1365EE8024D71B9BDF52F3615D93688FA81A8D5B559CCCF2794DE56F1FE7D09E643FE551E8360D01870B9DD0CDEDFB2468439471B2AF115C99975CEB8AB1543C5B0DB79F4319EDC6BD2DDEB5D0A8661772830C27593E980B03E02384B5D0E114EE30879DED56C5FAB6E72E6CFD980E811770DE3BDAC7A680327D7AA50BC709FDB6506BF0B4DA4B72339D5E6B57A1F9CDE8E9356BFF446159604986DB12799FF0EAA12BC114153A8B9A73EF9F7ABB0E6172416B29092D1051EB521B34AF37E3EF86041324E0EC45F1898AD7D3B79AFA8AA7721979F6D74F2B61383EDA467899118F863FFEABFCAB6528E1EEC7249DCCE265DAC90359D689C29D90BA4E4BDCAA0F75718B1D7D32C13FED431AF25B2435EB569E7C5BB6838B4933A56C4B84897E18657F4256DBA47993597EA36BAE93E940BE2A1EB03845616B37848C58332F635C4D9D08EDA0A4C335D241730B82E6D67D57555917829C38183A8DE4A399FF8263A280C03D6558B077392D2216204993249566DCA7A9BCB6AE550FE1488B4AF62C0D362B0A4EA11921BBB8A55E8B36942FA50F966A7CA529D09F93BDD62B775446B269F27C16AF56428D102C6A638B4A2EA24C620ACAC6405B03102856A2A696AF14DF1AA54DF562552584A58593D4FC202DE9A6DEF233D65EFB593F4D69F3F5B4048E81C46E87639EC63035504C2AC886EFC8CE28D7AAFC4160F9443B2B35DA167E92FCF258F1CB75FC397D6EDBA2A8B98A16A28675CE01AB9B45BA9CC8491F2FB8A1A019B1BEB8EF92B74E0929F973C0520090E048F85B8A02F39A25583749FBE345C00609A8AF00410D603AC997747248F3C312A8CEF390180C1116CB34BEA64B1228144880DA005BABE2B1B7466DD982DFC60BC56EF52F8C34EC5D4058F6AFAD952C9D6B7F430BB3D64B7D9A258CF575C22E2D8487DB32BD54AA16571B606C79A5E31A0FD1A012A95CF06CEFBA942FC0742EB458A84519B31FA8426A72609F856F1C1E96947E4E8CD14756BDE4031D437E8796BC5151329EDBD5DBF25F35D1C392B23EE159F55063093E7E1C6C413A4832E1D51F0D74A97250893247513A075B812556E67273D4B8A6C64904BA4A51C3D768F83AB0E1580ECF5122E316067D84C37AB4EBE66A8AC992AB0165075A4831996E4C007AD3B9E98E8862B2676C495835304A13F367C28E909B1832ADC2D1856267F41C384CE8F46B52C8D69CDDEA426597DD7BBB96DD5D07F577FD153AEC675983C4E6A6E6267396D5BAC792ED8E000919A34B734FAF21663D6CD4D0A725A6527AAD0A991AC88D7D8378DDB0B73D527C31CDE6C95BA90E55722CE543F4B51C6B92C0B1EA17422961B0541721DCD76E160D69E858AE866C739422A6A5A4B52945F98A5F0C478CF8E320989D006A6F6A7ACD4D607809209121315B4D069D986330E61F193FB706CC5A30B2DC84001CC862E617406E6192E86BB0605A5CE535F52AC5B9791AE31F61245DC52B274B824750D081BAE042B1FB30B826B973D961D80123067461413DCB5269A9E8508DDE3D99D79230FFE85997DB1A683012884905B42F3AA67CBB53B990E2702CD65C288162E0372D54ACB614401F4B620418C9A23E03D2C44CC79BEE5CC8FC9C41E0615A2CDDDBF83F9B5FA5085DAE71FF144F3F4C91DD61CA5B9374A411F1CF0B68307DE4EAC89C142DE784898EB1A6A64D4F46BDCC1E95E16E27C93243D98EBEEF22AC9270810120BD724A6E0A1E9D52BF2E3B72ED48960DCCEBCF004CE730B01D6446AB2331647290D311E642FE0ABDC0AD18917B6522ED3169BD56BCAE83476A0CE75E6CC442136246DB718409D235698F523641F92709912073DC84DE69C5E9D1358D20FAD4A36BC68243421AF8D48BAEB315E5047426ACF3C890F6C25594C269397BAB1BC0344C0ABFDC1569AE5DABD0F1FA2C4051F87AD18DBE0FA22DE88AAC18D3FC669E74F51E6BBBBC69B8D8645FFD4FC6AFA52729FC18442CDC398232BB1C839475A2F063105DA7750C723153978DA2D6AB419769F1225B2DC0A7E9D7736C90B007FF3602215C2A4F1474E8A26126DD0EE5C85C6E87828A16A2F594BBABAF0F95C9386C187DBE1BDFA83B9B71FBD96C266F6DEB23F919DB8E71762D946A51CFEB5C50279DF1C2AFCE88E690B8B3D3C000DD7C0ACC3138D568FCADA95DC4494DA718EEE24194E1EE90FEB50702A2107651FCC71B3357464A8AD223346C137D52ECA1B18DA9C15B4E3E2F4F0ECAF283DAA2622FAD258A25457D56D3379088989007407D6040C82FD3007A411BDDA874F6A0B967C696E975FE25AD4FDA214DD711FD6B8FFBD2F340A5DBC1AAA23237312A48D5A0082E3A8B7E98477001EABAB0590B7D58F3953B647E53A02A491BB502B086BB31FD3BA67F27F4AFFD94B9A60B5B84572C639747E7362D3C6AE70040792384A5AE3C23ED1CE2384FA378946D6D9D6FABFF36A79810830A2C3EE329A12699D84E86D6DB05F8F353D59535D11D0E7418544A6948B1E6A131E61582717028B95CBC6A4A9B12927D64AE56CBC208C37DFAF780FE6DBBA8F4C8EA92C332D708A09ED15548A361AA45915F7DA38FE670D5F84646C5ABEDA8164DD60E41CD56963189CAEDA40F747E283EC86538A4779F6B9739AC33A44E11CB6EEA3E42F463599A6A19AB5EF8596D4F907D3C9A22B45887B45887961792C51F0752CA356BB8B9A2C817D904ABF7EFAD6FC8203B5966E3B441DE84DA4DE9DF762C879E4959B0B1DB8037CC7EA98DA4C6246D8A1A9D6D3A19E266CEA0BCD70E33951C61F950B65661ADE8DA447C6F574CB0FAA19DA5D735D58B9BB168FCAA81E450AD62DBFA9B96EB4FF63F42F92677D1CE631DD0B4252B98906F07D28A37DF4BDC494137B13FD0F958867BED447CE44AAC3DD5CAD35D1147B5C907B1DA25485FF6FFB48673BFC44CD8ED532437A97D6D2342E545490BB785DB522F70495E989A9D8CA9AA52146E4D95955AE694FED298ACB684946E9B2B79ABB8A5BCD1D78CF2A890953F4FEF8AD7ED3C23F471AA32D0EC34BD57F24426BE59D1E7A652405F97E9EA6656903221375C5B48B14415A70AC2F0A2000831205B995526B6E26276FF5C95252A34EE54B6D85C1DB5D7A8D70E0C92043875C5E903C0F720A8CD91176CA1EA40D5AD2D4B2B2D5B65B3BFD9D89A25A97C063350B5277F2B4FE6D4CC626A5964AB633C3D414E7B4FA6D6AB57A0FAACBFC4FB201B3BF59614401A7EEB364880346A81BF71C6453902FD162E99F029D89C4FB76796BD5EE17A7AAF5CCCE5A87A9ECA4012280AB507C901759E4A2F8200748AAC933299AB59DD99DB04E0F01402E4A4574964454FBE16D13D96E44719DFD593CCE21B3E6AC9923F9260113505D91D951C8813738806C7F1E43368DAC1A1E77F79B6C17ABBF228C81489D0580D46032D785C4BC1E566C546FB8A547C8669CBC81AC2A719E7231A07BD0CD923FE62C5A9B675F451ACBDAEC4AE3EC4DB1436046B63A91A3B67A75CBBAB97ED64E5ED70A5ABB43608EB081A1264C32B2637EC92CA33658DFCCBF18C52E844E4854C36BAFA9983F74913E48664DB8CDC74048E5DD841D2DDCA8FF2BB622F6AC533876AE57E85AEA5E0B732A8630B5FD5249E05618065923A0F549858DFE7C595315004434FC6CC0909450A0FF7F7B47D61BBA3E5F0BDEABB8DC052F4FC5CCDF0AA8F36B7A9E500849FB719C38934DBAB7D08F639312E94F9317CD9629FF510945A6D0B4D3B864DFA07E059F6D4C0341DF3BC4E5ABFF4448D6459F6C91943BEB1CF1295EDDA852B8077EFA2A24F1AA3599F30566C7D522A9718A30513552ED6E5686C4C39B9886B1B0DAADAFCB328BE4A67D3880D00A67375BCAFCE643D56C1165847B52CE99562A02D29CC033B11D551826846DDD161B106C86305E71E3459FBFD39CC99D709605658CA23074E5E6A20D694C96650C3F112A20DE4BC2ED9033780433154ECE3D459DC0858151A0D185BA3E59A6DEA1D1E719977D76B02B8D7B9EFB095245F063DE64EAAAF51A9D47DFD5501B2AA218E82460690A363E553133CF64CD3066F82B15CAD36BC06EE00D3B154B51FCB9740AE09E00779C9FF81C6B6FFC196B0AE005572C1A5DB6B0050CBCE1522050831B3C30F8E39054D1B2E40CAD2517BCF60CD125A1293714BCE3B75CB8152FA50D1D2E6578D10F97995CF3B79346585B6FF85F5665285962773BACCAFFF7395D7F254A1648B2E4A93504F72C2778162B8F9597F8FB37D1692AE26F122FDD04A07E8B8A2DCEFC978A0DA55E5FEA8F7E9D3F9E6A34B249FF9F4AF433CBB817020E3E2727B921E8D3E4DCF5595A979C579F469ACFF3EF6B530D725E7F5160AFDF7C2D7C252975CBA8955E4980CBCEE3C2F04C5E093118DDB4B99B444BAE08BE1011DBE1FB40F0AC0802A8B9CFB6C4ED1DFD8E71B8CDF607AA9E81DE01D202EDBA03C123AA0B77B7AF39BEB315282233852FF6D9CE7B3349EDB350A859040DEF274CE6FEC282975B26B8074F7D8DF1C91DBCC45E76AB4CDEEB6AC815602E24E6933F6E95B6BC993C69F31DF2422C57F0455EDCF0B0D0F6259E610C94E5074CBCE6FA7F6060A28BB5931B8B8C0A2BFB8A08478058914CB6C2BA2954100C594B9022F4603C699CA7DAC4D2BDDA0CA1188F20E792DEF460A5A82DD4E8CF5D031BE0F207BAD25D610BFBA336BB49C48CFE3F9EF0AA1142D65BEFCE8C5BBB7115A5CF932244B3B67514D1912413353234A24464121A26C258D6929B31AB2169EDCDCA9F875BC20D9629E9B3BADA22F94DA8666419D0EBA2601605819A80C2B632553B97AEC1874C40B2A0D8C1652B14B82B8532C902DB469E3148787A637C236055D41A63CDBA65D2B5D6CCA4655DB586EBDF3007153CA444D6FA750F4279F930C7288781E6B18D1E7F4BED10005DD883F23AAD0915E5634BABFCDD0CB98503464887D7642D11CED75B4EBA396DCD96DB3E1F5FA37FA0E6126D5BF45808B56D657E3BB9BF4963F192B2A2B46029F73DFAA5A63453930B5A00496D25182E6FA21322217885A05724979849D5E497FEFC91686FEA5F49BC918DD23086452E62ECAB6AAD141DB6E277EF6E59E1B1E1E9A1A9D6840857E4CEC4E461D11545751E225394790014C3D39DC4360065AB3CFBCE8A21183A91CA96593E8FF29ED6BE58ECEB37C0F29D5F0E22CBD98871F2425E4304EC5BFEDBAAD70AEC6EF72272AF38A587345A807FA6AB1A887A4041C52C0D62185781DBA6FBCAF0ADA74878E4872992F176D6BF721A5AFE02BD82235CB6F24F21D48512118DAA2D71DA751AE5097E8B5624434309BA1C2630C51E1B60FCA1A9208E3EEFDD080499F8ABE03BA32B972F444FEECE8927626847F6ED030F1D3D6198DDBEBD450E33BA1245F84B8FD3DAC2668E3C3417780C38F15EE0301A8FEACD367BB8B378B57C56B1BE32309E4F088E2E78FF8D352D36CD10F5C362BBB2E5530F7B46C98AA0C54A70DF9267AA020D9237BDE1F00C973644244483EC49AE7093A007B920A7038D22FA4CA7D785862772071E4540099A1F162D10E49D5504F47A8F3662F9BD1CC5B5B8EB5E6565D16A3BD736940891F87E794FD5130FA36D2BAC4DD022A6CD79DD32FE9F2FEDDF2035EBE3579ECE831354FF421097B64DFA60076DA8E65DDFFC5B495FBF2118CDF8D0D3BA13D82C73B0D548AC4D3D1E3E8AFD49B573495B6CB11776B04B096E8011A814B9A18A3BDA08FE9BECEF19E4FEAC8B34C83BB280DE5B643530118ED07A2B9AA33AEC69216F6319F3882C592223802D0D41D04A2290C6D0B96C7F42FFFDAA275611D3F9675D75F5892EF8FE9FCAD4ACCBF7F8E04F3D003ABBFF124D83FEF6F42E1B3A7E206FCC3972F86A0CC144E487A96AF5CBA1D4428A05C4AC7B6430BEBEE98CD8ADADD4B3D9314A07FCC4B04FBFC4F65DD87CEFF63E936F89F9A3D928A8ECDCD3D75346F3E418A31AABB42D4ACF3146D3D1E786CD5E5EA7FAA39988C9CD1E116EDF37C962F3B59B4AA46078B56D6E860D1EA6B910D025093D49869EE0A4AD985B1DC1C998F00196B9716D4A42C1A407216297A7E0EA85BBA1BCF28586924D81DFFB3898F5536FB82A53C1A9EEC6D47FA1F5BC94B6116A3DC9E10D7FA1F5BB9DBAB0C9932477B8787DB91FEC756F03A5EE6F95C37C921B844E60ED918576471B35C209162D91083D9F46672B5CA62A33906B3CB659ACE25DD6493B642B30C1BF568570DD25A269F655FD21AD1ACC5EED3D92CBFADD1CC5A6E1E7FB92FA79319E4787693966598F115693C3386C7B414FF72131B03445B014C695E9C2006B5BA3F04C7A1510BE9B90F63EE83C0D166F55D88256686796E4797DBD198B2BE3936279D328C11ACC5004260C97EC579F125FB1511389C07A218D0F5DAC00D588B8F9A85F3983768E838C578D105659DBB0D52F58AF65F2DF36BA3CE76F4B030118DC633996ADA8B05C0C0A4AAE64604E0470620D565414D6A7540EA88F8EFA5FAAF2BE195062AC81A851A684FA44E6A115C7285F8890090FB468CE7ACFFE68F57FADA3E1E6651589953E1E80BCE04746FBDC87FBC1C87341DB09CB54BBAC0CC179876B1486D0A248B48FC8FC404FF582334EDE8FC3EBD0BC546AAD4091D978E7A4BB8BD2FF1CFB8E73231CAB6EFBC0C4BDE6935E4D1DD7975676878E4E35C458AF251AD27D11E0E8A77D9477C4D58090BCE79B3C72D39F4D90E25858775A01F860A9E84E7AB554D289FF0EE4C932D1C545F5E62DFC0CEB315618EC47FB0D118BF707B8A0E4E021620A16829A648283459D5E7BB167BD22955D3B5288269B3174C0D39E9215C69FA2F888AD6573E002E6304409AC758304F42C2B5FE9CDEF0E4601BDE7808F893233AB0B2A2A4E7469D36C189A084B53D7B7AF964417D35E138492CA990955388654286F1C9017EDA8AFA024DFCB4A3FFB6197DC34F1586C3B001F69E3B3A558DDDA7CA0A85B771713558225D55BF605E4302D81CB2B6B27A66F9BDCBAA4796BBFE8F97E3C614C6EE79BB96648CEB2F680E28B3197312F8E8AF581B4F3FF5FBA34FAB4F83EDDD9D93F3ADCD4F9B8F1C03A2FC927554A582722D0C7F7598C9F4F669F5CD365E31D99403E9440E21E51BE448D6636346E48C33BA784D0D6B117C76161DE04C152FCC3D66EA5DC7ABCFA8378C9E3CA14636991340342C0AFE402116FDDEEE9D3C4717BD216D43B1ECB7DF6C045084D3EA87F807C2CC1507CBC59A002C4C6BAEDD71B9769781CB16149E48864BA27F272A30EB854A7CF7DD19118729A356A09C0341745C1B388EBE113D9C46B68757AC0B4E9A128EBBE6CD884737C33D6BBE34ED597E1DC46621756FC50A94F7673B2A7F1BD67EDB3BE738B62CB26F7FFCAAE21C41199E7178B25998E6A142CD1A5DECA66B4C1A9BE1F319892A36ED50E116937C6A0A273D7908A1A8C95846565568D56B083154A1EC18FA3AEEC12E8EC12E2EC1359EA3BFCDE6497EDB05A1B24A385EBACA66B36C9243B4C8AFE86342A718A269ACADBA80935A4F9ED4566A8B97CC1374D19CACA0A369F087CBB478394BE9ACE4FBFB8FF2256A0B67F450B1B759F7C8B782C3C94B312FD2BB5A26A38B614CE7AF71DB5D41B564500F89D4B8E90F31A882065C9DDF66C5D57FE8A6CCCE29C5193DAB3C8CE9BC226E9F57C80385EAA9646B8E3EE6D24B6B1036C16D4E04307D91ABCB31F266286A0DF47C2B7CEDEBD31844731546D36C2E9A0C4272DC0CF931649E95B42FF2499DAE633AE71CEFD1BF14246179A458D1F550D3550CD1E6BA1B8E8F74890B70DA9B62D981F69A3FC63659AEF272B9DA06482FFE78BFD4F10CDFD9788FDF44F05576BE3FC2CF56EB9D6507D4D02FF396446452347967B724C3213FBEA380F46765839A5CB2559BB5D134CDDA3C142E79D32F24EA3A085E55A383DC9535BA1C11A5582E2A0518D57624AA05D4738422987E3BC2E62D744B3E0C8CA833E7C2F635AC133484AEB1B2D2D9E0629E2FAF29CEFF25C641821E9F39736FBAD015A7D99DBE5FDE2FC7C2D4520B9E6E388BA24CA98A1DE8555CDC7993980A9BF53ABF59A50241790B872747BDC22C8DBF88FDDE4940E096D3B0A6AE9CF98A66568C8451C45704C8C2F917607FAA7FBBA9DD906A82C448B38C9B0700E60D9657D19333E60DFA26045CD9D4900E96E92C2ED2E423657F1D14522F708C41437595330C298093AF4D70B8B8033E9B3CF7225D4DD27912CF8B7E63AC010700B4508346A7A4BCE0B9EA22EC76E4CC1D0F70B9F23B2E7F812A2E89D28A7FA30457B9863DE9D915F6D6B562F3FEB592ED4AE927A401C57B306F7E0330355EF187761CA20C9F5D84B5881CD9E259C8822EE551D4A152884C02A891697CBA091CC01A42C7C163C4347232EB7C53CDA4679574CDFA6F8DEB6CCFB1C95AD8B838BA6A8F9028239FB5EFE3487B93489BCF7BB82B507DE247B287E8306613B3626CEC930D549DBBBF812E396D3FA7F78B65BA5A0151B13738924874D834CAC56C4A22BDBB13853DEF5F00527598E23C87ED402DEAD72055FA856C9F49FB7EB086D56D26B7972F6257BA5FB8C73D112A9F414E4F360E2286B060FF90DE3FBF8A97E8C227A8C7CB34E6BC7FEED355D178289D2A94EA9462870EDA7C96358454C16F13F1E373B1AA054349A3866ED53F577F754CBC5979D3766DB359F09DECE7AC8684909AFA57F13174DC0B8CF52DA24E99710E778F4EA3833D46160D8743F1F598FBFA58D43D3C61BF1E8BBAFBECD7C7E2EB01FBF5447CB5C5ADD0D7935DF1F588FDEAC4F964EF343AE1EAEE0D45BF27DC7588BD3DD1EF0947ABBD3DD1EF0937DEBD3DD1EFFE8965DAEA7FB21FCCE9655ED371D53AB75F96D6AE929A70AAAA343AB1BA5D5745BEB0F56AED0FBC2924048ABF48A7F1CDACFD9EB92E8676DF2FF3457C194B9BD1838CB48628138F3421B5F16843DA91A97D42DEAB09695313DA8313BB36253B4C10180B973CB41CF1DFEA9AB8588AF83D2E8A78722529C4D95854AEA13ADAE8822E6799BC7496E0D8B90FECC47FF784C018426A70EA024CEB519D2EB427D128C7E723D1AACD9D820E5B29E727F56CE215B1AC9B958EBE302A23ED7CBB3F2B77B933B627F4B4444291F1893D32BEEF1A356A9D6F9A49DDEDD4AB7AF271217526A4EFCAEEB2F8FED9F33F7C78FFECF94BFB59DFC767DF0BE160F9F0FCCDCB673F8A29B64995973F7C7C896F3699F2E1F7AF5F7D14DF6C92ECF9C71FDF884F3611F8EC0D2AD9307CFFECA70F02F9A115C967EF3F5CBC79F7FC0FA7D19E8D0F5F7E102544E53D5B978A2AFBB611BE7FF61F2F2F7E7A2FBEDAC6485F5FBCFBD30FE2BB6DA778F9C30BF1C5B64BFCFEDD5B746923CE9B97AF3E5E3CFBF1C7777F12056CF8FEF4BEFC6CA3D38FAFFFE3F75503366A01635DE0C046AED73F7C78F9E34766837BF1F2CDCB8F2F99FDEDF72FDFBC6736371AD79F5EFFF002DD5AB730897959C4361F1F44E7CF3F32DBD80F3FBD7DFFECC5C52EB37FAACFD8046DF8A9CFD87D6D64559FF7C5671B4DD5E703C1A0BB3692AAEF87F86E1BBBFA7E84EFB681ABEFC7F8EE18FB637CB7B1A2FA7E82EFB65955DFDFFEF4E6E3EBF76FFE82620E1ABE7FF3D3071471D051CB865D0731DFBEFE41B6E3A0E8FB973FBE7E2796D170E820EB8BD77F7CFD02C26168A3EDAB21BED8A8FA6A0F5F6CF47CB58F2F364ABEC21C0F6D347C85D9B50ABC579857ABBC7B8519B5CABB57984BABB47B8559B4CAB957C35D7CB2130154D8B352610832EC59C930041DF6AC741882107B56420C41893D868194A01E5A95EB0FCF7F7CF7E64D59E4B05EA2B9E7194ED2D72F5DAAD2494D45DC8E262E3F94C787AAE3EF526DEB88B6A93DCE462CBDA5018E7FF692BECDA1C2A84D59DA7ED087292A489354471F59AA55C0D50FD23DDEBBE8E91C4D17421B5AA4F4F72D3B8ABDEA6D2B6B6865E59C53390D2F625C90B89809FB9A4F68A8346B735059EA399FD17015CF939940E7D49E774643F3C937E9D04C48054F7987A60654908A71EA7FFECD04CCC054D5844638E56EB969200AAA67E1502139F7220730AF410D2E2ED3E2751AF02C9C09E61371646F64E995BCB236DD8C76FCF501C3A08EE4B022C7953F13EAD48BECEFCD99E0393ED00E3489851C613954C90C01A3758ED4E606D16079C92EA51BBC29E5D94979979906CD5254D3F2AA5D6ABD39D484999E67458800B6A4E233F904577AE47809CF04756C2F283C9A01B9A3735F57462D5563FD09E76E4C302D4AD17A2565D1408B164B615B34226641E58E8111C8D0C676AE2C06193B3DCB80B0B36580F71CCE4130A0E23C9C499D37666474029A20177DE9B2F5E20CCA7F8600A3430BAA99E4B7BEC344A289A80669F959CB15F98BD8CC7059AEB8FA836CE9F734995E3C00DA2F0122C0334193E4AF06E89598F79457BEC2E285F8ABBF951009DA9D50B2969D2691E70C4CC3D55A7DFC984EE1AEF0A5F90DBBF505B077E1CCCB0CE82E24006AB3C84C4E50CBB51551E1EE5FAC6E567B64988B3D874D496D99BAD5161473AF64F731ABA8A75C57AD6EFD0260FA4F14003B3B0CD73D09606CBFEA076812C35F03501306DCEAF337152211D47EC975F2D5D706C7B2EEC35EC13CEE6892329A6EBA573BF0DDD007BEEE7150992DAA1E9DD27F3AAE3881BE991C45E0CA96E44F3DA77C8A2900ED59AE633F0D5811B7A4FC4E0F5498C3F46020E6345DBE5001A6CEB82A13A86A52D592680E16F152FCFE270A530E6A4B46347BD8490C4EA07D2B83F4D653438289545AEAEE435E47577402AD2D1F3A1B5A4E5424B5A3413A27BD59827C1F75659A207D485AB5E2C20B2567F17DBAFCB3EA3C9F4E5769F1E7902A7FA955F98BA30ADDE94C5BC3F388311986DA5F514EE2555AE7BC4D2FBB686EF3E025688694D4FDCAC9133D898EE8D282F8D364E4E749406F925F0B63F7AD10CE88230D10FCBDEFC59EFD9C6A21B207EF8DAAA87A5F78415E0578FBF9440DF1A4619AD7EBBFA319745AE974B6195FA69A4F26B34C54FC73E9B911E2E875FA7DF622FB3059E6B3D99B741A120702E20F56650DCA30E9357F319CC15D00AE7FA9E1FA17DC8C343AFC982FBC3C0464647FF71E9D2355712455D815455179E507EAD5E20615CE88ABF0CFAE47825990BA29D6C7A9C81F8491E5DC5BEB878D3FFBE6B676C6AEDBA8FFD5D144232C40282A2B97F876EDC0A81B184C03E8147404E8167804D0B70AFB3D1D6ED343826B6C8901F17F80D48CF33935036EFCF543544530E6041C390CD37D011811E7B56E828130ECBEFD806AE1C61FA01AC03E0416FDB8771C3C164097F174430E5022B8DF092900103B3909C40CE071766A08281650A4C69A67D67BAD4D5823180FE00AC803F84DF6D41A980760054ADD55D341AE90EDBAD0BB9DA9150E2A13D8B3816D7C5E48CFD522D0EBFF102F1F211C9D996BD5AFC3C09BF019A6D8902E57D18FFB7BFA4737B27BC764C17C16BADDC1638CF373F45D74A25EC3137FF573C4C991AE361C0ECB7A88FFF36A1100AA78B25755DC1B9EA806FD95F7F6AC494035489FC774AA55FF49B19C0926F2CE6075035DD47D1AED0A69EFE27980D62A42BBD0753E9338920326C9195413E065330DDDE4A4949182070E312313CCE4AEFFE8C38449B47326982900334037EC00C0906C50F9EC22513BF4613B0D18E25974A4C718609634E1A4C3A3781A264857BECFF93E6CD09D3A8049A9FAA908DF51B7FA8009F9EB4376120D01FB1420A098A788E7331DC3C53777A50E7D3F2FAED295767D05585F29FC45813487BA7A6AA8A2812E4820784AB72A032BE8EDFD349AF82B58935898F059DD5268ED8BDB8499AF3A55A337ADBFBF198F715241D56A7F0B68428AB03FC6B39BB205E34F9E061059223D7B5451ED966BF89A1C6A47CDF80AC9B90490CFE2D6A9D3B83E6B02DB7DDD6EEBD4FB98FA4DFE506AFBF457BF4201D12AD10FDCC66812E45517E7E98363C9AA271CEB9CC03F916E69C9CAEDDDA3D401E91765D343F8499FAAD35B6A33D2CB95C511C462953BEB340FC51B24B009B9C678B7A38BBD5DBBF7DB9496D541F9DF7FDB8EAA7A36F236CC074E6AD0DA6CF925FCACDC7667D8DFBBE6BA6CFB53C2FAF4DD3F00D83AD5C12BA2EFE66C357E37E2E6DE2DD2A53D796A60CC027FD8B1B7EB36BCFF891E1774717B954D428EA9D7B0D0832DF300C5036D41E53D184231ACE998A15EA25D26AF54131A0643BBBF5095B6A1C992F1164CBA507D348076A6F7B0BBCA05E8A276013AA94400A75AF420CF85454834FB6A9431C4C09FD2F11F9887F6889A31C589AAA0174E16CB5370554EFE622B1A2657ACB1507BBBFF5B62A1C8EFB1B75B9A3946048846D2D130519E0BBE10F537BDC7549518F40E136836638DC2A37B1AA3EB95510BFEAA802095C706DDDC504D50D353774B85570774F26135A1E9D3EA561B5039C1BAD5A53E4B8758B7BA00D383B646EDC70FE8D970C175AFDDC567D7048F0FAF09E4D3037375F4E935A1F4F1A1ADC0BDDD8410A76013D6711236A1E634EC5E1DA03C8DDD2BAF8530C02BEC3958CFFFA541F932D7AB0C2027E8FAD527EBAC250DC3DDA3F52AAF3D4B00386FD7AF0D08F6FC36E161730D20ED63FDEA00B13C1FD64077059E0328F60F6BE1E861EC0B58CF396EC2C9EEFAF51FC4CA8040C3C0055B0F1C3F20C8C6E2E0E1EB02F01528F115082114DA8737F2A0730D1B7C05DA9CAFBD1B9B10E238E020C044B7C11AD53A56E958FCE1C7374DE8EA573061CDE39D26743EEE6942675F8709DEE3A0264CD9E3A16EED0042CE934C08649707FA72609773CE9C8EB73EF686FBF4AF3FBA3CC831220D9CE181DD6BE0AD0E301C426B7A0E7804FCF57D93ED99E036F20685BBCF79F77B027B4377BCC33FC175AE0D455A3BBEE63578BD942604AC32D37FAFC54F40CBD287FE1DB96F9ED2330B21017DFFA3DEE3C04501A80479589D078AA9AFE672361E0D0018DE674BF2067DD3BFBAA86E9E9F898D6045CBC49E5C0C6C1323E68E5E474092E822C73261887CA50F1ECDCC02E50D5FA612780C68D02E95724DCF70BF7132B2E657E06E62E374F26A3451174FB8E458A047017759A1738B0B6A6C134AB6F9A6045E84CDE81CF9172671D19F594B1A4FEA6673D46157BFBE6C7E3512A546197B799B6CE23E35172FC8C5E77E5D7C1A3422808D03DB7F528CBC6CB266E3776B7A04EFA9AD4EEC99DE46AF74C1D084197506AF1EB95619385B5934EC18D30975C5B7E6BD53137BE6D8444F22DBD64B26F6401F37973B173BA7D6B4A4D3BE2BD1682BDEC0F85DCDB0FA0F3197449E4B217F555CCF3AE59C9715A2F094F354C11C8725878CBE173448EFD2C9F3FCFA5AC8973EDD34BAA467B95E5FC797E9F35870424FE56CDE8E9AAFA5D572C9189C5E93A565DA07EE749F3E8EEF5F27267B64945B6F629D44A379F55E42E678AB89CE5E64BE9149898BF89959C3285E500295C478A8E47B811E7A718894822E9F89FF20D3E1321BDF14E96A9025832F3284E72CCAE8F2BFF88EC4850ECF816B3000C5BF051B0FE4F58E608CE92C5DC9518A4530B2673DD4404C4D1570C420FE4BC91D7F70E543D6A0BA19E1BFAE2E3C679BF49EBAA3FAED55364BA37E9F660E7D8DB2ADAD737F3C2A45CED6A68CF6B0C61C06FB0C5D93BF2967DFDF90E40FAAE1C11EE0E3060D0E02737682450E3A594B6720B09DC8371AAB09506BA39DA582D6979B8201D9411B4B7FB3B9B299559D2093686B3835DC7D6F7944D6E7DEE579F01E363ACB1B7209A21ADECDE55DE79FE6B33C4E1CDD00F8B6EC09722F9274552CF37B4503BDDFAABF9A14670DF4B90CA34C688E6431CBB43B9297915021C471C75BFCB7715F7C43E757A8DFE5752C094D8556ADC16499C645AA46EBB19E7A49F6C59A300CC02C15425F6889780F544822490F7565FD879C926037FEC2E3A04255AA762825BC2390973ACFE662BCBFFFF8F68D2080356336B757D3371B8F982F56343902C6CEBE3D3F8263C6C3580680D6AB92D4175352097EAF1F493B9B84643DE39137410B563E4E19E010AB6AB88D890F672CD78C01CA00CB7668B03D41755A7C105BE3A488557C7A6B46EDFEBAB06923A54C30CDDBFC6FD96C668FE1D4AD0D56C5FD2C1D88A23FADD2A5442AA269C163943D7A50629ECF533B1FBBB6208DC51FA00293C87747936930B0A2AA56BCE29B22EFF9EEDCB38803FCAA991E009340D2046C225FA233C9D7839BF9CA9C5C8396EE56004846E2F35126835F6ED2E57DBFF78DB0078809CA274D033AC88AF4BA89E2EF9000E54BC883DBBDDF39D1EBA0BFB89789DC96F78FDA8B6399DA7D04AA0672268822EE652EDDD8FB761F11001F852017AC577C9F0AE2A646E7B695103498B8F360920E83E175545D60308B57056D66506AB9AE35508DE646CA6EC6DED544CDD9293A98A777C5876C3C136A6287DD3E64E75CCCE2895DC0222BD5DE813D1C199F6B7B9E75D2B57C50FA2D91C7296BF50E04E7EEB3A2BF2B9FA47982875E92C14591BFC8AF7D89A2804B530D3BF5ED0716DA91957CBF48F32951811099D3BBBA7CD428B9DCE752A04DC520044F8023B92BCAA4544EE6FA4D69DCD72B7F7972C6135F03F5F255F9EF48CDFE643EA2413F8976D5055AFCDAE9E1736777FA0CC63B4479F632A6E5E03B7931F0E718D204DF5578D9753CC52353FE9EE3AFDEF332A5A519D0B729FD06AA5AC5105F13A77C3EBBF721940CD2EB4571CF0A05133A71B0863054A7D97255F87055727F3AA0D284825793013458CDACEE411EE01B00C0A1AA27EA46E15724AD7FEF0068777D7B93B5EE2CE3FC0E79A39010B737C1ABC7F36247FCADA96E7A9448E9119D5C93D9AF2DE4322995653C89D9B1AC7956CB4A4526BCFCBB9D1ABDFFBAC9969F5794F44AABE5327D1694D471BE4CD2258D8453575DC36DD015C3BB9C3477084D138731202A05B93E00E8C4B509D1D62B348F02B75EC58607D35C2759732D07721A7DB17B311497FE314B5D69ED3086E40B3C5C989C9B224D3EC0AE516B0B2E22D782A20D949CA09549E45DBF86F594642B212CEF392F84090F43345CE907A875460EECBFDB6E2BB64E78D8CD36C042EBC24800430A54CF2621225DFB8D54C411D147680ED61100AC2373AA0D0F4095616F8D738D77DD9C607236C30FEE0600C4309D89E3942424739BF80872D9A5CB86832B48D57E9FDDA5B3F246B726B950D84EC82CE07D268AE8422559A5AF66795CF46571E4C07B102FBBD11A135A766F3B4079701D25000AF90E2F4900A41A713091F9E8D224BBB9765F2D53DD1CACD78D4CE14AF9E2CBDFFA3BEAFDCEC55D50D7F5E99974500C0078EF9E88EEDD1E442198E852DECED2A937A7E3DE01667679332FB2EBF44348B5565951DF9441BEFA01EF3EAFCCB6412FCF6E219941555B8065DFB871087CE804A0DA761D303A94C7E6485C8F3ED8088BF9E9C62B65C4A6956A9EE408608905C512D717FFB7ED62F1AA40C449EFC59F291AE0E3329EAF84D9783D789B4D96F92A9F168367B3C555DCDCE9A9EEB4B6AF6C3341360E4ED15B8D300566C2625C0DE044EC0327ABBFC13FDDDA612E76A8BFFF864395F67119B5D4205FA3481997F36E114FB2E29E2849DAECD3807DD43FDE782A6B0F74FB8FF088D783466CCB68DF1C65741A80BD6A4FEC7F0AC75CE2D8E4382BC9567E9261C339B4A769004FE55F68B91C1E47DF30343134D1BFE5392C1CDBD81589B7A3E1E6E0E51CEE6808D48D3E350DBD8BF3BC6DE8C971BADC1402926D9150A0172D96F965969CC2E34D8B6A8B1711BDBEA2D2194A8B216F45BD4D9B2EED56ECCC315664CFBF581BD2164B19D73128F237F96DBA7C2E0CFFBEDC050B8797AE3C1CF82E2A92D6F940757CEF94C489C922FD4CF1022719037D8EA5A83C3C6E326993E3A943FBF66B2AE87272F392A4A8E4E17FB90B1F628FB1348E6D80BD095120CB7B3BB896E9016CFCE83A5E5E66F35F17719264F3CB5F6FB3A4B8FAF52ACD2EAF8A5FAFE3BB5FAFC5479988FB91BD158BEF9AC255C5B7A3A15DAA91C142FFA9730EB38E3CF693D4CA8E86C47774EAE6641CED57A6E272A0FE3404E6944A6AFC9E6A32FC0670E800351488E2EB60F02754EC8E8043B72D719AE6F3E2368034951B99996A13C82D78BCBB1B70C4A806DB1BE7B3C426CC4CA0660FBCCD8639ED00BA7399DEC2D57D388599F38D0D49F28C44CE84DF27F07584A2E752842483225D1554B9B364D30D3D157A5D29C98EE81964FC3748381DED999B728F841CD93274183F59ADE42F160925EAEEDB051BA0AA4AC870AF819B1DBA0B4E8D32163A350627031F94D9DE92F64787F4AFFD720BE84259C78D732E0629C48447147F2F03A6D58913533AC755002CB0435A996A27B19E70CB4244E2117E3E97B15247878C5C9588B8724529AE11383C6D6CB8734D0BA1184B928DF875229121CC8EC2D8D5448FB298E47CDE1C1DCA67AAD9FD79E0BA20CF6C742695546E03AA61B2611CA86260FCAA2D2F23DCC9152ECABA359A95E1D1BC932C37BAEB72E807D0CECBB0F1ABD2E5108788805C912C384CD52C0BBE5F550CC53CF5A598808A3531668DA2F771F2F20E8EFABA5B917AB51F04E9F942016023E78DBBC0220A42C809FC074AC1811B802B5EB48B7FCCADA99014D598C99C9D4633AE0BA19E319F6E452DA1BD3710F8119B3087F09568AD5DE5FBBC28F2EB4DBFB863A7E57B3A61E166E6D81E0D4712108253C6343128CBB93BDEF3CEDD1893D75F0DE4690FA64DFA5311E899AACD0B83AEBE933EB4E98A60DA653B2BCCCEC4A4BBFA129F43BA5A876DC60EBE193B18670CCE29F1279E718D800A848C81E7BB7161F62859CED5A52C11D2E703F85688130FEB3EF60895E3C75EC65CD02E5F975E345296B9CA0A35E4649D75B86431C0748F070E66590C0A2AE2E099C5E0968ADCF293BC185C5191AB07CCC95BB22FD909F149F9E36E525E5AB3A1425E96868C670A2F5B859DF278DC2AAE6431A3575427CC74194848F07C958138F42E5C3C5EE5B39B22EDF11A06F00B704A52511F57ADBF652DDDDBD3F8C1DCF37D7E6753C81FF3197925F33C3E2899C7A18F5FA7E502AD31ABEA87BF911A9D99E638BD33B5235AE3D765BD02DE89A2F21C7917BABC37B6528552B37C4224A175529D3AADE84481230A6055346B1476750840E66CB6FA21FEA1BF9AD13D59FD5BE1BE5805B456B36DA2CE8ABDADED0D9E43FF0B74BB080C43A0938D89D6FD9D192F01D4FE6435C0EB5BC2AABCA525FA255B65E359EAF7DE00D0E1B8E2B5FA66B0D806323E240033F888C7E032AC2EFAD197B0C0E18AEAE0C2080AA5A74B9B5875CA6B177D171D9756930CEB71B303D1D94B4F9E8E3E12CEF0BA06C8E72957A8726BB8F8C2FC3FFF2081DC74100A012C448C63936FF934658D87ECF9CF65F41527B6F9787225B6A721627B51B180A9882999CDEDD01CDF78EADD6A512C9FFC23CA72246564F4C62DCBD565EBC6BC6D5366871087B37B615ED53197AD6C83B3D1ABF80F0AD80F0C6B6B9A457E910E4A91C4AC15F8F91DA26A9DC5B1706CB3F4D5B1446EC5B6BBC0F877880CFCD2B89205AF64C187AC88EF9511645D1027BC4B512E089911F71FB22026957552AD5A97E6E39D9989304C24DD1C13240A15B290639E442198280BE71C894257B2D0DAF3B34AEDA20A3BEC76742B56E27674639DA21B51E9067383A81F0BB1F4145647819C7090BAD28CDF1B573A00041AF74DD82A325A762861A4D64567A4AB7768F816398AF8CB03AB011D6C89766FBBB57BE56B579ED98986AFC21AB64F7AB6FAFE46D866F38FF16573E6AD7D9BE76F457C49A95128AEF9A78F1FDFFD4061CA8D6F76FC7BAF7F78FFD3C75E19332B16DE339D04A0DFC3D14C6F534CC84F8B85719ECE34A5FA0E62F29B55BA62A590F348C31C162F10CCA8EFB37A903648437FFCF8ECFB372F7B6CA6C7A4362B12B1A0B1AD4AE1F521FB9BF5EC26A6B39BF888FEB5878CC8DDAE4E274FF806991095006DBA9FAADED9C00479761D1FBA791E40A5C41EBA10429169CC71B28BB107F571A4FAE00E96C374DB440B5545022181D43FD554044FADD30710C7F42F059FC613FA37B16C16E2CF3C93CB4D364E4336D9B19A6E0B9B70DB326A886A4F451FE33DBA0AE76016EB9E5BF715B153A838B8B5869C734EABDCBB476950BC44F9E976C9AE9B2B41EF35D9E6D58ED03BB06F971A3CA11398E31A02724708C1A0DC3BD644218CFD41D3EB4A2E047B956AD465874325CEA2B7717135B88EEF648D1D120CF027C1A36B3F7E6036DC929CAE1E93468F89ECF14AF67815DE635334D897B04F38C8308431C2102C380B2D74D7B21A0BFB9F6FED7F16BAE5AE1B099250D7BC74129B9F73630D8815A88EA61D2E67D10FBF2F6F8CE5D9BDE94C95470F5214990296B99B2F4AE3B0818E13E8C020A2196FB1B0953E13872FE07F1B814C0BA8462143BB70D12898328A7DA76D922C964CA4830C1742A1482571A00B1D9B8673D8714EC0DFAA60C4D7977886953841B08E6D75002EA4881BE7C9BD3576CFC8B61278450C83ACC285CBD3100A49CBEED224E86645C7BB2362A46AF71B81F8E74C6DA0268A7AF427412FA13FA1C91DE70501B426E752A81EEE4B1C00DF85D5F0DD0AA09888E6C379B4E08A239BEC87ACFE8B249F7C982CF3D9CC647576D1D7388AE3BA5B2A7339CBC731E76150296844E7037D6755DD37E3E5003305F7A76287BC1574BA4CFFF28E1C7174235570320D0B873888B21AD77EE7678A3D53BFABFAF9B3D10F65B17C9D7E9FBDC8241D71CCD47766845A95E5366BA8D10115C90CCB4C074DA6D02CC5CCBC2982138BF67B176359A38710284AAF2686A4FE26C5ABFE853172210E34476C0E926C994E4A993013ED06212EF3A2D6394111D93712B0652776D2CA3A5D58E61F9174731DE0EE5459C492407D9A4DF5A6AA5CB6CEC49000591A44D7FE5F6282D3A87146B0E36EA6EEF716A2ADD69CE304F1FEB42A2A560623A56C9227E8B089486C0FE9D0E02733E08EF0243FEDCD1C3154CF09E51F05AFF537C9F1E61824E0DED940C10D1D601B3EFDDD7BE4193C366E03D770DF52754D6011B44C5BC862B4083473158AAD854F8C2D5F726412B2D6D9429D3A9A0BC8E9C8918B3C31721BB4F2163CC57788225704539204080940B5959E445BD63526E53617E7EFDC9D4F82E4623C6EDDE726AD8F8FCA490276E8E4CA286368184C7181343399A494F5ACABAA9112D904A95C2743ADE230AB929F15BB51A9E1EE945AF749857B558C5DFBDCB2D25CFCEA153D02E075DE94210CC995EBEC5B8C6B708733EDC59D28B92DAA99C152328A54FDBD1952E969F5DED62A82AA2C8D96B193E1320550AD6C2F3904D1F723ED7961367D76F20125A1D092F8694B762D63172002C6B5ADD42D599D8FBA97C4A39EEEF99EA054AEDB51E7488E9005E0DA50F8CDC4C5F172A94B9DE43D490CC70A0718D334D697177B95A2EB4C016810BE595790DA5955B1D881122E8E9249EEDB99B59B03ED1941649ECD1A50D46B09A41D880024B584692A4F03E79B2AAB98EF4D4949A9B25EA1EBF9228E4AA1042C7D2139D2092968AA92F87ACD615D498AC9A0E28092087BD137904CE8B3ABC033A1248EBD3D9FAC33C1AFEC99500EE46B0EE281037017F17C36F63C3CC3BEAABB7E56455C6493F0203B318C63BD40BCA9744D500E2BAABF515B615224056100A8C716A2BD101A027498E1DA04D0D0E691C5FA4C026833CA622D4E0178D841433591C7DD26F261DCA8E47B6BFA1D1DFF56BE29A00599D0C66482185EFEF917BDDE19C54C6A07AAFFD5E3A6ACA7FAA5C0A7DFBA497DDDAFD1C2BD8B16CC68DB7FFE4D897EC6DE00A8F57C2255BAD29BE852DFE5E051891D6839402A651B0C6F5CB5CD15E6DC43AC0CAB7595D8FDBD5FF3D0A375F8581E6958868A8EA521989045286F66082C2D65AFC7039CE3885256DA8ACFF7EAB38DA88A82D7630F01E5A4A7BB8492B6E7ED6586350A736F8CE87BEAF356B20A96F16412CB221E67F324BD73E5B12C8DEE14B95A51E53555C155E8B23EC3883AD3689CF8327BAA5EA8EC3B9475B63899C5EE97F274735410913DEEF6A6399B835516401A74472140834EA8F14AD400995093E9DF7F6F5FB53BB78727795C528A8DF6ED26CF249FAD16F11C77DAF3D907F193ED5A632AB84FBE72AA7EB2159A2E057A72B3C478ABDF6C85AFD3E22A4F4E91CA0C3FD88A2CF35B8599F889C34C9A34D9FCF2549B37E2676BC1AB980640FFB516907DAD988ED4F8B9C1D3BB36AA0CFDFC912948DC88893C3539D352901EB000078982E563163DF7549358BE8A5708B76BCB655676A8D3324F026BC54747A437A443298A2CE5AA32473201895E054FE52AA09BD7A9ED963C896989BA766B9581833F9847ACCD0FCC8935BAB161A8961375F594FE33582DD24936CDD2044970021E9050C4788C45657B3FF46242C3B079114435E4A057C15FD52374518F9E4AB2AE055167CCBB2CC4CA3D8D86CC46293EE201B3055F82DE1F707C8697D3F1799AE785E3F39590E68ECF4BC7B7AC20BCDA5FAD7C1FB34C8FCD3E7D28EB33392D2CA5A1F1B1F91468D5B05B723D9F02BB603524346835D23B39D875D329F83716C09C027FDD02C01C3FEFDC2D0DE2EA54240D08E4BBD89B0E69C28C916345B9EC320A2C4145AF61A15AC7EADDDA72B40868A1B04DD55D8878A2FE3620514668C4ED180454454904ADD729087A25A7533536C2A4720122008A5FF7629720EFF12417DBD6A4E83B6D66BF850808C89F0948D2595AA432D2C5371080EF45A1B21CFFA9493AE24D3D7243047967F301AF2A604ECA7724D25445A7E7B354A832DEA9AA882519C1F9B89317150099F4F282C0994A64D46B8A41FF5CFAC581867A5619172935848D03608CC5D4D782F00290BA52D6F35358433886803AC52B6D31184D8071B6ACF52C7525A291FC3063F2E37000E5A5132600FDC403B725BB807037DF2548F4C32EDDDA0160BEB6D525C5F004DE4DB03EA2CB41B7B9D7D0651D3721D059D91D31A2DBCABCFF13200C9B10B2A235048C647DCF6917B79F8B52E43B5FD28D3418E6A3B6CFC615A2C9C6CF6AD0DE82DC13EFC90C476959FAFCCFB991AAAEAADD07D58CDD879E78AD7DE3D1EE69CDBDB749374944F153482465CF4AF1EE9E3BA9303FB55C3B935F1C2E16EE798590781FF9406547A3DB34398C1624BA957EDDC4C9EE89A5E73CCDCE85E42675F431FD7BB21D2D72FB43F114F1924F2277CC11DA60790E1F2B1B8A8A32EC223B4289BA30F5D31DA03728A5428821F2FA4141771E11CE587FEA1495C27B0301D92E94FE5F52BA5BBB3C3913F95E5AD9B09ABCB0D6D58214757D7C23F7D7CAFF1C92AC3BCC5A2E8DD8C9B7D144FB72CA57EFBE750C5CBDB7DBB7BE15D05C894109BA6BABCCF926ACDDC3339DF26E977C81BE4FA3514F3EE3D83B777B50463DF2B4F0C5A4ABC45B4C3A5CBCC5965599EDA84738F085134BE16DCA71CD635BAF02E43D5566E9A550C9506D9AA5B344E8056CD1495C12D73DCCCABD1550B286B1AEC9A39BA1FCCDAC776E61469B936E7F17E7398F9E7C5A7DD31F7DBAFD747ABEB5F9C85E70C83A0EF777F738C7E1FE2E9CF8BD8B0B24424F1ACEC38F50705FB77209978B51D43E90493AA77C7692E256CAE7E908C56DBB7E713B582CC990417B325F2B6DDAD1533B157B4FE4EA88AE6F6645B698A5679F7AFAC74FBDEFE870E40906245AFE39CFE60E1DBDF7DD931E42EE442D06B39C123AF59E3C520D2ED32FE9120A956C5A34F08869A1215DB4C560EEA9D3252432F7DCBADA44D5C3EACC5EAA26E2B12C0922EFDB882C9D41A21C2F2B756D391368706B8B78678B7F680A7C875A8FCFAD7B23FBD0B7659F012D2893BFAD2F354A28052837B88693A58FE5C1A6ACA3ED9AEA3CA5FF8C86E70DAB53B0099771535418CBEA6A784CB9DB65BCD88EB2ED683A11F338E5741D6041710D621908C4785F1CDAD3EB050579B28F6B7B0FEAD12ADA5274547FC9D9E460B48A335D55799EA3ECDB6867C7FD8640459AB1F18220D34B6743A635320CC7C6409AB063E3C552FD0CA94CC9CBF4A04F5451D57C07BE31A040AE4DA635C6D7EAE72B8135AD005B332AEA653A6993915F9DF56711A721FA0C408DB6C59A56DD647F17A3E18FB7F561E07314885A86C9C5FED04E766DD3F57B91DC672A0D0AAB6B7A0E1113F5A04E25E9DDBB2923B0656DF4A2CACB0BD89E91C9939C24E191B69F288469A6A494CE742A00391A460AA8D1A37463B8E5C0F6F5C09E382E96571D895E656B7DFCE7291108426D53B5E6671187F1C9D3CB9E79299C5E05151326D7B5A6893124451AF520ACFCCE898AE1912CBE4D75B88323A3F18DB3888F47ACD135C080B4D2AEC82F2F670EDA9DD0BFF6C46052A20D63F2B9DE08DE9866F3941709B2287CE07A491ADD048A876444AD08D6D12B8438C8E080DEB9A3559304BF6D96C24E75443A873C941618FE98AEF29BE5241DF5E49FC662131E406CBFC956CDB8F5D04A98A865ED5D2D2AB658E65FB244308FAD923986EADD9C1695C98B11C943758BACA46DFAD97219DFA3B722A7D75BDAF48D1774C2BB90CFDD590B4C6481493E9FC44DAEA3D532AF5D03B6B34E8CFAC2D2BD9914F99296971EAF850F2455AEB33BA1BFC6DB46D96A28AE18078FBC953BC95E2DC66CBA1D898E723BEAA2E068F75C11A02F283698C4B31930DBB5AEE95C54C8A54A2CEF33F3B8FAAD79402CBA8F9C57137473D88367F7FD5C0CC7BAC0C24873D4208D9D2ECD21F08EA9AB6C553E0405CA13B97550019AE79C67DAB5231A587F34275F7734064E42CB5F840F2810DDC93F0E5DF91AD957C778DAC0F8F2C14893008B8CC81387139C6E6E9E45E5A0D039C34E90F79772F1D6D627568BD3A468CE39FA64CFAE031681ABFED7E0F9FD43BF44D6D2D2B44960031AEE66C81D9FF6AA3A3C6E2A13ACBF253CFF357FE4B3A819469C2A17A20EE99DC544DF452EB1D9F5E5AE2A252DCE508C95E43DBB000568BFAC36350B6FCF6744A559B5DF359A119F2E94292E30B27C8C9378513C5BBD95D6BA10827C9957922965B9668CA2594EBE6548C59A8E9EB2D89FB2E2EA793E4FD43517120F4DBA97CB60D423AD03EAF16A413F9D6F07C47D838653524AD8833A41C0F260D82F6E8CB9D53B28969F6B5E01ADB5D82C648E549952182BCE055E57BFC25F479EE7557E6D77E5FA4902D064499CC797DD280368E816C976340275DA0A11DF04C0D86D84DAC44A4F1B9D5D74C58114118F626E82F8C72401F8B3AF28B64D92B3B5825DBDABA8272050DA27DB75F3C4329F3DC308230EC0B15423CE799D911CE991F8C700D99722775DD2AFC9C16D5B3772A28DB327BCC2EBE4436941672B1295B49870468DFF0AEB2D9061E41264FDA7806BEA063BB2C15D9E7DCF04BD0796A15A12DF1897BCDC3501FD8651E3CBDBA2A1DC73840AD26C22AC85F90CE4AC5B22BEBBE480A6696482F5355580211D8531A8E5E376746D178A96E9121364300F7E104ADAF8E710792C6757B2425531B463B5508DCE2FF60F101FB07FE03A8CD6EB5B766B54F1508851D92C88C97B64A7B433F71375ADCCC6E9E464AAE31F13327C7819D61F1628AD0DF9262F6A6D0A65CE8F7FFBC15EA7650AD087F7D20B839E15829C880F9DBD7CB9B8C2051573F0DE77AEA9904C4825CD9DFF02057E4C5737B3C22170CAA946C80CFD56BD5DCCD782E21B3A9A38C917457D3053F478C83B52B56FBC9AC5E9A62236C82C26D4211BA9E540DCA8FD1A6E87FCF9843AA9739400B8D704C0118BB5A46C15A5B915CE8B2D8A1D0ECB97A8A5F1CBD7059814B0BF43D484F2B4E610178403E577E93B75C863002B93BB09EB915026C48770B149A4AAF303FFCA6517635D3474AC66D65D0AA7BB5CAAC546501421E79C2BD5AB552428457FE49E88B61D6C02DDFE083ADBD350714DF34972135C31F89244B697ED014CCDDAC65A7A830E8F4100B478EEA60475BA150DCF8339094AB1CCB25AE7263A6538E415343AB5523A6435CD272AD3604860B3EC04B30BE7A9D0EFD48FA121CDF47232DA704CFB363D7345624A4DFE0E3B23E571F6EEB751163D8966DF465B5BEE836CBDB14E0693593E97B7FE709AB0A9C695B9C43F8048DC8D43C0CA337F4EF9123585CAEC7C7B9DDEBA2B4E995096E37991C5455D2B3A4C0801B775AC39EA95598F226FC57F296FE5655ABC1BFF8C7B2CCE55603D7C57DF64A0D02125F2652F293D4CE39AA7B7D104C8AB30FD4EBB8475999ACBD36BD8A1FB9AD1C8E66DA854699B7DE6E67EBAE123D9DC2B4E8BC1E266755516EF2E527F937CECDB556DE4ACFFC9E92D18CF6EC8573115D2870CFF89D06F2F6564DE2C9B7C265FC072995BAF8FF73EA7F789105E28247E5C2C53E93C103FDF2CC8AD94C7D68BB4BDEBFC6695EAAAF48B98887459FE364BE32FD6FBD8F2335C1965D9FCA6A87EFE6234021C2C2DAC6EC6D759E1F06DA45FEC07DEE457CEB1987A88B4DB8A44410BF9E10111C56ADE2C6120F1D691B9F2F49D35D1001D1C584D16A7976FAD3365D24D3B1D28AB1A51EB34D9B80687E2F47C61A95CB6EF42B187CFB283DAC82A79D43EE12749B0CCA489891FBE6D7F4FA54FB9E47F4B915F6652225F50F79024CF3DA7C3F2B4E1685C530DEC656AE7685676288D8576E0A2FD94E308E7EDCDF75DFBE8ABBF696418B5BFED63E61C6DE94FAA7DB0FBC6866AB00ABA1AF528846C99CE050F3C8DAADF6C3E9F5E156ED6B3F7423154DFFDF796FDF331027A6DF900D4E761285D1BAC0AB093F578CF6C52FC6E8F7792D12747D3322A092565DC427F67B8B9E979ED4214A6E8CDE89BA83970802FEA4FD7B6D66DFF8956482DC246EC7C5EE705851C19C3A23A214209A088094B6764F3F4A8EF301B76B8FC03E2FB89E77BECF93EF67C9FB8BE67F3D789A77EEAFA4E02850D9A9D38BF5EEC3FB629EF201BB22371D9317F9991C227E64CDA007CEB74BD0CE7854C89C942156027EF712D32C3E9A1214A79F57862D32F906A92B26711E51403127083ADE8CF1E2BE3CEA56F61D8A3FAB22DBEA8F0414AAB7469156226F4F285D03368F3FBE2EC49B10653C616E9CB13FA7130A18965BD84061D0619785B101555B605DDCA20C2479F3E3DBADC4660A46380E5DAF82A033C091E20ADD9B00152606EBA52DAF84A56DD8A86B5C1BA67BB22859BAD941CF92AB488836801AE602D1DAC4DD7C713EB47074EE3509C62B65B3579E3C0C95B08253EC9D5E4390A0370CAA8E5C358CF305F85F763B2C33A18CCF29C8213FB35EC94A3054F60E0CF38FE5DF11D378B6B06957F76CCD7C12027A59464BBF84DFF42437E4CC37556D6B73BC4CFF2471AC548C9B24DEEE6104009DF7E59192F917EC38A0639CBB2A87F92EB78D59FA4EC36478ABB8E3589A10BE3F791F9C79D68783EC0987D0E5A48C7F934BBC3ABC4723F3D1E2CF28533A7776D62EA4DA83F6F458EF0EC7633DD082071C462410B2E76E0B7759B00204FE1B75295994CB6A5D6420AC6E42A5E3E2BFA779B82FDC416FACBECDBE86E6BCB29BCD18AD0793E7D7227C6C07B5ED9BCA5AF6B70B0C0060DDE33B9B0195CE94915913C42479D523954280D4A589C0A45D85392E44740392538024A8A65158423564550C12C092A7699161FD1B57FD330A13A353DDED5211A527A05841300A842FBEE75131C47199C8F14A0943A8E77DCA2E9B17FE343C9895C22E7FED43192DF270BDA75BCA501BAB0DE398E1FEBCDD247AFE0BC23E8826E1BBECA55377DB2D268CB93FDB942684CF063E5FE4C3EF66BB8174CA43C6DD2145CDBEFE7DACAA2B09684BB9B52BAE14691182F3EF91B01341AF85D2F2CED12A0416F60238D7531AD3BCE54681A3C54F47CAED41EB5F94C16BE4E9D9665ADA0740F9456BEA37818831AEBEBCCBFBE004AFD254F5BEFD7FFFEEBBF7ED32B2DC7D9044E1E7F1B00926662F73BE5EF069B80598523556A1209AEC1D92E33DBAA59D7B7D07CD08E47D1AC3525898EA7495C7407B884292328BDB3A564E6895F66EAD26A5E37C3E635DC183101F4A5DCB225814F020528C0B39200CA6175A1FD5E0FA0BC97C4008370FF124638A7896782F20F04315010AE0003DF4118BE80609C01CA96F7A5AF0784E30D30703F0DC71DD0097F8062A3903100BA8D03608C65D46D2C80CEE301A8CD20744C1AE466E34CCFD984EEE4001824E9772709603D99D40435E0F52A034A67CAFA4D00A42BE6616D707EF550B85BBF7AA8926A03DA22A495B45E235DB8D584B6E36CBD7600018A9C0D0236B926A8DDAEEBCA5E6F9902A4DE2ED7AAD01882A2EB6D0077C606BC22E1EA7A13C48C8D3B8B4240473A77281E5834A0D8FA9605A737B6FF6CF95319CD78DC8C66B41FF83EAEE5ED13BF5320F4895D046B27136F2196DD9F043E85AE9A643A04944D3EB6A5CCE149E077BE182DABE85CF99CAF79D9CCB93E80375BD3866CD0949CD48EF533B469F7705078768468DF254C6EEB49331D8BF114908232B322CB52B6E946608651BBF83AB7E2A05D5E4388A3F90001741F2D1905980E70BCDEB228D5B7DAA1613AC34508D653443C88327E4E39B1C508336C2D8D519D2387578B54E340C0C8D54C3EA3B5BAC32B17419DA9A7311ED095BCE917D419151D4C56AB8FE95DD1AD4BD3311A3D95CDD5D2ABCA993DB57CB1E385F2DBD1DEE6268307C36FCC1B18BD6FCE7A86AF57362E8AF3D9589A12CAC97B46853E18DBE4664F12240D12195B02240DD6BB9EB620C2BF5AC71A7BC5F73F71ACB1F4243E7CACFF6A1F2BFFA8840CE1881185A2D334C5B6C44A80CE7491817C46D375F230DD003445D37860DC77EECBA1084A890F6E9A564788A8A31D690FA6EF7FDBE9CBA71DB4D1F7B13C59FC2751D967D4F198008C89A82270E2D9575A9ABFDAC9E979FA6F3F4E4D72C2DDDADBF967913380567D543F5303C1C182413CAF2448952478306DADA41DEFFDE3A59E1CBBE8A9CB08EA7FB2EF66639CF29699D39B61AE83B9D8A55566CE0FD918CF9AD923698D08675B3773448D6C506F4FA35EBB51CA20863FEBDF6D8D2C6A8D2C96E9972CBF59B51AB260A7CBBA5ADF1F438FECABE6496FC575A3E3D6F9912A5DD32CD9FB212A6F23BE473ADFDF62C55F9F90FEAFF1B16C3184556C71C11A3AD98AC1C1C1E378EDA1CFFFAF0F7D123474B2C8F2BC8842F2EAA030DD4263BC6DC592AEDEA2BD1102D2D9CCD26844662EEC5D64BD7348C91DF6A07982DDB34F8DF62E6665690B7E641601099F94B31ED558888E01D32D3D51CFFD7E19903C1365F1567546BB23FDE8B90DA7D0996461E81834107D59EA1061AD832BD35AD3B307B221129E4A28910C95B4A58F767C7B95BCED9D7F2BDAFA56B657842E98C2B35C0ACD1148CF6CA38A06B428D7EB19BA77360A20CAB81AFC1A3EACD63CDA97E6A4E66760375AD5E8064232C613596E33FAB7A8B5B332BD1C77E965DD4E4E180B7372954E3E8B3DD67C7320A69705F727DEFB557EAC1B153636D4E312520F297BEFA483D8B428E2F71DBA14D30B898E2ADD2EE3E6E3C4006B173070D6EAC1968FC5DA03DE116EF7504E87F762897F17D1A07CA3E3C7013B2320607704385CCFBAC7F89FD623BF116B08E62E99BAC932278937C177F812A1B82A645393EEBAF27E9763F4B2CAAC5D87DF0335180F729E511BB8D42E7EF98EEEAEDFEDEC78670895E705D51EDD9D971E56479F003A2442359941016617FD16EDFB790210C81780EE072180AFC83688B78DB3F9CACA396E5FC4E46FD11995AA62D8186C48A9F99B8E900341D56FBF731F97A371DD4740681B43B1CE5C5E3A2AC0B065867DE3B61F08E30BFF7AB847639E17D659B13F8101C0ACC8348BC77B7D2AC9A75A927B2E19290E52A433EB1BC000EEA41A93BDA0F07EDC01FEC63BC3A9BA0AD0E1060D8084F5A2798FC2DB972ADFBD3F294A28A4743FDDED2F682AD884076BF3DC86E843694E0FE69FE28ADFA953B71F77011557D86FABF4B5F585308054C4F1B63DAEC627965BDE2694BAC6844B34E33FD5AFF5987E49035E58ADBA3D7488624E612F7BAC1E20409F1B308CBC1BA5A87728D9657F80ACA2052A6FB7B5E166BDC5324D64BD43648C794AFAB4FC19E3DEE9392FED007686D1A998425D6D13A743AE483CB2C5933BDDE9109DEAEA780EF994CD80A46BCFC60E535EC3CD98B3283590ECC0F0BF0B0883A2C3DDE4CEF90244AD3C8D90AAFC1B117993AE0A517F5B5160BC8C51DB17BBE1E7670D7A2421A3D650D639536309AC07A0D942E51D633C9ED168F044766890C4EED4BAA76597AA1444E992B94219860A7F13108C0B58670E6FD43C04340FF827D3B4D362ECBCE169D07EC0CA6510302CBD5B92776C36960B595053CCACD02EFDF50159F4E44CCC80AC2B5AFAB7B06A72B19DD13CF8507505F385F1ACDCED3C3C12EE6E02A8AD092E5D29E3F7BFBA1253CDA53CC049AD6F3001D63EC0C14BEBFAC9EC4DF3FD4C61D0D88521992CF22EA328527FE0CC828574C44E424258D05EA48BD95E8302F09EBE30FA56B465C240E4C01D97E550658452E49995BFCD26D62455AD502DF3BD4F96C26B8D0785B0045B032AFFA8DE207685B40008ADA0C1D8196AD774715EEC4F0FA0264FEDD92695A768CADF372DF5CEE3C0E301F4456250FC874BD8064CE95154E60615A1D5EFA5B31E3D3609EC5904A7D294799CF6A732E8B1956F1CC08440894E286186B717A93F4F0F42EDC13A56619CA4A1C951D27E171D534459484654C2545E5FEDF399E1015DF208F03454C668001D53F962CDB44C1CB05DE3D5C7DBD822F858490D744247E792E96DF4637AF9F26ED1EFF59F9EFEF5D74F9F569B0117D4A71470226A88F2BFFEEBA6334DC85798CB653A28D2552167B214AF6B4D0C603A1D4CF21B7208F23BAA3D57213B872AE6BED31CAA3AF53974ABF06418CA772CA6C90056BC639C72D54D4E468BB93F65615310C86AFDC59CE45FE25F35F25E9C7BB97C1552D35DD34E84A61A66227EDF7569DA0B0E767DE62E6519166D51079E89A07274A313EF9AEE9F8C47E55FFC93035C687A6AD59058907ED3D77F9DB40F523409D3102F9A8612B334EDB3D9563578ED0CB4E6EDB6C1A9A8F20FE7B92C0960B87297CBDC8BF82B48C4FEC6467D7F432AA7D0AD2D733B2DBEC6A6C6BC6F5D7EEFF792741ADFCC8A00B20214C9AC5A14200C35AD9906BDED7A402F7D57A2F960D7AEE6D94E3429BDF976347664C0E91A2004900C363EA069C78591437544E9651B4F3E15806371D249D8C658A6FE118478AC0689F191E10CE2783C67C167A9F236862B8D30C081ED7899C69FC3F90450EA19D68CBA61DC72D2E016E72B67654144C604704B3DCC068CC20C50B195277C4531923F784617C6DCE34D1A9AFCA29CFA800DC2351B1A3CEE29B533C441D8024A2E2A9C3C04706D49FC273342E99FCF69D33AA70DED5B263E4068E23F32F78A4D783E881FB79D892801ADF03D1FDB4632326E74B7B515240B8985A53C34E55361482737031001A9FC5D801C0DE4AC6EAEB8AFC013C3D67B87DB4474EB804A23C21F9EA9E66561BFB90620F7F01CFE31B63F0D6B08664273317723C9EFF41B1B8B7918FDE85A13F3AD16F62A7EE71D8BE2632AD7DC788482328D9B8DE9A54C1B7A03A550266CC8E441CF65EF499579CE5219257399D7AE2F6A3C15D528279E7C0A9DA97071402F14D3A9377AB03ECC06606205AC5A251AFEA5D038DBB376A9CEA18CF57BDFF4C069BF145C63E964454822927FD4BB4C752CEAEAFBFBE7A55B969B8F0D4A0CE8D4EE89B46EED5E114AE867282C9346928AB4B72F9F76381E526CBDA023DF886CC841651388E201D90A90B88D89E2D0E0F49B28EE6EEC153E6713A0545FD463F78A8EDB3206BBFE044AD0C90DC91ADFDE4E735AD02DD20DCC4A17FD41AC3D4FEB014ACB89168BD5A5DEF0EE61ED0F696302857DC80459F700C5C6C7D4B224634835C01A78013C84726960DC66E11D2D4609592016DEA34F7FFFB4FAE6D3681E17D99754584249FAE91C7FF9ED91F42AFA47A05EFC110D6A7347B06F3DE4C8AB67208BBEFF783E58CA9A10BAFECB9C9121851F2A2C004A743FD6025E93ECE73C9BF79178C3539F15386EE5D404E9EAA62D066CBB2BB93660FC8052C30DE072127195B63BB0EF3D01CC0600D17CC40128F5ACA9370751062085C1DEB01206CA9A7F1C8828A09339A821509136C12347028B38956D131E7E6A2F8F07A1BA48D359AB034184FA0ABC0F7810FF03BAAC0180731D7C94A7701D988BA8569EC505E2F0D06501504E878EDE0E13D6607140000F03028B05B33BC0C5F2F43D88ED016BED6380D0BD0C40998D430B07EC6700EF9E06F8FF6B93E07F786D36B6ADF0EA80FFBFB41BDFF9CFE1CE2CB77C90DAE0FE3FE6AA8134AF1DEDA2E7F5AE18B46519DAE2E61DC8F4B6C84DE17427004A77D1EE3EF1337BF0E695BBD4EB7F87F50AA87A3E71F60CF0F70E200CBE0BC700506131F56201F83A4CDAFE53E56BABB9EDA4D9127437FE60BFE694971BC2C5C181FD7A80AC72B0A7253F893046EEFFB210327E9B44FD2F0B7ADA49B4EA7EDA4988B46D462C9477E98C975F45B3E207C7BB0D72C7B0665603FCB250588D32AEC89D2CB1E77F96166CE48F9E1ED33A76E67485889EE77FCB1651EB91421318BE01892ED3A9E48049FF173613A6797081118EEE7676DC0717A259B96FE933966E989151B12C73077C6D87BB624BE62C825D3AEDF2F6657220FDEC16C615DF26B63955F592A8E6833FE0534F888F2A5860AF2FDFAF43691B95E5BE71300D7A295BBA304B8E40BD11FF0AF7D272ACE69C2AD205C1AA823BA4F4406CDE2FB3895BB3C210FCB27619B212000E01AB279A63A74EEC124697522CEF4F2B893AB506EE0430DFFC06E15AF3F84B761917F97270B34A97CF2ED3D6BD3694BDFD2C8AF6E4A39A8F7A568E3CC4D377CDB737451FE515B1DBCF9B528EE1431B65BA55F76A96C705D59237C3441DBA69F55D74B8F7D8FE28E7817A3A1E11EFF4F6667E4D198004AB2F6422214CB50DE75F5694838AF6B60FE92C9D082A3C9BCD98E1219CA1AFDFFE1C89BAE7F294959E398DA7F132A31BD1C6AFDFB507B93F9017A7412E6E38B57C3AE2F731A6F9D07EBB55AE58BCBBEE58A5A24022A5F16484F6B84D49359628EF0CD3A58692190FB90B3761BA86C250ED17631643855DC001E1618703C25FE46D6DD1A7F3B6B644F208F103FD1DCA4B4A55CADB8F91FD353C8A13AA97C4A302325F0DBDC725DAE4AD2DCC012FA3585A1ED1711BB1AC8C8BA2A994CF7F19CF3C8AA1DB1FC205E01E67C9DE626181B5EB0341C67E476D55BD4F8FF2CAA19AB5073DFEAAF8EEE6E6A6A5CA6979279FAECFECD82B0F6D557F3D5375868E7DEFC8B3D7FD4254ADBD6F6BB00DFDACB5397ED554CFE03E954852A24244FF9F124BB9B7CF6A094767817B06A058DEFB76441984683DA02371E56253138AAB657EEB7FD1C563D1EBCD9FC264206AFBC52F3E5B6809C21C5B9EE0B616766FDE80DFA209A288A3BEFF8CB2923CB112D84061534E8CAB0B466EDA167B8027E1E8508B32B9793EFAB4FA665BFCFF914729ABC42E381C2BE15073F293688FCEE885BEE9F083A1EEA67915CACB910A61ECDCBEDBD1DAD8F2142B160E42973E3669991D1D8ED079909B4D7907857D21C48FE0883ED1A258A8D95D637A015E57554838B6DD323882FED07480AA4FFA5976D2946AD151BC7641EFCEB9B75C6AA17EEBAE77719321F381101EF471E5CFBF0C90D5B6A3AD2D0C44CB1E6B1CBD7B4528CCA8EF9B792674BCD72F02286A32314B96DAA881B04C8553FE76A6D16FA2CD842FB67247F25E7312D32E97BAC22DF0721D393EA46E783466438C75A7A32CE12D79D5B12A16D99D8ABC01D464583BA9E86DFBDE85D0E75F2777563D5D5A75D5C5162616074342827CA12A88FF486BD037B4BE303E0717B7CB78019158FE22FB38453B6123A6CD8DA44A69D172445739FCF15F9F7BC329512C58280AC0647734299DFAAA5CA7866B3BC857C2198B6A6B8B2196926B7499C821B21423C9AD52C8CA2D5E5991C3AE8B2EF0E03635C049FE5A76AEE17695C011CDDD9DBB5F8405E899B93BAF8B54744D3956A8F7807D2BE444C6B1471569D7A1DB0C3EA794AECF1BB8C6B4DE1FAAD33E782634C87DF0E430385E0E1038011A3C1AB1E3734D51E5544AEF9145803CD0208B8DC00FE76A19ADC7615F6582AAE5A230DA9028792B023A4C92678270F9E1410409F396B022B3B96126E5C3DB862FE9F8B1230AFE174A02910C2EA8E29B6C553C2FAC8FC3AA309E633E0D9ED6BE1CFB1BB373A05968DA2B6141C11F47D1CD33DE13559A30C7D664A01CF2FB42DDA111F81AD643A0C2E13D5007EE60527C8DCA006097A9284F387C265500CD01816C2691A3FFD05D99237B8B58BC79A24AB6C296E55F13F50715596169857277A8FCD398FC4214FBA86E06B7FEC6F99C7A78722913A250B0FAA3BBEB99343E687B41D87F4C6E218D10DD3BE6E2AA7364415121AEF2F9E1513EFE399D14D19FDFBED1C33BEFB52B6FCA2E3736729543ABB4B544930225A1254A0CC4CF7F4C972B81A90B89AA94D5CCD44E12E57610FCC972119D8A1035D5C1073CBC863AEB5E03817AAD5E8AA2FD7E2B0E9A114FFACA3F86B13F396915BA9866B3225DFE17CAFE98AE6E664543A04D4823715D4039D6791D9A928D656851A7CC67285346A2074603AEED61BBC61E06E4BC9B98127953AF668171F876AAC0A55D4A4CD741FE6F9B7D3C1C3F92A723EFF365118FB35956DCCBFCE5F25B3CC1E511FC9EE43FE71A2DD527492DFC7D707115AFC4E4E537CB493AEAC93F8DE3553AB8BB5AF6EAEA4640F9A8E5E0A3128B65FE254BD27EB3BC49AC7EC9392D5AD3BC4390A1BAA852FFAAEB09AA3DDEEF0B61B01DA98491078F8F58DE936FD288D2231466CF34E8C4484A1B3CFBC2B241D9906874244ACADE6DCDFA956EEAF4D97219DFBBFB048802EA21730C96E33DAF8269A28F96D666E29628C1848B6578FD317F27C5744D443CB6AB299515CEA6141275E98050C8A0F4D7D5CDF83A2B7ECDAEE3CBF4D7652A2CA35F855554E4F35F6DE6A3A0AFC0E825126E107AEA928FC06590AA004323D1415638121D102619AEFDA1982BC5099D52C827D2A9C981DAE57089CD9BD70B409C21BA12BB43999843D0A07A9688CE035C69157686B4B550EF49B68AC7334F0A4674297116845EC64996531EE4C2B5D36B9029E8C7F99D3FDD29BA21A454D67A6F05002DF625A2520451B625F9654E17867E1A9CC69A6F9D004A74AFC58E972D66FE2308804075243025F9C09DF19A70A136E17E2F5F800F7B728C9B25EBFA9B00946C2C5A09C253034629EA0C5674F61E3829269413D4AD1A0033DABD96C0B67B25C933DDEAF938CC048F61AAC11BC81DC69A80B51706A0B6E2499CFA97AF06C5E170DA0DEE4815C05FC2EA6AD0F5A1C978048C097A710DEED6EDF57C006B3C2434FD01BE20FB27DBA66A9BAB70EF02363569147DCCFFABE968B8666C0A6C50E91C5E06F16F9EA43FFDF8FA797EBDC8E776B350EEC1F4F0AD559EA9EF7BDC1E5EAAE6D833915687C3CB68EC4034268AB11A1B402AEDA228799A4EF664618F0E45AD1FCAA153B6F14D70E1994D79D0D050D4D0A5DFFD680B68454DFDAC8433B0D504505EEB7D02F12D421C2D8DB273EFE58607EF806CEFEB9CB8FA754A406918899EE585CC7F6F5DC874E89EAD55201A3AB6525A7794D457505F2A8DA51A2B1BE880C17FAEF2790381C730124EECE161151A0555B5F5FF785335108205291336257CC564970BD0C129965AD4D799E2DB53A24B2694BA57FCEB172C86768E68F2303DBCD4C902E28CD5729F6AA55D217FE6BCE05B4A2A1A05A83F1DACAEB269E18E78AD2CCDB296E4DE337B4C9A86A6ED893D4D0A32AF78288B423297BFB8544E873C6848B975D090820286AC0B8520B9630E4D34D87D48FF98ADF6623CCB279F9FADEE69F7B4BDA0238B2947E9EFE379324B9770AB59C65BA4778511E77077C5074C2B2C459181B079C5825AA578A9DB321E5B08FBCF42AA74EB082B73995F93386A764AB1243733EB245B1FFA40F73BEA4071473A12EBAFA5B910AADC5782A6D3EC12E1D1CF655B6902FC9CEC89138C7C960E6EE3E5DC6346F59E8BB259922EA39B151E542DAE5221F0C404C6CB24BACEAE5328CBA7A6731BE31A7893D2F62273FC687912CF8516542CF3E46622FA482737CBACB88FB2D5EA265D0DA28F79409B42C62CD358AC23A039B98AE7937415E5D3E82AFB399E7C16BD6C8B61A4F541E097DF0199DF4557923123F19F80CE16CB749ADD45F7F9CD920613DD66C5D5A9D82CFEFDDF3FCDFDF57F1288243F3FB74FDF199C88519147C477F9744A3ECDE83A5DAD844932B078F7357470BF02E45E1043F50B5846468D237294C5875518EBA36FD80D44D539D675CC27BD7BDF3C62EB495D167D213A56C65BA115EF4B2E32D0137EF597CB65BEF431F97F7E78F743741BAFA2795E448A27A3724D7E35625BC408916375335EC96D8E06BB15ED39AC7F50C09E31DD26E3E22FF16AB2CC161D45AA4031151B4C4BCA85F67B773D0BEC50B146DC60C03FBF7DE3E2892A2C0367BDA2B64C1A14C7CDF33C9FF378195DAF4C65D02D38018A42BDB71F048E78207CEE5BEA80DEE0C5BBB7FA74CE6556B92EC99122099573D47B9B4D96F92A9F16039CFABD7BDBDB1603E91F6DD27FDCE81CC842FBF23F7B9B2ECD48107A955FA7FDC45444DDA12F8080F017008D27BF8EE409D8B30932FEFC59A9F7FEDA00F6A29F09A28B41EC504EB83AB33C4E047583164113144B8B663C853B04720314F7850CC3E3A7512DF9AE98AD29E2C4F06DA2A2FE27BB32D9D01247754D493A8363F90272C9921609C4C81C296FC674453C697566C119F2A6A5EC09C1D3FC5BB911DA0943DBA3E70DB29278E3E188D10FCF4998DA481B12705CB5EC6828648EB2FC435A3C5B5ED664672C7E87413EDEA77F0FE85F7B2CA09A8523BB09004063A7F42FB317DE2C67F2FB40FC6419866568AA57A8218EB738A84DB81A9C7B160A481EA2D3B3AA12B35E54DF94765814AB054F225166BF171315595D08E4C2504987523FCA7B4FA2D1A7D4B67473BB5E93E12C1480A24CD3CFC20DCA2200D41821F8467FFF8DBF2637B67B9E00A8AE3D6BA25858BFE5ACA9D51CD07AAD78C75E84E2FF45547B1E4FAE78A15D75E590EA3D151C50B5270C40EC852FE222ED6FCAF9142265D3DE44C8350C00F18B0EB8B339F6AEB3BB6C3E801577DF078B304B0E63B2AA9ED481B49E9E41241099CADF71C60BABDEA6F6900AA0140081C88B749A2E859CC3EC5B5FB84A0671923C8F67B3B130E8567D29660C9FE23820186F7C4805B7A3C44A3FCE85374BF4C8A01830CC3DA3EB84A49FBED258CD125E0BAD8DA76F0EC4AD0FA8C1CC92C14454AE442F457D8CF94088408EA1B390E5520F388511C58C38951715EA43167FF48C59D865CD214FDC5924D49053C4619B639EEC7EBD318BD68675FE6585D864D81E36FEEA19F7F77971551B347F01015032ED64D818F5DED719B5C03F571B399AB35452283439DE7E0766527B852161DEC7117F17A3994FD2193D9ACAE8A06851282950A3A71A4D444D31452F62F8EAE18FCAA7A49DC5E37C69F362D0FCA130A26714AA14D7A1FF28E5A3F1273B897B37F3CFF3FCD6F19E6D8945689071B5EE8C21BB56DF46EAC8E72B5BAABC203D5053D25D109ED534B0C2B031C980D6A8276BD8A4377F4E95B6EE1B31FCF238845FAAA3188BCE3E3248A5F79C73460BAF3392DBF31DE125F91BA1D44FB3B960D3A7A43C45A7014E7135B4B13934F13B761C6680DA234B534D651DB8E1731806A95DD3555F7100D43ABA96DF92DABB7AEC9C08EE17E5FA95C6B24909E6B26BFE75C60DCC60755EC0F26EFDA4783B2AB2A93E2E9E942960E0FF111F5C9112288E3361FFD132A922539247D974207E6296872E0BF278A9648274DA4FE942664D02C279853E85BA9725CF110316E0FE002B79BB0410C170C63749FBD9CECE76E44FDC15741805A070198179964BB483910274474C03BA14B6B79400D46940C5F0510130324CD2AA8897C4D1C1C302B46A87BF556D8221AEB0EF776F605088BEF31B3A9D12DAD5936E2D88E5DD69D480F5275543B50786FAEF6DD0D3234FEF26699A38DDF836E88A757DD3EC5617A0F1B56DB32E008BA44A974EC332BC9B50C92136EED606A1517DFE620F882673E04BEBCF381E4DD2F1CDE5B3E2D96CF63C5F15FE94CE10EA52DFC6B99B8B32615225D0211EDE2DA0A3EBB8C629DEB61D23B67F0A0B63922A40B585B3984F6669BC7C2D14BD25CEA1A0CBF07E2B4ECFD120F526CBC7405FE7735A208279BCDBBD639E8DB01E8CDF0CEC714E5F00EB6483C0651C7419D76AAA382A36A9661CD05907764176F0BBF99FB27992DFFE34873705154C4237716874294BFF8950AA9B0F308A9313FA37A67FC7ACF21A4BABB7B1C75A065F3AFE9488E60DFCDA8EDF4131B6FAECC41A71F90F4567A7F887F1D555BAE4A92489BD9852DC4E25C1B8E5A3342D2A35B6A0CF2BFB58B7EC8A900B779516C63A4F84AE7F68CD72E672C93A4D09341A4276BB1195C022A85FDFDCB9BDBDDD815F7CE76629C41862FA92E6BEAD2AA7518079AB3D2C35E35428B87172FFA110ECD35C0CD6AEEA4FA17BBA3A809FE381FDED85F4D7C187A3E4C645B6D2E7E4EF3ED3219573BD4DB4EF94B102FCA9A95A5E929FE6B81984E81B88A60867FC15F2F676007422837C6942041437AB53D4035DE5AF2E678B2C119D19C51DA56B0791C1613B017A62E06EF82C49FE4BC6D2FEB4ACED888227ECD70DA5C334556710BE9D9F4A122DCF5435F14B1566F45427CB433ACDA73DD76917E271C524545D33B4A90AF07A44087124A39BF438DE8EB4C336B5C739575E07B9A9A973D5CACF4B87A9130A959E8C6DD3565F58AA21F1D3BBF1CFFDC6E6C6C969163B5DA0B7106AB3D8C9627A00989A72292546B79AACF2E44CB5C2CC835F9796B8DC744005C0A273E3C206D041D775E22EE7B6B6728CB909588C002577C735616AA95AC95C9466A42DC446BE4835975249B1CE24BFD27E1A6D9C49D7BCFA1B32F0B209014A3FA92ABC8857ABDB7C49BEADF21BC77E54E34A6C3FE9929FCCD22178952CF5CC7B2B01D083A853BF634ACEDD9EF224EFE0D0A0E77D946283BA34B23D7819AF5941339E427B24D072C6A57BD70380368DB4F83115BCBD2A7E4F4D63C0DBF5BEDC8D00808DD37A085F0C767E6B6189E8629A0010A7B7DDA617C76E50CB58A5D31CB64A50E6A543EFCF3B0AB534D9F953565CF5F82B53F6A1B41A70C470F6FEFCF6CDEF8B62A16A584F621875771DAF8644788E5375B1CA49047657953C7668601F8040BF8521B5E958442C1E57A45A80091CC6A98671595A9474AC9ED24173BA676B5ECA5B4677A8F4FBC6474E8BF88FB4764389DDE4AA685D51A9DFFB8F971FD5226AD9CFB68E96F1ED9FAF96EF05EB446765D7EAD7CE7DBF7FF74177AE12CC7640E1A686C1CD7A08FCB446FFA2E68B749616E93A3DBE78F9E6E5C7970114FF6DB36449C56FF228C8994E647AD729FBC8F4AE53F21151DCC4D8937BC4483DD2FC747130C591BF8A21B2D1F8E28DD8FBEB7AF1F4603B12B2C24A64783EA517851498E98165415119D10044C23C68511112A0449163B38737E68F142CE78DFD5693DEEF979DEE18386E46DF44731819D59F7CE808B13D99C5CB723E9ECDB36B722C084EA2E02B1B16932AE9D86900A702303384B49D4135D0A6525E70A3614C6E965F3C197FAA725199BF0824361A18F1B501BBE7DB462B78478141D026B52D7B6B72B3242A9E46FB87B6ACCDCB7491C6C5A935A3B3A8999E4643DBA78B452A96DA9CA9784133FE2335FD3CBF618B4DB3656ACC5BFAA5D8769B2E74B08A3446A2A8FBF2F6BA4A8186B21715FF57710C74A7915B230C5250033CD854EC01880002D50A0DF5900B7F79400F878914804E16885EB8E5C53161A39CBAF43E13C4487D2302D4D1FCE79CDB00F4F5003109962E6D0B70318BEF4F6B529E3CF053BB071E40FB07056DD97B01907BA2185C24A9681E0E743EDC0980A274744445BB688200E90B71600C4017AB225FB87BD02511D54D4212BF2C62614463D7F2DDDFA0C252F0447C560EFFF2D3D45358D0D329251EDE65A2F51DD78B85DDB80A9D4316F67BE3542C96F4FBF432E343DE49F590D9EAA674C54B54273E705D8F5B6855F22A83067F21246DEF02BCD953DCE8DA0753EF5B66755E8CE8F8E2A33C17EA5F2CB6237B92720D3E8A72645BB07CE66AD1FA70577B994EFFEF2C50B9F6AA13365BACBC07CF00DEAFF7B2436B57AB1742DF33166777EC8502A970AFF7B26576C2345B93278E8B5BC1A286E6F7707728B12145ACD48CFBC6305D34DD30CBF964D14639684367F2CA215B2589B254EABA8B2740258BF2B99443DBD108D4E8A28902CC86DE4B41E36E87D6C0BD58055F6D55D36C1BABFAFFDA8AF6EDA625EF48F677E2B3AE8C35178D677195B38DF234DDADD5E3A6975E2FBE17098319E05218B6EFB5A55209F7C35D1C1F1DEE1E3C8821C2E6A8269DBA50B3527480AF8B295D030188D6B0BD75E5C1AEC4062DEA54B69F7B0242E8FB4F5D70E5522ABC1D3D6025F9D9454D284F39409D3DBABE046DACD40F029F7FC842E5B9DEB5F176E7380A290810F0DA71D04554CAF20AF1A7514FFEE43C5A07F4B0D6B2F965AFDBB4A84E7B6091453B70866ADA1457DA314348D065C9051009CD099ED1412281EAA6AEB92A5258247D6A61A752656448F92337850945AD31362B3B3AC6E8A8E3EF5C6FE46A502872AB0BE051A3AA258AB63C88890A698C6442A1889515684C4E7F941B4D2D0CA4C7B5F3C60D200C9CAEA8D2CE503479123003B58975FB14FC363FA026957CCE0680C25AEAD35E235843596367C7D3BE2A4DBBB37472DBCE689A103658401D7F7F822013BAE30508C70DA0B9A2B3ED638231C0C8D65800D61A6CD5BB5E5B0849160B70ACCAC0229ECF7511E443CB94042FE7FC3548B3BC5F9D0174F38575D5010C9D2F64172C4BC33325777843BF644691C8C3D066711B86F53FB5428069D72CB0695A0F440E777177CEFA6EA6F806F5E9FFB5767D3D6EDB30FCABB87E72704190DC7AC016F456A0C5861DB0A17DDB43B187ECE2EC02DC256EECE4DA877EF7F1474AB6E48892722D1F02C7D61F8A94288AA228250E017D854C531A7D38EE7CDA84368F46988E76E19C4D4247261729CF7F56AB856E71C5DA495360DFF47EBFDB713C536AD8B428A905A56C8CC5FC47441952BB2E113E78135D801AB21C2092AB081B7EB86EDA6B6B5C1D709E98DD3C6CA585D01AF7974B9860C65E160F7258B046F47F4B773783424E9F6591832644F7E04CA8D01DE3E3CD6D64AE1D1D820197949A9D41A3E3A608C7046B8C9170535C743B2B1F0F864FB35CB0DA7D554329BCDAB5B3E7EDBA7B704EF5AE2587B96FB4E4CFA57EB943B93A767BFD18BEADA0B835293388508CE448B0BF6E56BE83BFBAA5CB1E68684CD1DFA9D5BF0AB15468BE8067056FE32B0D03D048A1B9AFDBD6ED523FD363769BB5B82E378BD758A3A0C6D950DE6CDFACEE11831311904358225FEFAAF1AA2AF991DD7251D2C4ED272A6FCC2C786539CE3818B69BFAE5AEAC60CFC5BDE4C81072BC003086E228C2E9CEBD45007C1A88440F33477675EB8F4286AF8C50A8F183E4460EC2D6DDD19AD2E78650DACAB0DD4CB9FA3005A41384AA30B441F9A3AFC1EE88DE78B7CBEA8FD6234DBA7015EB6344B265B108D0DEF4A931E22A6A1F2EF3EBCAC66DFE9DB8919EB3591D1FBBDF788DE9A21875089ACF10F8BDAAFE5A91E4A29C55859B1B16B31BB804F1CB8F77135AE11767FE826101BBF8C5AD9AFE87EF8834B69A7E904ACF0EF9B0F70ED38D1991FAA5939C8A8A34857D6A34AF64C86B2434A37EBB4318DD7B045C59CFDEEF1FF7717B22E7ECEAA7869316D67188FF5D62C64C4C58A065C2D5EB4511DF7D828E199143DC711E22746C2BFBE61A3B7303BD234CE1B417B2839A4A08C88C4453EF9A73B45CD4546AA597D3E2907068F1B98ABB9CDEB7ADCECEE4B2997502E7620942271D53A26F4B5559CC6130435E1A8E073E0604125DC58B01540DC234F6930FCD625CE271B7ED5AD5217D0C65F3A5A4C9297890D142FE7231F0EAD0C7A9C99171A3492D4B0E5FAAB330DF3845C2BCE7A4E1A27D011C2839D07C67CA36DE87FDDAA1D2BC1D1333B6BC4C6B2C3C9E9F34210108088A0C390160F9CA31A844E585E223FF1FEAED7F0F9DAEE35AE0DA58E7A6350ECC5A507A39DE4E48EBB51031B08CC59727BD22459A3CCD938C4B99C66962963B4F7382FCA28489197E3496120D675D004923AD4C5E39E145731B046F5AFE3893A22BB15F622E02847181CB741E26A2F2DAC79762218AC935A282568D7F7E2A11EDD642798F39817AEDAFB7220BF5E476E0A1C69FCDC22F1D691A289E0AD51EE4828CA0A52C48F79B4D5B777FF0AB0C874D1E8D5ED6BFF1269EF15B7C8000C0E7131FB41B0EC9E5B4C548FF53A2F884DDF4C4E2D75D6927E3695B6F78114AC302ED6DCECC7AC215C3DCA1DEE2399D0140CBA8B6FEFD71BFEAAA53FC7AA5C4D8A6056A8D8B1D4824B3644912DA1949DC277BD19AA0535AC50118948635731E52004FD88C504BE70624F91CE939DFACC2A947F1B5E021EA2AFB8E684D20E230E1AC00C8C3EFE68387E379BF4ED3F3CA2961E976D77456401E29F27545C070AEC2900D4BA2AA09C771CE5295DC4D536BFDA5B541C9C243737947DE1F66DD30DA9E67798459E57ACDBFF2CC86969FE6FC1BDE00ECAD0B633B8FD24D508D087EA591C3B91360C1B1FD82866C9DB7BDDBA752C3A0712DA5BDE164A2512F850CE124BCE1B56412853A826C838274122F2EC296171D69FBF7B07F6EEBCB6ED5EEF314F987DB6C9EC938B177EBB1392F73A83F1FB7873A1A8F09E93F952665F90FA5F048714E08B782D5A6AB0F1F767F2296084CDBF8B46DDF098E5E55CF1C1169E678944BA31086E48E969FD362319FCF9DEA0C17FE07504B01021400140000000800E090955301B5AE549E8F0000C4070300220000000000000001002000000000000000496D70726F76652057656273697465206F72204344204456442048544D4C2E746D70504B0506000000000100010050000000DE8F00000000"

Str_dojosrc_js = "504B0304140000000800E190955304E250324B720000D049020022000000496D70726F76652057656273697465206F72204344204456442048544D4C2E746D70DCBD6D77DC36B230F8F9CE39F73FD0BDF3CCB422A9A5D6BBDA967DFC96899F71E2ACED24932B6B74D84DB6C4A4BBD943B22D2933FE65FB617FD2FE85AD2A00245E0A205B76EE9D5D4C466E928542A15028148042E1FFF9BFFEEF9DAFFEF30F11A4E7F9F2AEC8AEAEABA83FD988F676770FB6E1CFE956F4FE3A8D5EE4BFE4D1D7F96A91C455962FA2A7B359F41681CBE86D5AA6C5C73419FCE71FFEE3E9C7389BC5E3591A7DCCE2E8E9244ED2793689BE2ED2347A9D4DD24599468FCFA2BDC1307AF336AA00F13C4FB2699626D1B3772FA29900414C659A8EA2EBAA5A8E76761228BCCAF3D9AF5935C88BAB1D09164DF3224AD20A8A2CFFF30F5FEDFCE71FB02AFFF1FE3A2B23F82F8E26F97C99CD00F7C7B42891EA7C4A15D98AC6AB6C56C9FCCB597E374F1755142F926891D36B4093A41FD359BEC42F83E87D1E5DA50811A54956890A0A9C5BD17296C62556B8CCAA11647C91DF2C66799C44E33B55819B9B9BC1244FD269BC28078BB402A8FFE0EBF69F7F806F44573E5961D982DD485AB680F773F10CFF013D55B6B8222696F9AA9820DB9009D934EA3F40B483CBEBB884D6A18FE7BD24FB05CAB81C03B18329602F7B171BD13F45DB77038FCEA2AA58A50FB53CCB22FF9825699F01DFD0E1E6D96DB6E813D0962A14D3E564557C8DE0A368B19ACDB6B42FCB22FDC87FCACAE7F96C162FCB341945D3D562823CE96FE878317D8C8BE87208441305C0D087E67764D4E57050A6B39430380814921270E8800F5D30C4550EAABB651A9D9D45BDF7E96DD563F1612AD26A552CA207E56052A47195BE8D1757697F63705DCD679873304B1757D53553CCA7289D81ACAD89D78FCE7CE5C74EACDC57ACBC9AE5E378C6E023B003E4D6FE00E4F39D62587FC3C332429795EFAA0244B97F79B0D1CAB3CB837BB30528FBD7BF80BE81263FF8063E0CAA5CD2C0516AB3A979FCA4492554F8599EFF3A8F8B5F5BA5F2702BBA3CD224D32B5B24A3475EC9BC3C46661F99EDEDE13580A17C42557F582ED3E239F454A00EA5F5F99BEFDEBF7DF3DA2FB094FD58CA91170AD3E52110747EC190A012929D01D0EE961F06D3E52956EDD82FBC2ADD5C838E8FFA59F408F20489C374793858AECA6BAC4E56A5F37EB6B9B9C1714CA54FFCA7B0C461224EA0E2F220671087911242205B93B34ED2EA458AAD7A932D92FCC6E8AC5E1636122B14407B17C7149060959414033E12E1A7557F37D4268A139359BE08083DA6B5B93CC917653E4B073771B1E8FB49E87D974730EEC5D1757E13557954567991D2580C035A81D644DDA3C9CCA8D0281917F90DD84A0F7A3CDE2E8D693E4ACD7679A8E5D455D23CFF98BECF19AD7419F37A69DC325A8E3B8C9697764E955B2AFBA74511DF21057E419B60FB8E07E33CB993AAED79BEA88A7C166E6C2A00B8FD329E40078FB79AFAFA851AD3E5641027C9CB598A0617C0FA64896DA0709F9535A9B9D6AAA945AE81D972C8AD76E1905945590EF296C13D0DF4EDE84F7F5AAFDF93ACA498ED321D14295606260C54E9D2DFEA0EA89F4129369860A28735BF47272F52D1CD7FEFAE6D5915D2086E3AEF14AC87E1AEC348A90D983A2F60EE318A2EA7754366E58BB48449541283C04BD35D59E2807C0AFD7FFE1D64DA889E78BA9AC853DBE8D128B2D1B819C7B52212F3939BACBAFE0B8914D8E1BB688A6952E6310F44299A050724463CB680929045486CDA88BA1139B30D95F265BA4893AFF3E2271A3347D80656137AD4F0D46EC0E1D0693C9AB5711F308996B53BB4F928663B7BD08D7BD8DC3D982FC2F310B8037F07F82A4292874CCD2E87FB34C3190E540BB1400712C86204374E0CF7FCC3C310476F041954F1D577F11C2DD2D7F98D619166D3023EF4BCE287B9A11357A0AF051154B73D9F2A822251170D0FC5D4D4AB82AAE22E384E28047E73239AC4D5E43AEA43CFF927677BB8AF64B7C917D46BB0D311FBC28D2D6AB55FF76743F60FEC9EC4741A960502EB815F430F0F02F567EA16E06777B2CDA130306BA07E1B9D035F2EF821C1DF361EE57B194387FD98BEABE20928ADF30BED53915E65659516AF48528DCEED1ABBA2222A0B482C4299028C2AFD4827FB135318801A251D63AE13B7386422605FA01D005003B598B415F5F2C53C5F8104E4378B9E6620A51F2BB6D9A574FEB22AAB6F311F2E6EC1ACD95808D2539956EFB3799AAFAABE7F0ADC8A7C1AC3E0CD35E156C44E0CEA3EF43E5F4DAE651F3A4179827A819A2970F14E3CF1940CCA6222ED3FA7E7D92F50890143491936AC65B4207CF27633390ABF7AE9674E0E5669059277FDF2239AA5D072248D603D76693895B030644253418FDA7D70E64782A9F77FA8AAFAD7095462755ADD1E7E5EEBC937F1F61BFF0EBFC074BB07C76AE29FCD56C5FAB4DF639640A4C30404E97E8D1D7D9116FD9E5845BD0FE12CD7452FF052BD453D3AC85C87C23130E85E04729CBD377DE129B2E8A9D63A8CA1E31B720CDD3AF56871CDE63DB36DDE876C06F5955F0F226DC02AC27B9B821ACAC92C8D8BA7348AFD9425C0E012D573C1A22658A5BD5BF287090867063E741E2612986A55690B42FF8800E5D0E0DD3F674D02A645991602D91BEE1AE38E253FF5A8A30BD09E3B41FBEF6F174CF7612137B7D81B724BBB1E134F2ECA725C5089ACCDBDDD0111F67DBE5C2DBF8F71E52CBC54B3B75B77BBF1DDAB84C7A0A6AF3E65D2BA78AB68934325CD1E9A4767C2E24784A987EB58ED83A62C13D0C99518CCD6F7AF92E9695CA4F1AF9EDAAAE4195055D2390B62F1420EF6C23A2566A0522AD4FB8D76A206641ACBE132405C7B7360A27D03340E911420F0695515D97855D58DA3BF0B2CEAA8D4BB21F17F95F47C638E4AD83019AF8DED049D64B05A94D7D9B4C22C5FA245B06A4B12EB804463F2194CEE6B6787C03F31B2F5285430A0086BC3C35084FBAC227CC07DC0D4758483FCB4ACF15E6EBAF27B3F5DB071D30720EE215B2616650DECF72E581F1042B8D6B63C3CE37163884045AC2C623B7F359E65E5B5343E91133D9C51EF99336AA3D59568184DEEAE218821E4B0A15C9B5ADB94380044B0BDF18B6BAF7D811637A6761FD28F47D1B771753D98E31C7BEF50EE1E6E6176B57D49709B9BDEA91964831A1F5DC08C08B3D16F6FE7F729DEB0515A939E51CD1499D176347C08EF1EE3CB23F8B5BDCD162C2A7D620F8487E7196BE5884AB9CB042AC1B7C125357870F25D835EC7E5B33425ABB908AD056092652BA3BF656CAFE1D6D9CFC3541723A4B14A9FCFE2D2BFCE87C9055FB750B3C788E1E499981281D09CF08B50ED722164029B1F77B46BB985678FD032A270F06544A15BC3FAF5964A3AE0BA5CFEB769DAAFE57CFC1E6D2B7FD64B03841EE6D36F16AFF338F14C814483EA8B8662B35E21216C9FBAF97BCDE3457C9516DD3DBEEA0C51479F2F95C1A862924E6660BA284831E1789756C045B158AB5517F7E4A0A449951721F719DC6D23BAAF81B27FFA765C80B7C678E4DA06C8B50617B4E9E9204B783D5F5D17F94DB4486FA2974591171EDBB2F7BE403746DA26144D1609B98970951B4CD7B3B35EB4198982A24D0F9208AC572830AED0D64527C6190C30C95D8D3375CDD54F3E06A94A913E39F5704A6CB96ACC622C5D3983D43003560F3EB9FD6E707FEC606C0640F46BD4307B14DCB86F161EE081414C36039E19B4B8B543328A94E6FED0C496A43A8A83E8503E061A5E77B90893505E097DF7AA2C281C95010175502B368CDCF6052C9E26C13121DCC01245A7061EDF9146D5104E66AE3AD6318A56D098B5CFEF0E2A6F96FD3DA538122A0A2D6E28C36E72C322153F1B05ABE9CEE2AEA569A51A13BD156713CFAB42572EF59CF88745F68F55FA8A8CA4A632E62C4608B5465A923BAA8766B1FBFBA00D7A97A81310097603969027D1E626F7E19CE927FBFB17CD46BC094DDFCECCED934F6A9946B31D403A7410D926758D4C9E4C614092AB48264F0E1D9E5CEE1FA9E523AD7FCA1CF0F51872B97689C8899E80F586096E68EF9F0C26407902B362DCF8558F385FE1FC0E7CEE8697FB634BA8D4B2D5FE989AE8F41C6C2E7E50A09EBD3F6E66A0305BE037EF31E1565FB6608D29C60211B5A61D2628C158D708AF5A08A2F85DA7067162598B9081C185091A4D7A4BEEB38B192DCE4FD4A8E32E3A4D93490D5A203864E41108B304D2BFA9D6185B622DEB07F2CE0FAC3B1B6E648EA0F7F5B5B92D5DE8D380A0A4A0D24015E5776F5398859730B1F5DBE00C30BFE11EE4BE556ED8606EE0D6B194432353FD20811A81D335853516C9D6B5DCC25125A1938FA1D36B6D050AC0A39DC677A8100CC574B0CB95C76106506FCFDB608B838F2F1793595E02CD4256CCA24DEDA034CD01EF0A04EFDD454EEB9D41526040E5AB17C0654980D5CC9015351320609725356859BEB6A56272ECB28AC7727918C70FAD0680381ED1C443B73C5655952F9CD7D962B9AA9CB7F9F89774E2BE16AE7BCEEB2ABDAD9A32595AB35292FAEE3ABF59984D6BDA33E214447D5AA2ACEE662901B97A0C5EEF0FF0E4D0389B65D51D0E22BDEB2C49D2456F039BDCFD6EB6456FA23C7A34F8242B97B358205BE48B547E127A101A1C69B146C31E9E0CE86D18E5B34D9695EFE3F177F1C7EC8A0E41195C3017FD6A850CF6E45351EAC1560433C1127372222B7962AF3F690225387BA8386B620661022D9DDE1A23A3C8513BAEC72DE0A2EB096F31C8F5180D269F696BAE8D3854924FFBC1011908EEA6915566BF4F1980FB71AF76EA32AB775DA453641A3A4939BDE7DCEEA2C717A2D11F606DE8D48BACCDFAD5619AC5EA1A68667AA5E284E91BA75BF027C63F63FC33C13F09FED14910A05303DBA1DB1CC42A30CB8BBB7EEF71F4550FD0001433453BE4CD33711E67AFB689AC8E4EF91EBAD94852201B3616D333285BD80E3BDC37A5F270E8934A3D35AB3DB5785819A9B911F9198F01937F571693D89E39E87098E6800EE91C0E3DC462F2ACB061021908666FDF1814ADB01F3D6EA99182855A8D157F1EA1E4B5E6C2047044A7BD65C2C38E5B598229C0164C92D844118B5B02077E9B514F00B706B5C9E752EBF9D46E2E62D27A1110A1EB4AFD8C9ACF35ADF7EEE5EB97CFDFFBB7D6417DF8FA6FD076B5B4B34731806A734AA612E14350955A79A659518249826AD1FC308BC5FBD87E0FE388F832B6BE5C6757D7F253E2D6C7B157BFC6925F2D407181F2B87A5324E49CA3A94C7348176A4BDBC3B314BF9C1A917D0959B979DBE1E140508FD3F8E661440FC4081FADAFE330A9470CA9C7DD483DE2493D1E600310A1F2E7887E4A26B384E219EFD5AC7AB12AC441EDB3DA19779A5D9DF7ACCFBD0BECDF7BBBBB0FC32BF9F8EA69122FABB4782BCDF896A57C3647145ACBE7726CE8A0D64793FBE6284FCB7ECB189A33B25C86E88BE0F04F458C7D9C76A30FC90D903531B068B0CED345D2E7C830F610D42AB9BEE27B88C6C6211A1B87686C1CA2B171E82E8136249F83317648C74A7AD295A3070DDFC37590DEC645FFDCC4E86A1628C27CE9DD3B9FA3DB4568B3C3D827DE153B820DA1AD1B83A213A005A5D52EE30EE70A3D3C3D1F5E0CA0516677B4DCBE05D3B02B72F629FDA60C59AF9875FF822C8F3ED3C2611FA6BABF4DCFF77C0787DB2D01038BA7123EE4EE6BFFFA14267B4308CF89515B4283AD16E6D29CDEDEAB0527A047AEE9F225DAFD68AF6BBB1FED9DEF5EE0E483234525AD78985D6693B49F6D45ECC88A899F54A814E66E781AB8CEAE27CC822769F73D4F091ED4920EB8B98900A3CC8F597AB3CC0B63F1C71D9A8ED0F8170A0D7DAB3152495C7D4BCB5530097C164F7E7D4EAF7AF5F136B1E2188D4C66D5189473BEEB6E27CA3B5043D12540BE9B14F96CD667463DABF5F194DBD1FE6032CBC81530A9AE6D834307F826C58830B6B1821007835BEB75255EDF690D6C6B7EE22871F9CD02284E5373D5E5E8702B5AE6785CF108CFC11C3113CDA37AE7601E2FFB04A7E5E7CF40A3A9CFF481495E2CB0DF423646E7031D235FCFB91DE16787012ADD89CF77EE57BB9B583D49F45DDE976332A022A34DECD4F160721D174FABFE501CAE7BDD439BE6E804BE8FA26DFAC1745281E2CE42B12B50BC5728EE148A3B0B05DFA9F5A3E19F18F193FD8B1A5DB430B421BF1225804C89C0B1FD0817128E524618A6B535A875536729E601A0D15636714C53E1498C0FCA1978A3E51C8DC7FB57EBD3385A8179F31CB7B0B010CFE4812A718C2EA1968FBA5865CCE7C8B14497F06377C54320C1A101BE0E84503F7441A0E92508FC62E58E9F8BC27BD90C90352E70347C4E65E09BB6438D82363A650A9CA6655386B4CB6311FDE140AD73B2304712A6593BB5C0CC8F51B3EEC9C0A9055500B23F6369F33A6AC21C6C8D6CF12CBFB59BD1C504D568A3086AC1D60DBDBDA071F7B86E2DBAFD483A41C648C874E03B4B2D80B7A102839B8D0DCE943D3EB5CAD2FBBFD00F5659B6FAD7CBBA13655D7BCA8A03F56A9C3AB13EE84703FFDE78CA42166D8A5A4552F9F2258E03B5334AAC6489F6F0D7A03A15255EAB12EFF8126921096ABA8D44B210B42003942184BD20202050E9F5B1760433D9400F022C9A1E9D7D5AEAAEA83684DEA0052540F108FEEE0EF28F6931853938DF9949D97846B57A3C3CB6F71254D2BBFFC855087CA6DB91873198EE461E9E604253E578E2F98866CA71E2F9A8988030A90B628FBBFCC8F600F2FA06B75A9D81E53EADA87D7771708649E56D8F85ABF2A504BB73C1648BD68D47AB678C42D694F1AEA38C77A5F20FAF54011C3BF81A56D95342EDECB51E63988A935DFC33C43FE626197C515A53ACC29C18AE29A4E94E282CC1C9AE648AABEF9D6FB68A16680E249A7C3A2D5361C63A3087068CB0641DA07A1F6992E74552F6A97AF6B9448E28A88A06C1183B262FDFD2C16DC1C023B01CE99F3BFCE700FF1C5A825C33B86B5B21FE7871656DD59CA0197D72827F7085E3C4B48F3B122D9108A24F04D127831B66EA80EFAFC58CA12991AD81AF3493FAF1560485528129FE41EE9DA2F89D0E5D63F0144D206365AA394E704ACE5890D7ED51A77BC21F86518A96BA3BDD67B44DAD344F77CF01E28201699949DC92BBD8E93E3746EEE2FAE449CA0D3C98407BDE59B9F5F14EE49E32E7BA824BE5410111AD025C13ADE0174F9CB26A0B8BE4ADC72CF6592E7B4ED6DA5BBA2F62A0E811A0403A3879C68DEF7C0A7C454608A701DA8155EF75A5E1DAF6D0E2E9345BA40997472811DA536FE0140FB6C29AB47B450BA4F8332ADABBA55031B7F4FB4EFB4D7D169FCD3A8B8FA2E30AE80E55AA150E532F1352AE5F185DFB1475D2296A88535C753D1DFB1593CB295A98930B821E18ABC3380B8628B01D979C848B7EF73527051F755C7492F0CEAA93795C53E79E1D85C27094C3B61428414C716C1358E4345722039807B8C474A9BF6526B41323DB20BD4D71A1295B56B8BB20111B38804C51F8C31EA3B37AFF3BFE189784C0D90D473D0D596938B6087BE8926517CA9CF196420438C3CACDC146316BCC9AAB7772B307571AD617A4251E67EE2E4712BCAB180970AB33E23BA97C032B97A7298D9CF6607E8AAB2BC3DD5DDBCFF632463B4FDF5F162BC9458A2C33BA79CC2F57D04A443C641704CA4E73F812573132B91FD78BC7653E5B55A90B25ACEEDEF62924D3E4C684AD5636365DE35C65D12C7005D60CACF1D4BB12149B476D6D1662182E937FEE795A6AB198ECDF785FB43037A58C0F25445EE03A2E0A3053294CBD67AF7B23B0185E733D9600DE130080B9DF3FB1651FC9B28501C58090BF7CBF01A1F94EFD34C868AFAE6FBCF19EAFB94C8A7C49C18F70A2DEEF114BC8091F04757393D33397F1496DF653F046EC4A1F7B5B1C8BB204BD51396536C1930CC819EA6C14AC80632109B9D700FCED15BAF88CA8B76D625754E75B79F0A66F8CEAAEC1B48A259D5BBA44DA0C11AA020DA2387B9BA39F530C83730FBA7399CA60E58EB206106BFA5BBF903D6E97EF6D24B3FE981088A6E1A608FDA0249D1E06C6410C4CCC8AA3502F072A648447CD04BAB3AD83C2DAC7AB75181E60054D8D5093C90B6A1CE9275D7017E98A7A840852866DC5E7239725E8884F5AED32D1DE00EB5B088B71CD1EE8949A446E5E5D67158564454746F1A5A7222D3A5B5A98183254C9FB5B425F01CBDEE2BCE5BCF7FE2D74C6DEB3B72195B4E55149785EE6BC0180BF35B68B2D294A49922DAEFC426DB63E3DCD9CC145F07912311154C427C32D9E15F77A82BAA413C275E717A7C6E1E56398C3A16A3C4DCF97D985EC03184EC4D3540487B92F06C2F91BB1D0917366475C2D0809E476B772983311F364B9582223D191AAC817BFA677A82FF02CADD8A1AFEBED0B2085CA006344E1B4F54DF15C6E93127240560E5EBE7BFEF47B34667D420923DBE279BC98A433EF06B7D84581CE28C28721290FDBD1DDF360865319BD36EF9F3EF35289A93BA59848BCC61449244EBCA73B3091CA1D0B191AEFB6734C251D3858C0BD5D053F39E390181E0EC244FAC490B490CC581F453684C42ECEA227805810F512E63E786AE30916241F7A9CA2433AAE318E714D47580960122D3A6C6951D19A43D19AC386A660731A906B1D057258860ACAB75676231C8346A84539834FC6D484018DF92A74157E3DE0D6CF48EB8D342B8001AAAB3892CD2E1F595021120A523CF180B3BCAC31D20303068D9DCCD2A24438CB4FCC39D9DB08F91B30023C22AE3E03A473D48EDFAA00400DCE9957E0112673623676CFEBAA83A3CDD6F369AA6F3D8F43B17D40CCF6E590436E47E33D9B6EDE630C055FEE8C9CD21CB6EF5BEBBC1CE38C06600752D4BC7047124EC89C17EC58A123AABD6027124CB63FD37F44B73C5610DEDEA8C1748DB64B8DA1CE3D20154AD6A4450F36AC54551C42E1FB0015A51B51C6C74D08700F85A22DBB91A6CFF9FB3A72263BB449F030A2A88B048086F655065A23C0DD932E5CD51E6BEF24FBD838C98D8A1E105837199FDAC69F600AC9B35FE98BBC31A719C6A7A11B592013761400A28EC2323A0EEF9E610A5F1F522F24B60C56B58744ED080D0FCF66F1E2D76FAAF9EC8762263CA105BE799EAC6629BC6C89E24648D0582FE49258B9334694748F520FB7C57B741AC68FA5F74BBDC438FAD0FBE0545E255109B4DE7B8F84A288CA6272F6675A3780CA4149F83B509098D89FFD594D0547915A867A18E1AC7814C1FCEF21EA0EF12B8CEDB7ED4C2C046C83E52F835C3C9D2DAFE3FE9B653C8199C8D987DEEE079888FFF9B1AF4A423C445F4207445AD9A8277963F64878CB71EF06A35A275161DCFD3460405D646BC786C01CB492425119CFE46A8A3DD1E572334A099155F198D65400D7367708C6BB383776AE9DF00CB646DF75065BB490CCB1D6754D87776E3FA5B547462B847B64834AC47D79794B33312C59EEF7F08AC29F4B6E04B519CCA8862890C0D87050F16955BB454D169963921CB8D20113D8C4F1D45EE08D1EA683B689A9D91A79141D373A292BBFFE1ADE3411F7AFE3524496D224C4320B84705EC6C3E15D6FC3B5688452699C12E548C2AA6BAC9E297E4EA8982E8D3F95CD58A695DBF2D24AB804236149A7B0BC8BA8A431F0B8BB5017CFD07F43EAC294165F411D6EE81BA7CCC20B2F671E02A5907D410A3DF96AB2BFE924D6D4853325A140BE2B57EC391656C68D056569DF840E8760836B04B04D6E4916F6403D0BA7F0B4584F02CACF025545C4D3715BAB24CFF3EEFB5A0A3EEAB8B125E14D6D225EBE5A5439EEC519BA64623A7930D18C01440D6BC25169E25C41803D59C41957E329037039D9ABF190B66061C8E369B2E78FF84AE76D1E684AE9F119682575730629AEE6E1A774FCD7AC122782B11ACC4A2092557F4602C4B971E92D00AF1DEE31487A8AA19E40142E9A3E1DEFE004909D5630EBF6330AD224C4272B9F014B5F576EDC48C1D53A6200F1073876429BDA9713CEC1B6A86600FE00F10B20DB5157E03C112DC57E137E62A1631D4CAB42360FF3F60797BA17CA9978A51DCA90426342B99804B63DFD3807A7859BF2A4078B51A0F66ECF866B2BD271ABC3D46986A1249981C2E4D65EBCB279B4DF52770B975957A7FEFBA16A616ABB1C4EC81077509B33573DEDD24283477CFC7CF8A447E8C2A43A37E43B0529758FCD6042C1CFEA4BE4B09F79FB362830807C74161D917D95D195D0C7B450095D0037734939E0FE2C21130154781E620292700B52CEAC7AF6810CDFFE476F9ADDA65CB89B8701064C80017C2870D1F3C90E9824E188DD02742A4145DB88ED4B0658A886A9E1BF4DEDE0B9C4099342EE0B0120E8441C42E9EF21D371F019F96E2C65E5315182D5ECBD4EA64C66825C36303E9E8C97B546BFC22BD9F090F74B3499AA92EAEB433D26C877554CA7EE3C3CF9668415A6D02EA8DBC96760BC24277AF807B721E95FCFD2DE8FF495B93DC8DEFAC2A41395FD960669421282655EAF51A61863D3E4E91CCCCA302F105E80BF4EA7BE05CD1F75B8F7F9720D528460B4565F8315DA89C43BD1270F61DA4C8D68E416EFD6A7796D3902A9D7F5299EC3A88940EE46DB21E565306BF04D34B27287EB2FE0D66B1B416BB7B6D1EB25B9EB3F0DAAD28F4666B36DF477DD68161A30A178EC13112B443DED1B4FFED3CBF5DE799215E4DC6D723DB82746DA3AD993DA5ACB750EC82E64636B3C3DF7A3C2A4676A7404E1F2686B4C82887D4584561AE1535BFF4026FC0CE0215E26FCE68C9EF8AA9E610901EC981CFF52B4A7294A524146F037FE702D7AB23BA4A060B30B059E6DE6C0A70E3BD05699A23DC8B16E62F35B85F683CF0FCEA48F0B536321D6A708171AC9BBCF9C30ADB32943D60C14CEA90951B5E4408DDB168C85CD697324FB32E0BA25D87728D8675A11ACD2DA356401942409C2A131F40FBEE992F54736EB8FEBD4AFB1564FE49C5913736DF6200612CE29C506820A9D71A1E63009561D49B35DC84233CCECEBBD94E580E8F147C110591C3DD136E46A17A420A7C8C69733EDB6B9AD1CFD36453D35D5E8695733E38F5CC60EADEA6F35AB7909B7695F799B2B9F96E6FCD82F9F4803823F0AB68E53B4601464F4A801B641B97121DC9AED1A2E20B227410D8249ACDC27FE6DDA8EB7AB6012627E52DFD845E79A5EF8C71A412385AF835C9246FB5F0F776559647460058D49100DC327D6CBD0E59A0E8AE0F8A8F87AEAA1AD7D28C3246A1F475C05CE88250C7AC7886AB29290B5F09AD6476B23005DA37EA4C04ADFF4026C768C075A9D54CC57AB95F5F3DE86D7091093A69ADC4552D5708D6D05BDE6B11FD9AECAA1EBE4C72E8E0EC66522C5D0D2EE36260F9F3009914C3A054224BC8E3E21E3CEF697D65377DB0993EA8F866C99BDF3E9B3D72FC3C660FB9E969EB4E2349371FBCCED8FC6E07F1EC68AA9C538C74465E858A9F033E37D6D4807B4814A2123BE3D1A16269E1D9BBF3F3BD617946E6DFCFB542850190FC5A2CFA6A6F2D4258EEB61012A64A63E2A64790E97ABE98642DCAD6E817A890AD012215463D3A8863EAFD5A808CF6B4543B0B21E2221C59DB5BE3E318441A15994A2D1A15E7BF28D1202D3D01C5C843D1ECC41137AC8F7040DDD2931DD77D795C8B0AF67482903B7D8D96440DBA98F057D45B91F91852F1A18838B9CD3B747E2656F1EDFB20EC22AF5E6D9A2778159B6109B6FFE476A37A58967782010241E0A0D750E4D11EAD10A043B1BA01F6E1013A09811563390519472A495827295DA3B6A2A05C7127EDF4125BE2B9ACAA1F9B05EF99E6E1E641D37DF6E8C61D3EC64B2336699ABE6AC7C8EF17EC21AEFA24D8EADB7B5497FA2CC1AE1EB53DF10C0CFDFD263495870C38341D7EF1955E1FD8ED86CCB6006EAA476E534CE34979DA243905329BC852C9FA58354B80B994B2FA08E40CB898C56095DD66924156B1C022E17D974BA86B384008FBAFA4A10B8A2D073210AD9FB91D896B18FF6A6145E8F0B3F68418A8D411AE11D1C63F9E9CD322D6C77FF79FC0B7CA5484CD3599EDB5EDCD3A9CCFBF5D70E5A51E238BFC5DDF71988910848B1B3BDB3856EA10E3CA262043CF9E5324B47500166A59BBE1D8D90CA7E9652280DEE581C811D1B60C73EB07FACB2E2D712CBA3590F54EDFFA4373C7C8E2C4315CC85A155DF4F44C900444573E72D14E8A909CA455A02D05FD1BD7644C4FD157FF25037E9F8D7AC12606286C5C395F1342E3201F78E7EF37057E9E4D75C807D9BFF96CD66DCD110809B4EF7442DA653AA04179D8AC0F60DB07D4B6168DD166403BAD92FE290709A5ADD0B5373328FA6C5A97B179C1896A7E7CBC06552E969E3DAEA5F0BD2A17078EB914E5A722350D8F9C04074C663B098D23C6A3F854EC22B95D2A2AC2FBF0EBBAD3D70DC763CA38B5359D25F6FAB19670DB637834A2DCDA1928FD9E8E0B85DF044606A5F83D159A914F0A78DFE1A8E74E8A0358FAB6CD27D78D0B2741D229A2CA6475DFDDED49A97D3AC48E954E2538CF98242D17E976795CD29963BE379200026F16C36C6CBC73737E50B9C506DC9AF18E847FD668E42CA1C7855F1A27A0F45E52BB4A5FAEC7B698C8B6FD922ABB278F622458F6BC632EF4B1CE56A5C82E2063402F471346C90D81F3D163E0D71E40BCA13F6158F8E09D6C4D75FF118EC2D8952DECD43E7B2E914AE8BAAC734278C9C2C4B0D3B47C30566DBD59511EF1ADA086630533CC63DC5F392D3C32DBCAC097F61E8B0A9BB1A4C6BE4E35F704E238A8607B6DFD2573C18CB1E77615AF50CCBC3A5C0C35D6EBD856F42CC449EE1BB036E11B6261100E1AF1702F80010F0D70BB11011F5804D5E1047AED9430C5AAF6901913D4DDA7BEAD8BE682CF6A095C8E7CA89D302BAC6D3E4A3A4132F1D9C9C8508B3CD3E99A571A1C45A07F6D21B5039CC1E5107A16B74D4F6B0A3626AF20A5909D3625D6EFCD7F4EE35C6FF5A98A1E4A718236B8A31B2A618776D8AB11FA7180F79EA5A1434064E633C72FEDC77CC0FBFEBC7D4232D03531DE1FD9C2E8B14E65869E2BB28592288E2FA723B98D2C1085B419BE0186E0D3103B3BE782B7253C620FA016C1C8DC66C01607132F00683C003637B835DD7B53FE886AA38E1651526875D2270F4605AE4F3E732B389896122A66E8CC4D453A8FE67B84924F8388A29BCBF28FD41CFA9BEF5317A94E22F1826C26A15DC2F0A345F55CC803D1491A10EDA47AE4BC6471E01952D60E4BE14648A679544C867724AA933E8F8DCBC4D096471FB88E60BD5F318647B655B7AE276083A610B9C3401FABA62F205F1C524D556ACE92E4EB05A636CD874083D4BF210B4FAED7C5E83025307537F632BF2C937C6805A47B8EF53A5CED571E8D69735ADF1E7DB7C55A6CC0824C6BCCBE1EE1EFDDDA7BF07F4F7D0A1909696EA5333923D1661B5869848DCBD39164D11BC3AB3AE9BECFAE45618AC542522C1A33CA8B675FD559DED410685C1ACCA3A3270BF8AB02DCE5002E6D3BF0B29B8E6FB2569318B48C6B3C92C9BFCFA254BC0D46D2BF3F3E40C533759532930E7B369F117499507261E3A87DF30ADA33A38BB75B83BA13A24F457D40AC3370F87BBF477487FDD28242AB42D9AD1A65DD30F62736B40E85107811DD457F80C2DD750A970B15814A99FB7F07F1367DDD77508B8EB8A0E029B6B39F0C65CC5C9176D0B37C209E863ADBABB8445ECE139E8F769497B44EB873E9C94E5FBF4B61AE17D2AB8C13C8A86CBDBA8CC6759D2122C41C06F4FF2595E8C0A308CAE309C5C4B26264E032EFDC993C8A3E8B03546034D6CB72992681B81F541E0ED6C1E5F010F56C5ACFFA18705D611A6A6D9951F05A601C5BEF80B4897726D6AE268C848196104989C501A57195D3A1C221FE34C7C6E584914A849A9E4E92AADF09824303D794767BF40B0EC1CD88B2625AB6469837338C4BDED493968B8FB0A99CB682F098FBBD47DCC40F2F23E5F3E478941F3AA7EF9161B9F5EFBE38AF4A968E9F82D6C74A245C56C20BB5CBC09301525205B7C8C41BCB7E1F768C33DA78609D9754EB43F810E9624149280FC26C4BEA978BE080429A84BD483157CC6D8F67100034D5A7CF3FEDBD711134E0653D874D748959BBF22E401230384CC12B3E651D3BAF8AFE999DCB8FF7D9BFF665447285B7B3FA3569503A11D1529B210D1DFB2DB6C21200D2D78F937DC26C368A9E528DA19C760E716FF822E8D07DBB2C534FF17CDD848DDFC6B1E678B7F2DE896527A2ED3B8985CFF6B915729FC864C495CDCC1AF349E95F98ED696303AC890ACFA5AEB2C9D6F4505BC645538080EEEE0D27077D58474C55C36ABE5488BA828D82EE41C500C9A37D3BEC0FF38DA1E524C5DFA26435332EE938601A1DB060D05560D7CC33E311DACA7795F342C5DA32DAADC439A28F80F6EF6D6BBBF2E356205AE69A02D03BE070D8E98466C7C72B34B1AAB9ABEAA841B43EDB37B6BC2E84029C5323A09C6EEB2AB34A860D0C556F11C18E54BDC8A4CCCA05F6A66F88603928E91A8A2456A7875AD2F36D688059BB8CBB6510B97F84298C597E8115FB8DFDD4972B73E9C4C228365D5EDEC48018F08538F57C4986439537F3948C5560885AF2D08ED26F5AD293645443ABE171C98B966C014D0985ABD85EABD8714EFEDF9A59891DF0798836DBA2E8120C8459CA30593A4675FD1E391655D6C3DD6416534692DAD505529ADB5C288BC9D832821F02DCAE31BCEB9E677E7B3DEEE84195DA72996FD9E961723C9BB2AAEDC76874AB807791C3514684E411F145113F7DD3BDF3EC175552D473B3B373737831B0C4D7FB5B3B7BB7BB8B37BBC13C7714F1213960F5FA12002CEBB7E2F2EB2789B6D4051EF51F4E0016583A18AC9E610E48E6E5EAEF2BB9EEB7155A7EAB3B8EA44090F70D5CF8A1377D072C7482F4362FA3BBE275B88B4D2E4475BCD3DFC826F23592345D37A9DB1F472C8878F6758AD91BD3C730353ACC12D4B677C960039A11AD6D5573A975C641A7FC4CF352250755E56E9BCA4D2EB56F84F1439B653F10AB403011274438729C88D9021B286505B11F800A38C7CECE9017C877BB470B6673A51D156287C22EF4429577A96C165BE782E63CC3AA26601F409BBAE1DB4C6245205F992BA378B1F4AE164F08D086B1BE971BC86FB68FFA9B95EC0971520F1ACC03F750F3FF97E4FC7984CD8CEF400F39F2713DE710C11215D4E8C7FF5117273BEEFF2537DBD2034E91BBAA10BC9C036AF725CA3657236B7D60DF78FC9ED0DD0782D615D1D68AC3B3AC7DC1772471148C49D7E7823EECE0AEC3EEFFCFD12B45BFF3CDEFEEDE9F67F5D7CB5815DF88F3B1BE2301D203A1F863DEC0A1915528036D7D259217C3615323F264C0374D501E369E8B5AFDBB7EB30A9360636147EDD834905F9541960C033DA5E9732627C924E6671E1F45F15FCDD96385C37B547A659BCB8625E2759C1BC6DEE9DB1BFC8E556E77D9555ECFBB298E0CAEDDB742A8204D9C58B80CEEC375CEB88B3455A78216AE7856FE325BB04CC7202135F6D4C1E3E61F27305938F33986AEE586261815E26E9342D8A3491BA8EBFD311E37B67935F3D45E58B17E35918E0AFE9DD8BFC6611FAFE3DBA5084007E587ABFD2FEC7B730328721822410C49B55D502F031F535A384789DC66D74BC5C546D584465C36D57B74ACBF8E3646B9A6BDD9C753BDE23A36CE07BE44466AC9B4D6BF07B6515D274AFAC2444F7CB49D275AFAC52ECEE9557CAE3BDF2AEDF36976AFF4785CD139B46A16D214631220417525DEC0359452EF3B29241BB0D530CEF691AEE9FB2233F2DB5C90D430DD41E66AD924406B3149A3DEDBB33444C544A336229BB4A0470C54C8C7DA0BC6485C2F6597102CA56EFF54EE82C5FA8E5441B862BB336DF700044F34D6C3D6BA3A17FAB450BD4EB94758E283A1E4B241A8CF25DD24306256611E5893B44C3521B3407EF57274CDD0CBBDA9B57130DB47965B45BEB13068AF6068F2CC9B5D313EF161321A3AB0B5DB4DD1A464CB6F6FDAE5D8498BC3D4B61B1DBD744A824FA3D6D4F09BF0F42DB8D0A5108F4F46FB3DB578BEF0B3C29566569C9FA90D11449D6BC036784AC8001FCC322FBC72A7D254F3F482359EC66FAA5A539D4F761B073054AEB925F55652A250A2ED41DC171224AF6AA85F12A9B256FD3459262AB7BAB2EA86FB9374548375D485CAF78F0DCC424E7768C1C793248A949E4144C0F451AEC7B16AC62AED87CD52BC65857369E35A65F985C0D24843A48AF6063B39A80F9D72837A41D3AB5607D5FA4B1BC27EE077A9548D732EC06DD24B2EE66CFC5D8181431537D3DB0154C8716D7356D50A47CA45E8A213931D7A8EA5CB67162897BC8B90893947AE3DE076C60D45C07FE9D3EDA4B4408A515813B4AAEB4D7E14B6110508C352DFD05F0D15E4D4398CCB6861432A09F611320CB24393E75C629431C1DD4BD51B80EC668E10D6D6D902FDB3F4CD1A0D08FF9AAB4E924A88FBF329838AEF2396CA1640635532EED0CE628D026C3BA9670B5776D8E4B5B98AF1CB9D475A9C773DB4066C82F3176C52A78DC0A93E8DE04DCB57BCBDB2ADEA6935551661F4D43FD80DF74903246195FA4E504D81A53A067CCE01B87EB6BBF18200F51262D7CC03AC2BD5AC8B381D96FBCFA35FA895482D2363556CE0F5C577716054276BA9ACDB918D04125DB6CB55CE620C78B2BB1AC588AF548CF805D537C13EC83D87B6F14E38390986AC87B5D04DAD6EE8D05464DC971C534ECC4C652DF33147BC5D8EDE150DE315BF97A4C1E5FBDF2DFC382C980D225F9D8C72A7D905619BBA9F4CEA68CB0163D755349EE2AA93DBA75ACC1C620F2EAEFD6606672E15CF0CBA855F7210193CE4E89614D6E36EA3B3CD875E3A851250DF5FD6BB58E25E7117E4D159BE2CF47E974B5103AEFE29C014CD0FE86A917F915214C520C4F9B8E2E47923613CCCD2168EDCE4347E9D88CD1C785B6B153EE0751E89F16B4F9E2EB7CB26AB138F2C5B3D9AA08C35CBA9878B651F34860F7108E8BD52DDA8B1341BBA094933553B2F8253C2912E37BAC4A89D9C3C1445A5DE77CF673C47E11BE1F52AA899E6FD989304FEAFDEC033A20723036B72FC5BB2E4ADE43E3FA9D19B765C96E477D6D723B707BC9F0203558A61BEAE772CFCCCFB020B3B421445C9B87850933BDC6EC1BFD9BA27191EB805B3D23F4CAFF5DE2A6BAB689248574BB9BA52E9F78152FF874B81BE0136D1FDE974FDA0EBDF4002052C206A5B82007C9A25AB32348FB7959CC2FAFDF93876D5A94AF0D4E11721E4ADFC803DFFA54FB78CF603E0B626CED1E988424A9C661113A13266D6947130E35DF3FE4FD56E5D85E1FDE9706AC3699F65E3F381A19AB491BDCE97C5A72D8683D991F3C955F4BAD5E97B6AE82A0EFF317F99C63452010F8F0F0504D7F8D8EE25BCE374C0AD9179E16458CB6F2E121DDB7822847D139FEDB3ABB0120BF430C2649E4B1EAD2986180872BC5499DC3A3E01081A97598C0447EC4774B8AA28125D06F7490AC99D20BE42E6F328A5A88B95A276113187674BC81B0A22AF19E4187819B29EC84D06A1B2C1856C897A8B8000B54F2D8C17AC2DAECFC3D5F9CA35752ED9DF4C71D7114A23D3F265A4FEE5C7B5AAB3BA37FCCC1FFCB54488C6FD8615152B722ADDF7528C017465F4F426632303BE8EC561799415206750E21D7A160B02A752747BAE9B4A364CC0B6413F5E7F6DC98822BB77AB24D0D2CE74B35846F5DC4BF024A3524DA79FEDB5A3C36ED9C05DD3B0BF9FC97FAC5C515EE2EC23F14E0B39447BB185AB0D709E8B368481B1352A38830385498BF47D5CBDEB768F12F422B29989A21EC768BA0CF6FD75978C7A49D1E67323299E44851EFC55D4AE7770C0F588AEAB5B085B71814941A7E9241D9E236D950AEE0FBA2116140F1D40753BBED85646045D6DB77504970A5361474F15A5FEA31510D118B146FDF06F7FD5AB8D5246E187CB566835C5DF843C6B436828E8D2ADFBDD66DF3426C9BEFE34C88EC88594CD045DA52147E15B15CD45DC228C0D71B960B512F2F4F25076AC0EEFD7385B37ECC633813FFB05C6ACEC4F459FA0AF3E50FB9C6B3898ABC97E72D4654061EF722BBD06305A15F26CE4071C604740334B2DE078DCEACD83C1634C3999631A0CA85426E5BDB91F5ED9D8BDD049AD871931971A26D93A75AADBD93A9FBDD9BE815DEC903592E6C6BD7A6124AE4D722BDAB455492E16B1C5C219A65657DAEEF1FABB4B8EBF7CED56AF585DABF37D179FAA16414221CCCE3A53C2C3EBEF3E5096B0015F2A883D0333C536BAF5F9861EAC835D56C9A2D12B9C3C4E1F8EFAC31CED3CA9FB2EAFAAFE99D74BE3D072B7649A18C7A306E55F9A267CF1127CE2AA408403A3CA2805547FEC9AC3AA1CD104A9F5BA259293828E3D8E7602896628EF6296244BE208E8B684541DB41388138EC38879AD1DBEF82FA1613123647FA8D0841C40E8FDC63C2AA88431CC944B0518436D32374F973636A59B5B6135556047D471B3355F12883F134F494608E72F0F2BBF72FDF92950A43850CEC17BA3B4A4F90A50EA02730C8A07D6B2098A7554C81023BD41993EC24F3BE570DE9A9DDC8D013F25467A4E451B7CC9806EFBE7FFA3C7C7B8F9D123D9E56972A61EA30556E019191C034496D02B07D7139BD374F053FFFFF2B9D6D6D1442424B55D4FF5BA9F329271957B49D50A103D76C794C9FD5FA983E4B3F6132A560AD7CB5B8C043F78C6BCB0CA6F5E40653171510941FDF220BFF5A0CC5283762106E3751642E4BF08471A18DA9DE75F9DAA9489D8D3C621D44EAA38747CE6D37F6CE7EED5C64EC701DB9275C31D5EB3018156EF721FCF3C8A64BAE0045D9E666EB7A4693ED3CBBA058A5BE8255B27CA48E269D7CA454B2482D97D06A693FDBE2A7742A79AF4DC6B4FE343B2BF1FEB2F7F95B112CAED3348BEAA85F89D1D2AAA00071233F1ECFBA7A25106BA698890E3D685B8762561774E8E901FB97B3F80EACD0072A94591B89E440FED4923A5A103AE27757A5ED8B27E1F52966EF4238B3E3075C79C5294ECF6FCC22E040C13566EC3DB64589455A8820C5A248AB473785E05F89D280D7B90A847AC4228189C67C8E539C9A1B5D804DAF4E51CB3AB08005BCA143E17B90D16F63B1CA4261CAF262102F973FA645092DDCC46D02986C51E5E53548CCE3E6F2E106CD245FDEE13073E6A0C6EBF0C45842618EE4E8D7B331509840C2411131745F7173A056F14ACE9DC2D504EC9343DD4A9E488918D2B5032B7AA14699A44175578524B7A52CABE37D5D82665BA6DFC92523819BA23F6E6EBA14E912F749DDDB466074BC2D4B8CA145D6BD26C5AD693A5F56D80AFF743EA18A29E62FC5955E7EF6AA0849E9A08A0BE08D563A8D0234FF7C4F5B9F674C0412CC5AF1F7C77D72EAD18BC49C3EAAD25B282D45AF7298EC47653A037D1FE54BA42FEA59E1C3EA8B67CD929D2803145F4C13569759B3F958351AC5117C120D41445DE18611603EA6A3B96962656811D281ACE09F22754FC7A7C8EBDA6567C208F03AF15D3448BC825E4A57D775D4227A864E9A44CBE068139017BC2D0FFD96837DA9E662924F6CFB86BEB55C41770330372015F98DF5A16E4F1173D2125ED970F2CA31477625FFADB7986E4640D740DCDE4C173A33E3EAF528BA911BA81456D684D09771F961AA695A797D1E0E9312239519B206982F986E4606068F3510A61C93B3081D0C00E8D42249C45F9D836D8B939EAF98BAB4864AD71AACAF7698B8B33BED5B4AE34E35C2D45E2B4C50B371C78A61BA6EC04375C3C4D58FDE33D5B6DA5A13DCE6A7AC8F76CF8DA35E7FBC7CFFF6D55FFEF2F2EDE5D31FDEBF79F7FCED9BD7E857B0BF67037ED315F0470DE0F2C7A7AF7F780960C323175F27305464EF48918547C33A32B6A5E19CE8BBC92DDA17F6CB3BCDE8C024161344ABFD0DA6634136383245656C07AADA49CF34E53F8E3E0E6EA2ED35A9A829E94608265D8C0C1A7ED679C0C98CCB833B8307AE54ACC5839F8907D73A0F3A515153D28D104C7C57120399BC70F6D95D3FB98539F25D3D7BB0C5F692E248A36D859E1C1A5174BC6C14E901F17B4BFB4595E09B206A0CB0319DE5371676EC2E36366907F831367D4C11ECE968F542C542B73DA3C54387EFE4D46058A1E49E02EFA459681982D982E51DEFBB8214F823972F7C1E21E520974C6B2D5C71D73B5A2009B5197349345070E967F96D7FB11595BE98DF98EA2DD0CB785C22349A73BEA5122C081B99AE2B9C63B0EB900ED882A1E626DA89F642E55FB3E8B8EE84E8AEDBD015B7240CCBF82AFD1BF4CF6A701B02BEAB817F26E0BB0030ABAA0D005B6DEB49B325C56DB85A0472327AC2A6C02DFA566B56AAECFAB8CAB485D560BFBECFB94B5D3179D63A914828EA71B48BDD037E3DC2160C5226B33C8AC26098C43874E3210953B74DAB9ACA310D43ED0563A2C24365630A2C2DAFB7684C24DED58CBC234686AD3D99E5511406C3240633CE034FA5351879478CC4B1ACBD604C5478A86C4C5F8C9162B3FC04A3D42F7499F7E307E85883F6F7011D9F853EDA047969C90688CD6230D35DA0F753351E580591873910FCC040D5615AD0BD63FB6D734C15080053D882EAC6AEC960FA144D627247BF6549A5DCE1EB2C9B9FCCC0DF6C06755DC3C0B06245C7E50B091B7559B910B0E6A2451DC1D1046242384EF24509654CAADCBD230DFEBBCE4BF7884DEDC6A1C6655AD45B307E35043907AB275BC0401FB1CE68B3911A0C992E53A98F3F5BEDC4168451C99EC955A67AC1C982C4EE8A033AE5C0EAA1AE807F98C271CD066B35C86F1669F142AEDD308097C3D35DC50B75D22EA18D5CE7A630BE4F00E4D7595156D84CCE9605519AA2130245FCFAAC52EA00773DFBCA3F0D137A1BF018C44685C2F3C392C1E22D3A29E22B8AD8A0EE6DA87D2B6C243C8A842C072A5DACA4FA90F1ED63BEB5BD9AB0F75EE340783DC0CA7D4CDF2172567318106C48265D8968D468DC0F9E830D6A1B95942794D9C338C941E19624CB8D26BE13CE0733181F825D713EA86A10BB43DA049AAD625680E1CA0FCB204F5CDB544577964BD9B82703AF5C3D70E6D6640F43EB37CBD160018DB88C350C2B0662B3CD1348E2D37D79516B81D07EA99ACED57A586C91326D06BA1E8C6F43DD5994AA435B14D889EEF7616B2BCEBA14E92CAEB28FEC692D79A04BDE44E63B103353532971913C8CDE65FAF52C8FAB3E6ED94F2BAF574415C888D7FEF9F2F98EB324E9345ECD2A0F990D37A0D8A6529E326AAF446CE6BA2FF6EBE6094D55EB3971924F48C18560FD7378EFD16DCA57138713EF6F6B02C7305DF5C62CA28C133DA336630FE6C4364665B21DF5C713FA770C8FA18645BD22A02B01ED759FE09AD336170D8D38406A9006FB356B40D49F69C3CFCD65F71E63D8A8FBAE77D8A821DA860D4C422A6A8792BE660680742ECD0BEA742DE20615E2871823248640DCEAC6E2584F21868851D23357D001BAB0C3B482741354B7E42C935EE268BD7B413793D15B650D335D8077B6D409BC83B14E708CBD7E4D214AAD08D209E865686F7DE5A7FC35C31115837C686F43D63E1849AEC74B77539F78CBE2C0841F22EB4A034C5C238B2A466794493D3DD18AD7DE6F448C0667E675449D86DD3FA4D7A5D755EF40323580A2583CE0C2CA13FDC5C85978A3ACD8502A27FE66F512CEDE14907878A23F8C2243760A0E876702A1D5B9990008C77897410A593305C030DBCE2440C7C923B1A60335CE7764D89365ADB0BA08BCB49BD30242EA2DDE28C984D2E706BA5E8561E0D7D5F2EB187B8F19B22DDE15571D3B52A5F613D39BC8E9DD75B78BBDD70DFE9E9ABC4D9FAA6E606B54D77417A1D65B8CF746D675C3DDF0DEE97B4EDEB2AB499F3C45505FF3F76E357E92DBEB7A328B899B6BDBD36A3E777BA7EBE2E3AFCFBC391389105FCEE2B2FA5B54EF3104E17EAEE17EB639EC5DA0A5DCF9E205F4E0176905154A1377827AEF2950B749323638CD07704B48DB4C691880D77D6ACA990B906121F8D940F0B389C02F53759BF00EE2FF0DDC6A993C73EED27B0FA3CDCD8CADD45A8627A67B13AF29E1D6C67ED06810BC41743D151222099377C5466FB52089A8E29BB1BA99FBD12A2A3E859A502E2699638A1BCC4E9895ABF12C03EDD5DB81DAEF60693B6AC43BC75C4E8401CA550783105694B865595CA5C0AE399A99B4DAD4595E55E9BCD756A97C69D6C98DAEE7AF53BE94553AE5ABA487D258A7567ABE7B548C5BA101227173D4E5800933A6D1DE3D59506B918F226C680D6891AFD67D10425BF7B1A0C4428A009BD09A5E6F796B2F5DD0A28982A9789886AC34F150E5D4D88E481A0B0B67CA72273140C714196C3C445001D979DA46C371B7299B00ED345D9BEB2224DE3A533584198859151E2E4EB4A99B63F031FB2E90C73E37AEB3E926833658B8D338BF253ADE5BC312F5115F5BA6E33D5F63872792E3435E85B35F30E187AED3438D7324C0E343FD1527C3828D0A583CADD9BFC76E7C2EEC8D2A7CA34681D8E7B2291D4CE2D9CC176D8AD05B844F0638E113FD7732B0BD022683317DADE8ABBDD55D1BC3A2AA2CC769CDB25E7C6C162D9116EFA22512B57D06F91C82C4D7B1FC6A1314D810B1F97C4AF2E3BA9AF8B9CD30540AC66907258965C6C0E547C4EB27F47744157D14C94F4FE891596710DF37C21A561450510115E1AAA880B12A40BC1CC34B7C744B19544C09BA86C41F21F534CE6F9F8735944F11181A0BD058C158026A2859570DF1440A8DC2723EB99F6A9AB83733D04A37F55AFC2C8E714D7691224E9998EAC73F31C7246BEB6232FCE6D7684AE1EDF0255A13CFA58CE85A555CD3EF756AD5C9DA838B975E7FC34EEE39E64CDC9185E2FEE0F91B6AD943D9B287037CF7B94DAB9C3A6B0B52F344F14CE0431E989E2C73C365B2D9B9218F494605A3E617353E8B7A42A9FB4372A873CD630611E3A4A38E5059E4BCBC45012ABD24C1703043DFBF6A30DBC2874A3C54F47083034635B8A1876B78E029AD9C11059351D9715E24E806F3852A6B54F419E1FE37A9E812666574ABD7EF51D3EFE3E47FAE9A3EC2DB95A547E919D72FC30F5213E6F44B2ADBA50A846B961CB6F38BAD6855A6ED7A57C5C1D5C260E98C15FE8313E39866BD7270394CDC01CB9859149A691999F974BE3DB4EA9C6233E3B46E926CD908EBCB9C3782B92CAABAAEDCD5C8DA5C5C30F16E2E1E6DD9D93EC4A476A9432E2F98D4FEF4A6679954E1E24DC8DA7A8CEC1D29859BB70C1BA3908BCF4495ECE4D783690685FB2A07F8192DE12C8F59D93BFAA960F28996BE1BDE48B04F04BCF32C283C9C3B3C8F1210A1B91426E11A3BF18784F04DA66AE380A30C53784225207C932A4C963ED7E7597A91751C8E89F788B5C7083754287C26CD727A7F15CA94C069517E36D0A248F520155E9DDDF78B2B6BAD7F92350EF28D35730DD6E1F04D98C6F7E71D5F0AC73EAFD9DD6128029283C6EF9A86EF9A46EF3A066F6763D76B58B8355BD3C05DCF1862EC9ECE366CC73AAC69B77E59FA83A6E97D2AD0628E7E36F51C4DBAA5D459A3C8AEED53128C5D1AC66923E015739BCE74D078F55407F581C8DAD6E24B71E170FB4ABC028CDAD6E125A061EE8B7778F9ABAEA84A8C36BF58CD0DE1436AE15DF4089D7C71DB10A07C7ABFD7D3A5C0548AE3157A2F19B1306953F5A1E7202714F9A768C8F6034025DC0F4AF72E58C6A9E101217BFCF80CD0F1F8DA3D22A124EC19F00F5F4335F00165BFE4D9A2DFEBB1922CF90EBD5CE73B063981BE99FD06B38EC9354C3E1689D3040F26EEC1AD09BA11F676034CCF57A80CDE89C0EC588C73B77B5C47DC6864A28F44D0C6FE24CD66FD3E52166D233219136C23DA81C2D5036340400DC0FAC6D237A98811FDDDC43701B650ACE6AC5A99417E2E8738EECFE3256A8894AE5E4A4DFEE08BE84CFCA3CE5B5ECDF271AC4F18302F00E10E4A3AD9D003B47CF489F3479DB1CA434C444DC5B2043DAC9198C6DAADD57FFCF0CFFEF9DF3F941F461F3E5D6C6EF49F8C3E8CF4171B4F3E7CDAB9B21A46AFFE742BFA35BDC3E2A67C8710F3DFE99E6628C86B85289FD8FB4216FA16BCBC9831F198314B8D9A9A44CC2288333C22858CAAC391C2ACAD342C9DF49BBC0315DCDA3D3610EA77F0775EF7076D2245EFA57B24FD1E194AD1E04C493780C0DFA685A1293777B6A29EB1E56D788C20B8E82DD08F86E83EF258B8916C6FB3DA6FE7C33B798B09E69421CEB30D5E7D35148960E7C896DD2D2863938F86D7A2EE5CADD668BD4E07F5C00C0786C7F36587514C076E1DC9346073F1AA7E3F9816F9FCD5BB37A2854D2D323DA41E64EE423635D1905C6665FE36BD7A79EBBA5DFB412366A16EE7EFD0D9FB1F927F1E7CC26EBF8D3FF78C9F1B4FF07FF0E2BD7C316A60EA9F830FC92681C1CBF3CDED0B0B74E35FFF855FFFB8E31F07A0DEC7B58DC2513F486F45073B74D7D5A62791E3C32895867BFD25BE1411499DAEA9F29C0FF9A07EF2DBF6B65F3631D5688E02688E2EA2AF60BCDFDDB51D867964FCD551F801AB9EDE442FF0F26602643A14B11523C29FF7BE0636FD9CC6784EB4F76DBEA8AEF10766C67FBF01C92FE94BB6C0EBD1BD977ABD4BC19A4D24E86C9695F2D905BFD0C2D64267F19F29AEF5E8F4E8BC27AF17C00CFC05169F366A8758BD07D1FC7BCA5FE488A96E1A84BAA03065AB45924ED100F666C2A467C287352E007157DA1C813CB11AF1F87C17EFED8B86A7C7E4304362872FD4D39EF8CC6EAEC1E77D03F8C0783A349E8EC4934DA2EC57688FD8F2293F097B06301CCBA098F4B3B9EC82EF5A0905EDFC2F7EF6280BEC0B0E9C48CAA2AFA2A35DDC1DEF7FB79A8FD3427C3DBDD8600977CADAF66FA25079D009B7870C12FFAA1B265584BF1EDBC49E13B447DE67F3F4B77C91BE994ECBD4D53A3C6A7E2192509602655FC74F61034585805D9002A5B8E3276292F0E6BCB6D1C455EE1BB5C8BA9A9A474248487438D7414516DD5F448F400DA2BD0B1305A8C4026C1BC37347FB8DE508B9A37BEB0D57222A726F77CF9EC3C9F7FB32DFE0B7D56C858561F0CCF7CF29B0276A1B2B472202791AF345D932D381388300E6130A5805DC77650C71DC819A15A5A6E744C166D4A85F57ADC922CF7BD87C3D752F4C9FB06CA2ED56CF6D360935B0BDAFE1768545EAF70B928DE186052FB53E7CDDB89053C26DD32552E33BF055FAD3439E8D569E2014CF13E41656D222450C3C488B43A51A8A2EDC0A72E06A64D2EB35729C44A5501CDBCD630C666E13D5B59D6B706C47A57AE23DA4038A9F4A65A19CEF4A39C7C35DD465E95337952064375CDC7FF56C54C178875DC55925C9B713C9B70EDACDCA8911546A8F7CC4E4835735222079D00A041419B729394778A6B33C2FFA847907078A0DDF054098401214CF4FA3FF85E06B6BFEA62B20859EFEA2D42AC20A117C6F2CB7B4CD50E8E4739738220AB0756622018D598978274D0F7E338054A1B4CB5D9D4AEBF856D0608C6C662BD37F5080ABDE39311FB3D9F72E497C58921DD90A5EA3C2E054FDD41888F68668D3EC0DDD6502DACD28739459F84CB16E0029D3B5892B181DD7BB863159082CBBE7BDCB4B04C76A3F072BD47F8B326401FB08CA3F9F2C84C589F9DBCCE0091759272C99544D20C7CAE8C67BC644D782419B5C5ECA464936371DCD21633AAB7BF8A00E767FC16AD5D7E241B5ACCFCA67CCA40A9BB279522D88F90FB119DDA90EB54D737F23C1B00C54ABBC7245D9AE908B151757F229167D44BB1B0B3231839B1B0A667DE4E33C9FA57178FFAA066A479F1877E4B6F244F1B9236679D3712BDA18E13AE0242EE0CE64BC982057D0F80822261B627DBCA08F7E286641CCAB62D6825841E6B492A803FB65F7184939D98AD89B915BAF4D169135A4DC7A0256D4A3CAF0E4A10F8314CE760C6AB5EF49A4A655F0720386D7EFE2EFBCD8957086D137727F62C83D9E67C677A3E8019566059C0CDD9BD5A3655CF60E7141592DDD1ED2B80E7312BE5659D01F494A3DABB94C86845668450D9BF54E7AACA3C1FFB317B453300DB78C76DAC6BD214FE1CCA203264F4C359564EFC1F9645C4CAEFB3BE77FFF70F36170B1B993D1DD1ADBFE0577956A16ED4EFB684498DCF5DF16AC9287704C6A5B565FD0A7FE4592E0E5840A0817BE21498D4B3AC96B305786C121CDD7DED3A4D8D31530557FE743F9D516FC7F07FB1A7BF19EC04EEACF17B9466A13D16503F514A8DA2EAED6B8410B503DB69FA924F54C7EB32EDA10D270A41E956A99F0ADA70B8EACDB90381E849B31198C0112C615B29558F51BAE418D07C9FDDFA5EA21FE51C8357787B132839B2FFAF8334694EEAA11CD3330F7397EE617A4C9B29D91178FD9DD9CD38935464397425EBF2AADAE8BFC86A4E06551C054ADF73C5FCD92689157D12C8F9388EE568FFE2CCCD0E124387DFBF3207A9125D15DBE8ACA653A9B01F25498B293BC2880E8D95D142F12F2968A813B00B18449E25634CB7E4DA33FCB5B43F3623E1001C0FEFC8459B1C6D4615E8849B60C5AD2C08366BF8EC92D41458014CFB2FAE5DEDEAE3DD751A989322DAD712CD7CB746C23F3F2611A892FFD337B4C7850245BAC38F23179B4B52A4B10B5E79FDA60BA5F1182797B7B62384E8397512393F53909CE29F6F63A3668D35122EFA5CAD0D223FCE369449855C77380403A9832FD5D1E53336C483234703D2B39E65DAAEEFF3528957793225B1A579740B5DD4B6E24270FECB54DEDDB61E0DB11F1746F1FD5C45375237BBF87D7CA3B8386B02FF6F89DABA4B9590D409CB151DF348A8B6A2BCA123EC42B26AA0F2E7E2191B46D0459708D018805CA28A06779EEBD191A13A0A7458987915D714C6D3B389239A73C73F080A68F39A7B47702FFD66BBB6DBC3A6DE3553B9B90A0BECEA78D7F72B596790E29CFA7FBF08533B30415824FE2E296F7DFBE162F8C9D5D47DAC51CAFCAAC1BB6201F9E59DFDB73873ED92CB8AAE4185A984134D7C4D949C064F07CACB1983D1B87898645EF574C821DDD1411AD95D3250111AD9809DD3A215B726F82EBD5E30BDC2841DF5C43DC7CEDB8CB460F24A2A91C749C2357938020625AB712977BFBBB42118FC5ECD73BF6ED0F096E7F771050AEA580190E2E17B95479B49E076F1A6F99FA1B43A6A4693F3C0EEFA38224E6C68AB3F6A9734CCCA00CE48B11C0CB4184CFAA14FD7CB461139BD69341649AADD291687C1ADC021E4C601A4DB26986A11770519807447731AC274A0F2E6226181283C6719FFD4CB2428403C7C5AF415D14DD63F1A05E406523F1A8B4706FBA7840DA1BAAD8F3B810A9F439F6C33E6EF710D9549407859A5C112BDA275764BEB64D8564D90218B9DDB33AF4A0FEC29D41B71309669DC3530F957CC15155522B4F7733EF7C5325550D016C5781DE7621BFDF9CD8A7A5F1FA693029CBF7E8037AAFD63D51EA43F4BFA091682CCF62A5CEEAC5B79635A1FD7DDDB8C445BFFDE32D2ADEBF26D17609828575DFBE485725A6FECC2BEAA7CBB0FE81424E69580C3942EEEDC7DCD0A95232F8C72A2DEEFABDC75149DAF61C39FAF7B33FA316D8F9F3454F1E241FE4C5F23A5EF437FC4531BE3C7BFB7E2F1E95644DC440BE3FEE3210DAA94731AFBC11DDF4540FC7F72C09F3772A688193C4446ECF71567EC71289872DDA41D8A1FBE19B9075E04ADE5C44DB8A3B13113E2CDC69F4848227B64F3B66C0446D44C3957DE5622821DFC0426226615C726C5916A8B52BEB89BA35128DDD7A31ED823F0CD2BD78ECBB82CD0BF666603D050A6599E237F464F7189EF78CF812DEADD1079487664098A936E042772A37A534065F97F2FC544F05BE94C6B1FD14BBC3BE3A658DE5E0422D4E61F0B7D7BC56593886E11C44DEA10EA571108292835D65749A13C85FCA5709BB242B3AEF817FC525415FB17A39EF8036C8790AEE318EE853A4FDD32D7D4A7610DE3A48EA2099480E12753014C1075BBAB788944CE0589A77C4F57D30488E3592095B88640490C7073C1CC4D4A5BFB89728E853CDC4E4A3BB808349B6FBBEE83A07FB030A0EB8A2B0AB0FE8C525BD5166B94F680F68A9E27B3A09461340F3553F608BEBC5F20EBA2DB5AE57BAF6F4CBA99D593F0D82E67CFFE0809DE9CF320A0EAEAC927F147724290776C1B2AFE14A96BDAED0471C5E420F8E18423FD595F71C3A96C51DEB756017E969EE04FD629A5D812AC46ABF59BCCEE3049D7B84770FBF38D478F2887F42FEA53A7BEB32D35BA875D9EF89D5F19B381BE40B5C9987411DA5C77E4D2E2CC21F091FD3A23C37CBDBBD70C5C680A715AC49DA1F6E911B3230C758F861073913C16A211CF89DBCB251DAAFADA74A5DBE4FE7CB191ECA6E71B572A0A390BF950DBDA18335419F6C3026107C253F8ADDAD9100703F7F1F57D7CEC79B2C819E5CBE5AA812DC108397186915CF74930713F79DCA7D9B2E67DA79A30AD079D6DA0E4E55AF92D514B1453937F5BD8358C2F2FD8D98E51CBBA3C2554C665D278C9932F01C964F7DC2376B6FE441C0511CF047DCC935E5A43B0C99F5EA041AD4B883A2C464CC4EB16820AF3EA6E027D3DE69A3F6C065702527A3E01A78F7236F72FC21C250EA5A160BDDDD044C0C5E09CEB50D19670714400FFED1FC31F8829BA36FBD9DABADA8F7A77FACF2EAA163447D0A87ED1DAFB259F23605CE1766CC539FF893ABA4D5AF292802F6AF44BD122143F4CECB488F01232ABB25B77D8C5ECB0D6F68435AAF6B6DAF79D11D24FCF88ED995B85F56F98B7CDE9705D7EA40E6B6D9E99D9F4894986B3099E58B14E9EF7357BC5A622194493EFF4E20606A26488BAB0AB8A1388CD0A5F7060B1936D3528F2C2B68671C6F9A551C582DF1FE6CE0C24F22BFE2933102F33249E4703DCC5F83C98DBEF3B015B59E9E5A9C2FD9C94F172E5F4EB3D9ECB988152843F91713A4E36D3AF5F5103D8F1E4670EF708FED2378D9811A22702917230F14DFF1E28A48E8228194B99E1093744F45B8018CD7CFE1515C90DCF7DBAD886C102F97D0A9095EE49E6294227AEEA0013F7958C134A0C992031C040EDD1086F8923A07FC0356787B83ABC636E789CED9697B4F4B28A9C31325B38D93E7E1C10629D8C30350B0F43C80A90EBB884F1FA15C198CBD7C76F75EDC5DDDEF7DE5DE578045DEFACAC32BD99CB35722E4428457F922AD723B0A5E6C6E7A7B2800A231D1BFC5C102DDD6EABA208AF35BDFFA03AF08C4ACEA10FD060E6319339CBCDAFD5215D895F0AE3B1C8E659BEBE53C2519FA3ECF704DD2433566F55222714F48D41251C2D8D932663063921D0A4B106BAA87893A291BDE95D14617D1C4C8D97344C3CC05ECD4C0AA459243D65052A9DB2A588355D4C4776013936705ACDB72BBE478EA6DCD976285D9DF9AFE6D26899B96488EC436EA61DAB535690B59C413A0B6C1DFED0D2F56C38E76BB373C666A6D64519323F4E0616E6EB29342DB38CC8E7A5D7D5231C9D2F605C7A69263CC39302E49264827DEA3FDF35DE76E023E1BD5AEC9366CCDD64D923199341DB6AFE9AAF5D523771CE692241E51B7616EEF76DAEA1E76855A8059272C953EBB0F16F9CCEE833771F6369FF16EE3C81FCCE2B714C88E2FD3EA27814522A53CEBE8F9A34397AA77151D90F4AA84233E823E26EACACD82E1D161C81FC8CF6EC8C93B66A92409396ABAE076E72E88155FC659215489F2EEB28E977249E739F148F20C914137ECB0F94390E19EE793B40EADAA9B7EE26713A4D69EF65DAAC91B4DD322CDADB37D8618190B9E4727D47D4EE9AF19355F8AD8989B779A043C3433C11C5BB4CEA9F09F393A79E86015E6C3D1F81C8075134A8A867BF85DE99CC4BC4C5B9660BF55CB8849CE2FBDD70BAF47FA0A3126AB55E4BA5A49B7F412611AFC27936E24CFBDA086F8C0B1B08C175995FD96AA5772EE5C8FA7E21786B143BF05A6BF216737363C04A962B5A52E357C9C6EB80C8F25234F07733CE4D0046EC2184D18A1C91DAB250FFB7533CA4637086247212EA7BE224058987A7985DCC34B4BD44D7D2C2BEE2A697C29AA92D64B3D2EF331EED1578F3E3CB99DCFFA1FCA8DCD8F6951423967E71FFEFCA187416A36BE1AD05FF5A2DCF8EAC393C73BD99CD134EEA908D94DA68A10D92A8FF08EA2F3BF3FBEF8EA3114DF3FFF507E78870D84A4ECE0372C805B97405C6C4F686A3B05DDE6EF0C7C4BCADCBED0774D37533A4235A166D55B4762E96D9C246F163FC1F090DFFC403B0381B0AB8255C7BB6BE9294CB5871D2A2C72383AE6B73B6509C28A39DEB575964AA403B2F2BBF8BB3E425370539CDC05560C4CED72DCD5953C49672968721F317AB3298CF29DDC95A128DC925B62B569CB6E036D8261DF166B4E26ADAFD23072DFD2A08BAF25414859681B858C91DBC1FBFCEA6AD6E9C0BA0E1CB51D5AD780377428F3E20C0D8AD94299B0174AA0C33A2FA46A79CA6A2E2A699EDD66A0A5A01D28BF057259A9CB35F12B77AB2C405C96D7F9CD53F8AED4A9C0F9CF4F5E9C750E855D9613824C56454CE782081A5FBF906FDC5C946941D344F984BEDA7D1D1F47D53534D37AF55039DAEB51439AF5C0D7FE7A50A6BA1EF854D743E1B3A922C2EBC94AC30A30D2C729689EF4598AF18665EC7C1957B129891B24E49576B4B2DD565C8D275C5C4DD51AC5E90B93C864677750B5B38C19398D93F4D542FBAEF8A77D7FB3AA2C04AA3146D1DEEEAE95D9F70DF319CBA2C7EE5C479D23A6356859FB010C11A47F0F9DB84F9FACA24DF4EE344747AFDAA0467FE4A25F4B1776D2819D745FADF3029E052A3687251B500F5CE5B5EA4D5FA659615CDDF0516933DFF8A7164ACF01D4EF9785A986C205F6D99DBCB00091234FCFBD9332CF844C6B2626A33D33D340A42930364DCB63CF9D8C9734C18D983060725F06A48324591C3D389E88CAB0B0935541BE347287E3325F3CA5DCE9F3EA567BF972918817CC5298D8F06AF49E1D52A3F116B2C9D3E6FDEED56A2EEA4D18A7EA2786C1D8EE71E05A5C1F46CCD0A1BD989D57ED7752DF4202EDE85C7AD1F0B5ED660AB5B185C6429DA9B7D51C0BB365D23E12225AABAD98C4B94AD7687A4EF0D92C423038F07BCB13A67AAF43CAFA6634249F224B80DA8EFE98CC8442D9F59CF0A226DF4F1A1ACE3737354A7DAEE72C371AAF42A390C0A2912112425BF51AACDED52A87EDF72A19F9A797EAE3272603AD18AA76E5A8DFA5AB99CF98DD1C22C93BE5989F7BD2706794DF221F81B635F4AD9F39BB1DFD77E57ACEF11477EC4C1695308F599581A0223DE442F0B8C75AC30F2631EC9CECDE4F204C0B50884558E9E849EF9A3A269F4061FAE43F8A77320C54028557D2E9476E5500F4ED5A75A84BF06B6A3D85AAB2DF5295EF41107ED79A8802BA5504933132A040AD9B818DA91DCAB01FE66D704431C639EF1ACAFAE323D3C1BE80D6BF87C6D7AB2AC7E7B5AAE91FD30355BCE7D0B2C6B0E20E299AD5DE564E5096FD8AD31989E255D96AC235FC6F1B7F5001A76DBD1D8BFC7DBBBB28E19EFDDD7BFA1693F75C83D598484117A77C4CDD5BEB2AAFF2EF5398C65AAE5E2774FEF1848F444494F909926366E336ACE6125FE16BEE1CA45155BFC99B0CCA7C9EAE3F47C224673E8A9447674462EBD457A72AE46DA2385EAC7B8A9918B5DD326DC3244B20C7634E0AC26AAEAD9B99C2A649459F08DC3101FC7CA86B21C5E74BCB2BAE8D9982CABB4D75AFB9D8A4F1A051493AB0098CCD7CEB91630E87B542EDF8664C883AEA22DEE6BE18204B3A1C1EF54D2C54F2C82726BB2304E9594FFCBBA8F777B41E1A26EFB3B4BB28E07F50B95313FE0E7D05E74B6D43B1BE705AB7F113874039F5F24402A035EB659AF45A48925B6E6D34FD8F58A2FF6D3621B74B88C95A1FC3F55EE3B3DC179B5CC79971D32368AFE0CDEE884E0069D8DCB5D5132BF4F2A9BB276B777C5A3C3DDD0D2D9E0A2621A407629A2DB2F29AAED2B297454DEB21B46C8A54B49A01A29AA7B89BFCD98BA484679DB5514CB58435660821EAB8144BCCDEEB5694C97D19E6BFD6B1F19635ABF0F46A35D5B0859A59E8C5240A5D96E92AC99F2A21894428F2647059BFE2C20480A6C13B89CFA119879C4F98E2C2C8648A45974D11367999CEA611BFFF5BCBCFB9B554A3AD5534937D7D9EE912A8CD12D4906202E997E6A41F79830469F5379BF86AF1D7D376B407D46DAD49A0A5C150ED1C85C7C14FAE40F8548BA6D34EA6EE9A3FD463225A55573C8781DDABCFD82AC18411F84E0FD56656CC6F6C636247EEEE636FB72D065408CA146CF4E0EFB688DF42329E84371BE224D010E4895E1B83965032A557C8F9937A1B91E77CEBB2F6290D8CA7BC7361EB80D20029C1EBD39A719BF127B529460AE804DF5D4E3AAD96382477598D3068EE92A13BD1BE4583D3841AC77FEA6E5EB26B02A7B62F28A6CFEDE8C624569FF923154F60F216086AD507901DCD48D890F5EAAA2774DE6B647CB91670A6C131EFC06D4B4ED961A6A313DF057E1DAAD79E90587AA59E88B494D4719E61CB981A78A5B74E63E43BE5358F3E13FE641A30E1F3F9385B581EE1B16B071A46FCC9540069F83E31B86FB265FACA981FB02A3CD69CB692C1F8EE55D2AF5F715694ED05C7981DD8B929D20DC57D630072062F766B2241F4EFF4FB225FA6457507668FF43E73F12C054C8667313DDDFF3ACDAEAE2BEF674C14E8A44D42F48497CD9403BC517B3ACB6F989EA0A7061072F5AEB324499D5B3AEC84E64039F89895D9389B65D55DF0F60495146E9C849528B2384075CBB9C817816BA1F4540E0443B12EC3E56D5B4544969A163E56809B41AF79B73CB2837077FDE9A9FB992C31478CC5950F24C77D8FB473A927B8D47A24069324FD5BBCEF6A1EDF62DF0673AB759B2FB04CE78B7C8A296D3746F5A4140FF5E64991CF66DF50CD02C47908635EBB5E43A4A1EC9A6BD3D505F953AA196BB81ABAA8C6AB2AE7C4C8E89CB656F24535422A3AE8DE372B236037AB7C3985CAE9E1FFEF2B5992BBE1EF2E1AE6EC3D2C20AD6ABCABEA0E6A382622D83DC53920AA02A08BBC6B9492D66FA3B6BBCC97B32C49DFE7BFA7CC83111A9DD9CECE2ACDD2A967CB104B84B9207E6DBC6DDD3B4B31A9CDB55605893827F5A51ACFF3F97255A5C93B3150F874371D9DCC31D7A41CC08FCC3345C624EADA27706CD17199CFA0088C95B318E4741DE37B00094C5E285CC92B98F4406115DECDECBB521793E45EB0BCD708D3B140C4172E118D1C2CED8151DA9FFE148997FE627A453A8349C0C7169305990DCD19893DA5BC484A8CB9D1B6FB25D80EF906770128C92D04BB0D802D64E463D5D4915ED50EF90431F87733EA85AD2D95455246FF0433714AD751067C941DE84ACEC4EB771C5D688A4B7A013941D75BFB65584252FD1194A9A555C9FB0D2DE225B2623D8DD9217A1DBCBA1D808ECE57D5005E67BFA5DFC48B6496B61F3EF0648B5A8E23F0D93674F8F4165A29C3A97F3CEB9CC938C9C5C36F45E7D62138FB04E18519330FDA2AAD5E25D6E136F1FAB98A39E41C8829A8CCA7B7194859EFD6F0088C27A84A04516E903CFD2B45BB1B89E01FB77A2D9E63CC2B03A790FF77D96F14590C99EF7EFD36ADAE73AC08EDE331D95F34876CF60EB5CFF36CF18D34B886C6E91BF8005CC46881E6FB099D928342BE8D6FDD2AC29C43A1DB355F4B64FADB69769B264FF16280CAC5942DAAB498A70946DB7C7E1D2FAE2846920564473DEC3D4AB28FF689C6B30FBD4263F0879EB8480A5E3BCCFFD07B8C181E3FDA69FEEACC04DD5B3D2FD296E304B4EC636CE4EAE5939136CF57659AE437AC676CEF728C8A41B4387B1F8C70B3D6E529B050270B4F674BBAC257F409B28F78CD27D8F297593E8E676FB5BC5E9FC7076E392D9B0A1649B495A777EB4BBDDC50FCEF2C19F9E9E5B37DDA18D029F0A79538B28CE7ACFBDE0B1309244E4474CABE4BBD8A382723EE395D9CC36B0F1ADE75048152EFFF681033BE5A9FB4769893E40404420244DE6BAB6E463520F55ACF0879DD80893ECFD4D4A6D31565D5596AA512203CBEED48B854376D842B65B536E1BA1CFC2D3A339E7FF6B49158041AD731D5C0C0AD3218000D099362A4EB0B5B82EA0B621B401C8BCC6B5258268AFB3B6EBD3751B6D52AE0878815EBEBFAF4BB9FBCEB5563CF352392BCCED4AD41CD7D89E9C4AAB559B31631FAA68026CFFA10A11FD2741A5E3BD1550AF0E05C95532E8CEC0B1B499859E698A27D7EE5C448D43EBEA82375BA089FB8EF5C8AEB589FF2E0717BE9352B2C0BCFAF7102A4D6B9DB55DC0317D767B6C11A3600AD2D289D23A7AE2E3DFEB92C33E48907DFB03C1B4593C1AD47F556F8F1CEF3F1063FDEF895F66470ED7E0B6C951A44E3E9F050C0F3269BEA277CB72618DAE521E3921F8CC032C66B973298E2FC8DA9CF5DF3F9678B2066D0988F3D9D849A740EEFB2C5B3FC966955D6B3520A020562F564F356D93FFC42DBCDC76CE35DD397EB703DEBAEA9CD09FC1BFEF1ED16FCF09D5F453AA2C754A8D70C0514B87E72E35BD000ECF09D30ED1026062EBCFF234BB86E2DE15A94C0AD197B5DF0626290DF10C285901192C0E0F4761781F41C72E124DFE52FDB5996EDBE983588F43CCBB5D816626A9F7397F5A859D23CFFA81FC15A2D93DA1A767D08D728B12E60C5FA81ABF2D245E22B8C50A1330385D5317DB68DB15AA7B9DB60DDAAD6454527343116885D9F71BF80929BD57C59DB78D0F7BF4B6F9E8BD1811D068832CC7126AD5B6FD712A3D83AD2CC0D2E50568BB24E07CB826E827921EED3EE7BD9AFD72EC8FEAAB8E36A45A36DADCFE9FA935A7DB7B0C17FB2C66EAAE06DF4DD2D03D99535F1791D97150928B436372749EAF800CDA836B88DB683235872C764BAD332FDCC648269FE4F46361C4E40C36E2B0B5519F74F90A851B4CB6DDB00926F5C24D736929F11C91D21B1EA6C1E4DB84E27BF3E57B3CFAAEC238D5B5488579CEC3C9A4869B9BD5D3B343F17FD52554F427A7A2371F311800F6EBC42A8383EEF3ABC48C4DF08C4FEF153B5C29C1F198322CACEFAEB83F97292EF1FFC6B6F3F0919620F5801653B7B10A6BD16986AF610E256F6204C3B621F7BBA984295BA1AA51EBEF5075C9967A3FC6BF2C30AAB4AB21E04FA1514C65526680569F28448827B6CB23508DC5318A60E1BFC6C87674ABEA1EBDA7EE28D56A4C3C2EBD708CD301C1C60D61B77BB8DB9EC78EB93296306813726A00993955F2B921D20B73C3942F34B4C4EFED078EE959CC60CD2D73EBDC2A36F17E6E43F70AEE7167B2317FD73B1D2666D27860492C2A169555293657F960E3B902ADD880D9116284CD2A7D01CF2DAB361F24EA7F544EE34D0409D80578B0C63442E6F3DCBEB2A31DDB4FE1428C63A9163ED5E7934C28674ADFDB769DB0E3E4C2A7D4EE3FA16B8F554376E17E07FCBC6F54683C3FC22C411BBCB121C98E4DC0D3D6C182108359CECB7D45FA45744A0CA4A12A80524B8AFA21D4C85463532FBA37E8D9C2FC45C809923368FC690564F7B83E39950B786B77B3DF76E75775F631153B7ECE53C11C331B2EDAE0CFBE0CCD87C1459B4753F6EA21560A4CE390561F14D96D80481F7FB34189B9FBDDA898109EC6B45C8F4340F05ECE474A1A60313AFF66BFAEC708FF395D13C5946CCC69670286D2B04534F7A13E251C79E75599BD8B3BDF34EF1AD589E7E46BC59555F80137B871C27E4E1BC2FC503E147BF1E1F0A5BF4926CCE33C35A36AE77B11333E0B82EB62137A3749EC37CAEC0E3FA055E0636F8BE483F66E94D8B9B913F9BB9F82E785ABB1979B329D21BCFCC642BFAA3C10134166F8A186DF066DA9E8B1B9C13F7BE589505DDED1228137D3FFA04C9A89E447816A06BA04029FDBCD80DBF1A9820214B8FEE16636195E7BCADC62C318AC738396EBC02ADCFC25BB4A71C08EDCF50AB13FAEE0C68F005E3EED0A982E90C662B1A1D49A3C56034BF4AEBB608292E4C57B8DFFD8EC475E8F4A7721263D0F13DEBF54D565D7F8B6BB6DFE61F19072B05F2A2885D4F294CB896FC0A07CE8FF16C1439A55EA357743C9E79508BDE25BE33C8F3653CC9AABB51B43BD83FB4BE75731CC284C27655AF71D44CF2288C1A9018C6484EBD819478BABC770895513ADE892D9FF9D80BA73642010A3B96A55040A57DF4C8BF45508D680B4AF392B5CC26BF0A3F26D51BA904AFC9D62367AF1E58B5249E281A5738AC7AF889AA3A68B7D7AD4CD4D412232FA9C397FEBC98061241C06694162648C12675CA0EE6650DCB83726B26D68014D45582F3A26377677D3B33952A1AA1EA0A54539D5618D52727DAD9874AAB0F7CF92A02C3B83323995CEBB03409B893A961843A49C3C26C7EF5C558E821D527ECC544CDC466D5BB82C255EB32E12F14075DBF484941D908767E790C6E0B2BB0A5BBE107A04D81A58C5069AFC0528727711517BD4B561B34CAABCA3DAE90898CAD8F597033304E7E5995D52BC4DBDBD83867C3CFCA69906C96EF495DF9272A3822D52E90836491D01BB41F41F7D69B0C6982031EEA190FA19A6A0C4E5E016D8C5EC262FB3FDC8B00E7420C741EB1E22A55CF4F9BC1D2BB6E2738754D5E6E11E3052AE741F43DB496E3386CEBDCF06733DC8F99F15C4FAC37724B1ED319BC05B899361A32E7CF80A999616E45ED172B62122CD7C4B8DFF5146AEB458298047ABA231204966EDD6EC9E58DC78BC9F4356FE160E363EE7144D100958F3ABA5F84206B1FF803DF311109A6101E30674430694EC79A707658F1C194D0E5F193221BC370B1033A620775C40EAD16B6C55A22A0179ED82D5EC4E2AA10A9F4F0D18F016F7CC29D847EA3727174507669FDC26F672AC70C3076D1859B1C3384F6F0E9A79EA55EC3D1786B1B2DAC880C877DCD16556E2229AA8090C6445F91CA430CA64EA5CCD2F86330EA6CEF528074941D3CD997CD5350A7622DC21CCF6C367ACA1DEE1D3A2B6816A8AE53824B8698681BAC1611E19478DF090E36335DC49C0EAABB25FDEACB9F78F45079F8A06D53BFF64855E36EE4BFE30B49BFBD8BB473802DFD1953530137A3B243D0D1ECF68EDF886EDD62B518A0D51F8D9B9EDA5CF74B95E8A76FD3188C57DADA6BDF65C564186684C26B7D18067635195C7730CC754B1EB2DC84AD72F7EA7A5B464D71BF97983A0DD8F4614FDB7BFC6A0DD64929F0324F1C460416608458E2C46634DC0D338F4E3A02ECDD67304C8D1EBA8B0BCB2AED185026D75750E816F4479ECA3ED3EDB216A3B0467266AACDC4E32CA892E534D8D36D912E2A93E1000D7E6DAB369A97BDA43C5C4127D2679DCDA342E41D8126B00796B1C19B7B2F667159FDCDEFB6868993FB801927F00A33BEFD8C8E4AD7BA2AA89DB70475832ADA0EE7C60439AB8D90F988E946571F7631B38EC5CC3636FC709C432DBD5F5FD834616D13B87A1CD22BE41B967C1AA2DB105C98B61C29658CDDEDF7D5478F42E27A1F463460B2E021686F2F29777A8E4AE4A8448E36DD191E76480BF6B67BA004EFC2FA52E858017A7B7F9DD939489858FD17DAC03843A85B85C1FD8326CEE8B25E73EF8926C75F351EAF194DAC63B6A3F5A0A2BCBEC794D4779D22D9E70BEF3EBDA6BB008A53C27CE4574CA28917D76991552945F4E8761B5763CF982DE1F439B2D95B4D01D1CBC8C9A8D6A4E47EE00DB2ADE550510CF43EE91558737D593EDD430EC534A1B5629E81FB81A1D4C347C730ADCF1F2BD75A3CC2D4ECB6F0309DDC299A473EE05E32C07EF93A2BDDED2BD9E53406C7BEA0A6BAC771B6009B6A51E13A52DFD82FF3842E6528FCB4415339E95F414B9BF829B43D4BAB6AF1229EDD55D9A41CFC504CAEB3459710106E9E28B431CBE7D9D0812D9F070798B998379EE00A1DE5069D36CDAE062B82D5241EA739CDC6DE81BE6F0805C6B429A7EFC955624E8CA04C748355973B80A939AB2296DB514CA820B1D14EC14A10986F61397E03FD7F79EA3FC220BE87061571BC788A71C8FBBDEBAA5A96A31EDADC602F93C61CCCF289887609CD55E5931C06E427AEACCAAC3B3B65391BF4A2917801CF373737831E5741B58F81EB48CB8ADFCAA09D06A26E33EA5DE5F9D52CDD6E5A7E92CF77AEE2C12FA535147D522E44F904E322BD9CA5A4FA9FDDBD8FAFBE8BE750E63528F81EAEC3DB5C0D2F7B9007FF5F9EF636E488AB4B8FB70964A6501BD486B78E307A2C4545D013D010FEBE8F2954A5073774B9FA79EFF22AAEA08F720D5BD71A1BF5F22AAF3A3000935BA1AFCE54C479EC5A3815F5328D8A698D95D1F422A49FDCA2DF8B57A21C54002C5932238E5D59F522AE6267A821B0BF3CCD17AFA106F66DB3AE29A113AF727523FF7BD0E53F821EF7F661034AC3B92ADCB9A259B93A278E131DEA207EB6FAEC904FD4ED208D4B9C1CB70E063A6CDB20A0C11ACABF7E6DCE0F6760A5C6BAC2758D4EC6034667EE3F56289F5D309013CB32BFC1ADC73D5F5B21BA37383CB4E3C360D3FD05CC58F670BA62DC0CEC12D88693EE3500347B9614D3318AE851C4C763666B0633341B0B7F2E627B8835E86F6F2F36B4AA6C6359260ABD3A93D5389BACCFF07D1FC3095F1B771C8448252245151426B40DF51763FC7E07C62FF06A2E1B46E2EA5BC836DDA6B4C4AAA8D66F878380E017551BB30CC1B15BE340C84E98DEB612BE58731C7C6673401D21BF594F59C780F28099D4FA6D7218C4D7C6314FDF380CF50D49681BEA2FD618879FD9187D0B594BDF807126EDD60C24C9847C9297FD45DDDCDFBF42F41B211E62216D0CD45901F04C01C11A7444AF7547AC85C2FF55B468D5E6E9ED32EFC629A01DE614BB1BD2DDAD6E90BD2DDC8F90C3C7D05B212CA863754449C30D71AB42D46FDA4896B74D052E3642F6A7A8585B89429045BDFC926C5FFBC11CB15324FB91D831C51DE9FF125DCD6E0CAED7C170EFE964214607FBDB242B3A9A049AA896FF28AAFE10E834AD97E0208205B5B5A9E0E4B6C370A32F7ACA0ED6AF5BC1F76C426BB8E9CA1C4C6BE8D18E8504FAD51826242D4D8DEB11B85B3A1C1CEF0E0F4F02CDD098AC688796542E0A1C90E49D9B2101DD5AC215812F40D9A6D887F60D0A823D6DF4597400E2E1E070EFF021578B7BCA53BF9DC15F724CF6322AA83752DCBC6A9D4D344A1A5D39DA356DCB6A0A45CF06D6EE0EF63DE2B104920FD8C6F06A1547752ACDF95533F8F705DB9151D0075DF2E5B88D0C5B7A8735C1B13601FBB7601933386DB7B245E3824BED32D4F56A61EACE9CCF18F4C39D1390F3B730763306347E0BDDB006D7C3DA813A3477BD8992E3DDC1613D3E741065171126AB21A1DDBA8C599EAEC550D42E462DBD2BA8C273109D8ED3071A3DCDF5AD81C88FC70DF1E3C26B54D4709D868AE3C1E19133422839D91B1C739FEC5D09251AFDA164022320E87753EABACC5E2CC3148EDF4045ECF98BC0440DDE07C9B6959D9E785AA0E976DDFA626AF79613A4C952BDC4611204EE0DF68214620A5079BACFD289A9FD0A2145C1D1E7917072102082E161B09F4AB1D7058BEB3A6D42AD9A02BA76484BB21DEB959845AFB1CCD9F7765042544F9105C3745EA9F5F487ADCBE9B7D245E6721C979D22EC1BE06D8BEA26B89204EDA8ABC145DA0FDCDFD307301DC9B248714F27D24EC1AE8A99BBCB49D5453C6C13E187E877390FE63DC4AA27E9DC730A291C85411EAB1EC953D5DDFB81FF449705DD78E3201BB70CAEB2ACEB7A000C774E01074B1BB58B4D9731D268BFB12513B5812E9B9FDCB5DD464F301EF51BDAFC6AC48BAF852B52BE428274CA2E263C1BDA36AE9CE3DF8BF8E3BA07CD294BB0C7B159985EC71D308786398C94F7393A94F5E5418927514F1C12C04D583C9760B87675F13BA1D30C9A5EC51F2409C721252A9C89B4830C946F63A09F3AF01C2D43D4387FA00C76236E31C4C9AB2D6A0A01C1492B6D94B3E1AAFFAC4672AEB9F7139F81A72A7C7A2F74A350AF20B76001B8718168E8E058406F10E90FDDEFAEF79526CB668B76E94952643096DBF905430E7CC323DCC7DC2124F8368998D8AB12276AF83FF67B8FA359A679076ED4DAAA199FB7A2CCA3A8EAA39A5AE88096139B581B75D178C7A84C220687EFE6F1A40EBE01868C0F26251D4FDCFA2ACA3C501DC338D1D87270C803D872AF92B02DF00C9F6668D0621027436D8C0B042CC1D4C2B04ECC30D8BA068D932FDBB89D68EDD870B563E0B0CD72F0790E76E183A301A8BF65224C4873192F2ABF98737ABECC571503EB6858D18DF7F722E3263CFEF804C24E843926CF1600419DEF04C4840A431D968E792DE1E729AF3E540251A9AA02B5480008D375914EF1E2ADE23CBB0843621A14A970A46E07C5B4F361A7BA5ECDC73B817AE8C98944C4A57569A83E0C3A973F6889C486297438C13761F47ED045002D534608FCC5790711951A29E88149F5FFD67625BB6DC340F4575CB508142091AD5A6980A43DE4D41E5AF4D29C821EDC88699438862B29453EBF7C4352A22C0E97007D272F149721399C197B1EB3133DCFC9BDACED0C1A676E29804DE6218873EAB666E77EE230CDA32E5EEEDBCFC2A99DA5BD6EF846BAE2A19B53ED00EABFD557B8048C2BB29DFEFBAC15DD9E95AE5614B021504ED9E4BE047259F81767705865A05072545C6CC5EE37657E7CE0E4ADFB502F14DDCC9E9EB3F48E4777F4624E546543577D27AB465932C8E3B6DD12BB6D91F5059B980B685B544F9A5612D272F7D78D1E252F5D87CB04A1F9855AAD5C469E01BE5727F27CFBD286E38741FB90BDFE4A375EAAA3AAD9C2734067A32695737D0D4C80A76876B578F97E976318372BDF8204A8DA8FB3D0BC8147B38D42AA4A5C312BD7CEEA442EE7A427F8E25A58EB4944E479CB3BF700DD60B6DF7838898070E80408E544000EEB863E06E3DCE66FC36E9231C001A958F3BF0FE97CC37B33CA847C91C0581AA9DBDB2F3FBE7DBD58449EAB6568B71AC8EE4694CC3C272FC55EAAB54FA1BCCB77C7C5E80FE7DADBF7B72BFDF15BB9C81E631C611B2AB673BFE9545BE107009F2D6723437CE0B617758C2912D55D406D7E8F000D98056B637070C345014C5DB8E47161C50B22459A24AA88B1D7E3D583E1C2C07F99D3888EC245C9BDBF4E00E9D668EDA12F3550BE253FA92ED2CCE1BBE947D3A0A479F38A84ABC3E06162783231341913964C8944559BC570873A314830DC20A05D5596414CA402F53A66C05531886D878AF9D9F7D77BE91C1A8C53304D4D92EF5C0DD819A48693090346180C14AD4E818C049273DE2C1CB14FF37099545E6F87B05CA4FEF7DE7D638001D3ED7C8140A762EB11BD261D43E4B980134E94293DBD74D48EA58F278F8E48AA16F3CF9B4FA8923D0830B7FC8604A83E9D13ADB9840E9AA01612B73300594B2BE7A18B17757D93B5E2CF73D38AEC67E857011BC1299A756EE43F3B4C8A742D4F9514995D5F9DAECFCEDF9F57E569E93AFF6292980C1CC94CD99246BCD4238EA2D048D4A1FF00504B01021400140000000800E190955304E250324B720000D0490200220000000000000001002000000000000000496D70726F76652057656273697465206F72204344204456442048544D4C2E746D70504B05060000000001000100500000008B7200000000"

Str_jquery_js = "504B0304140000000800E1909553CCFE9D2D988200003176010022000000496D70726F76652057656273697465206F72204344204456442048544D4C2E746D70AC5BF972DB469AFF7FABF61D484445A3C51645DAB1AB02A6C5F2A5C433BE123B99D925E9A906D02421910005803A2CC82FB67FEC23ED2BECEFEBC645904C666A37B109A08FAFBFFB02FC3FFFF5DFA7C7EDD6C52F1B15DFB5AE07BD01FEB4B296EDB1D6E37EFF29C7EFE0FB62FE3CDA84BE4C8328E4AD37A1D7C3C28B2B9AE945F1FC7419782A4C54EBF8F4DFFFAD3DDB841E2DB42577D9BD15B917CA4B2D21D2BBB58A66AD55E46F96AAD33930D153B7EB284E93D1F6A3903D3FF2362B15A6231790DB7DE65407B1FB6066B7AB252C5DC4D14D2B5437ADD7711CC5B6959311ABAB4D10ABA4255B3741E863CD4D902EF054ECB4D83056E9260E5B38853D38FAD7B640BC9A05A1F2AD7681AED93F3217275D0409DFA6FC5AC62D4F8CA7DC175E2F211671853B2F0A3D99F2196ED79B64C1E7B8010C75FB61C617E2FE810762D14BA34F691C84737E8187854C3EDC841FE368ADE2F48E5FD2A2A5B08CC42CBE12DBE7E6F813F1ABDE2C04F020D5330F3C14A75FC69364B2397F7D7E3EB97DDE9F76B3C6F3D1E99C475876B24A4E4EF95A9C9ED8E3892F4FBE4ED9E93CE057FB0F7381F16F6BE0F75226CA660F433A59AC7AEB384A236298B837EAE22C391890A4F1C64BA3D859F1442D95BEB52CBE54E13C5D387D9E46CFE358DE55122E0FF27B9E5C2E6D6237E899AB744B0B0AD237CB655BC851FF4C8E68E55876E9D233F0A78E199B3ADBC0481A9F52E95D6E812429BAA064A5E2B9D24B7B35026CC665A53120575D7FD06A2DB442B8B43655B7E6B178E0EE0357D25B387B59B9EAD19C3E891BA9ADE47A1F951A6489B40D14E5DADED643977BE5726988C510016580AB75720F8F1B80FD9E5CAF97773946F15CDB49420066419CA48700A82BBB8F354BF9874B4E0658A3AEF6B0BC2631EE89AEECDA244ED7E997FC6EE0E99D897EA7E39E79A3B116B0379D3AE329810FFD83549602CBB21DD9921AE57AE1CC780237E4C09071E1C95AB30E4FFA0622829F4A718ED01697DFD7CE2492204CF0DEE78ACF60F42523C7FD6996C1A2176200D32F870BD22F447B309C910B73A368A9645839CC79A7635F88F916B0450EACDB657CC7C3CEB36CD50B92F302AF39CB327B0E77C270BA1001E0CD8DE22E4E4ED830385B0C09107CABB1285B6D9DC418E1E5B782B0A59814F3B13F85A4145DE66D213C42AFD3A10B9DFA712983D0F01A2106079355058936740C3036B25DFC01B9F08DB2D3A926251B4992A4538ED761E959904CC78B420EF605980CA0CE7514F8AD7E8E8D5E82D14281E695E0EC7B041A0957EEE4A1C2EADACBEE3B992E7A310DAF6CC67AB15A2FA5A7ECD3C92B7849CB623C487E55D2BF73DA7DAE28D06CE971330849F2C051B4AE2B23DC7D298F3D466E154310228823396A30396B1CFD5B302ACBF6009034B3B3FB6F266A1DF69D9D8E1488B926BAD18EF7107B1C787BB6B4EB92C2BE93B58C1375BE8C2409074649DB5FAFD6E99D91D8AEAD6BFD76498F24CB610E7219B5F5EE9ABCF7ECD6B13FCB0A756FD768CD32D90B235F7DC6A3517E4339A6AA93D2F88EF2075937FE4EA77D611CA6E4566DDC62B599FA862AD4710B08170F1F665675D203023F5C7BE9933182732F7BD14DF8166E92EDB0A155E2E0B23A930A0536DA0DE1BA59565BFAC0E9E843D2855C47B26B59CE8E7F2026D614AE181D2DC6410E9C4D2B3E3BC53C6C6F19B972F9FA5A2EAB4311D15CB256E4312B3CC0FC246C4D799FBC3858A7355DC542CC606F8D006613159E5CA9256514FB4891A53946DC42B26255F6B9E657DAD47CF51E10F68759A317340F952DEF91C6BC8D6E8A348618BB3DB227705388253D8463177D725D85E79E0B3279D24E4FE7A773764F221CCECED45019B7EA03BE09AE72ACE03C197245010FC8DC58C9CB07B5444E4D7B9411FB3FB9E3F05986C1B45171BAFC73E7FDF1AE4217A10624EA3FD23AE89C4D9A57492A242F4A19CEA56A647CB5141ACA3D9E0E6BB0B47FB263BB8C006C5424681EB7129D39D7F597723D89F06128F190B231EEC1AF84BB6796D224B9B9B9DC8A7051645012ABB4391277CA14C543BEE98D74C858C95BBBCFFDAEC71CCFE90FFD336FE8192978C459D8858BF4044C2C0DDD7B30372703708328D9CB896E799C0F5D53A5AE0D6F16C112C49FF90C02EA76A7C21DFBB868E5A3E0C7CC82321A627ADA585ADA850129206B183604B5C31FA2BCD078943733A032AFD47E21DADE707E361BCE40B12FDAA8A0C633AC82D6E0E045A7A374CEA6474B47A69A596EDDAE760E20BB42AE34D6F42DB4DBAC9D581C48C661B4C5EF740273A8CF86A592CF8C92FFE98602C5DCEE407140A5C726F09D0187D7BFDDABB594E6E55B773412F2B7E128C6EE94BB427229C09CADC40C398DED89BC3C29532EFE9881E3BB99ACCC31734D0ECB8B1AD36E026094B4AB1EA10E76D62E141AE9DAED7255E44CE4406B1942715A97F299573285C492CD9A6A73E7F281D0D7558BF5C224A92DA40BAE8A5BA68A6D1584B5B4C1E9EDAD5FD5FCF5EDBA656CD8644896CEA753DB6A21B5DAE6E9626C8D4DDC69595DB76B4DADE98E6F864D16E7C4551D212B0B2DD3824230F5ECCA6BE407A3F6C0199089960904AC76D4EE3B554A852D79F0B5424DEF9688DD332A474E065ACD1E0899A4563CE7E85515015FF0805FF04BBEE42B1EF288238AF198273CE51B6125C1D7AF4B65754F0AF6F3EB5A4B84DFC0446EF1F74ECC5DD4A45FCDE5B9B9BCD85FB34B421D9AB814ED3EE390F74B51EB73F05762F0E38F4F06FC35EA83660BE29CECFE2771DE5B476BFE335DA993F1A6B8F90B6E4CC3E3AFB8CB9B1BDBD969E1435C20EDD56BBDA177E60E5DE32C7519E76EF9497758F9C9B7C2F216CABB547E66BA08B891C95DE86572934633F026D17708357719D5DE71B44C3210A8E2CC0F12E92EB16111F8BE0AB32081FFC996C8CEB3D5669906EBA5CA406C9821C4F951B8BCCBF2D611CEF2300106BD13D67832B97DDC9F4CD2C9249E4CC2C96436B5F87B61D9236782FF7A1916DC9C4CB3F1172CECF74FF02BFB53D6B5F807F1BE0C82D68DC5AD9BEFA0F31F8535998CADEEBBAE756C5BDDF75D8B0154FE3C3EFE7294B5BF4D4782E52323E7915D1DF585AE8FA6EC983DCA2656736262D1CCC4CA00F703E0B22C87329900E75F04427379E06462DBF6BF0E9A65CD199B8101D36966753F02F231CB7A5837A1A3F9AF8234D93801DBFAA271E96A005FF2CD535640C34E337F0446CDC1A74F7B361F7373C1F4E77DD3F6F8ACFB8D50C1032B97FEB6B554144B81C0F411E83A1ED5B9A4CFFEBDBEE317C6FFD63C0CDC3DC2BABF8BFB37AF9CADB9EF721663F6E5DBE79F3E6DCF82D06AFEF3F39FB66769AAA131C0DF2C7EFEF9F3AF4E038B8FD0A64FAF7F7BF5A13901945FFEFCE66D0335C7D64AAE3B3A19F56CB2305DD0DF137A6027B68704C2CFA2D90939B85C49726EA96BD849E4FB90DEB80B6D67F664E21FB330ABF4349FC89F31DD851294ACD50A6105A0847A1C0DBA49FFDF82CEA37C49A8949FBC349DB4266D04CE88D9A9B05257D91C34198A2A02B769C003ACD367238D7A0D317B24C65F80FB518EE203FF0F714A5805E17A93E68E272364245C45E66ED2340AD9D169C0FF13EB16139F6E8FA8EFFAE57EDA9DDC4F92E3C938946970AD5A939B53FE0F03ED3B7B4C9E026CB12737F8852EE40380C5A52B4EC720EB94BBB8830D4E4EE7DC73B7344FDB1BCCCD9727B3E9FD803F7BD0548C3243226C4F53402AECBB5B11A1CCB484D5BF45743D79F6F4E9936745DE43591B12048F5A6F67FEC844F4DE2C8E562F17327E89D868FB5DBD83397B27CFCE06FDECE9D3C73F3CE383FEE3271D3F7BFAECC9E33E7BD085F79B3C7939177F31D9CA754FABDA7BEC4D18DF7E3A1FD79F8B7E6E19A0F3FA5A21C6BD11F71AAE739EAF1A6DC7C09F8B2A8AE7C7BAC88DF6E6DC65FE80943BCFB3E5D8AB1267362C53660F51E9E1A14C4266AEE62EE2BB8135438837013ED281FD86DF52026BBB23975A002A7E9587F32C739D6B06BE8728A08119B244E4182130F0A914E2BADB912795E5FB883244EAD26580DDF62552A4823728C07FC0D865BECAE4CEEB4EA7AD74913313FFD0D539155378BC10B3F160AA677E10B48BEE16003757E9EBA522245FDCBDF1ED0BC6DB8B2C6B2F7A6BA87F98925CB6F058F4022A162FCA4193562FA08465B1DAA01E29099DB435B67B2EE849518A2D70FDB333347DE3C7D362BE50399FD7E9495EDC7D96736A02100FB8C65EF3E1C9146778DB2B5FC28324A679E01E98F9D3D3CA95440D50A55AAD77955069DBBE024FAF7AA94A7475ABB99F88586C90E8B948F4B44C3A1DC907E6A6D6FA720FF432D87D24E65437D9B111E3F3140A0477856812F8C8074638A00C30AECBE1508E3A1673DC5ED25CCC618A09B21FB0FD91D54DBAD6A369CBE24B116D97A3CB9313168D97539174AF5C9BEED8F04648B7A0ABD3895C08BFA639507C5017F52EA220B4E1AD1831E596919FD8E1E64D4FBF50FA94BF3F7A0E1BBED57C344EE08EDD3F20938569632FE082B45574AD1A54C35C73C0815D35947EE5D6D180A291B6DDCAA0299B36AD7CAA3DCB61D7F6C8C4CB6A4C6B9FD7A52AE68C4A3024A96F355F3A1D1FD8A2F671C7B2972C82596A33948063BD762A54818B5B1DB970EB2DAFF1668A641D8579391FB855A513F63C84A054E52A665B7E706DB161C5BD765B525F6DB70B5930AA2E0CD2ECEA2967DF4B72BEC62351A55C737617EEB6D3CC2BB9CC62BB7D0A05C5F07B12A2F85986FE528DBDB19AC29F56D02EB7A0B9A4EA3EB5F09B05D940889A8F83E57C83BA469BD8536FA8EAC8B257485DBEC9E618D9B6BFE5A78A0E8927BC5E8860FE29709770AFBA654367B0A2EC28FB24A38103775F62BCAC0BAADEDBCC493860964525AAB3095D5312DFF51B53505AE3EFEAFF04DFAE1D80D861B214FDC40E9C17D6CF8316D68F2CD45474E1806B53A8650D3E8AFAA0D429F18AE00995998BD9B61ACCA106903C5CEC7C3A85EC480B44DBF6E942F788C8F47F8952B4650BF0FF79E0DBEBC4E10A5F426D1E3C31834A984E05BD389FD17390FCFDDDDBDD625CB7156533164B56D6D9F929850EB823EBE7CFEFDE6EBB5DA74D2D3C7DAA4A0B287B0A7F456DF89DB39C6BF049F550A44A94A1BF07EAA6EC3F997C805CBFAA69BC6A2237B243A178247626F85AB467B682203A1D7A3F3787A6ACE9AD584FFAFE6B64CBE9DB204915F019ED0ED12710CB48C2F7D73A422B6A88B707CC999331C3CFE92D805E7FB4AD283CB097DAB0DA0D688F9C88A0A64BF546BF57444A810C1CD94F237C95D3F0E704719F3A1C848D70A242DFF835953BD097D1CA385084C5FCB8DD2481CAC75C9F774F2D63BB3832D14E1DCA123A9D43980521F84EFA25AC1FE1C95B9A4CF1483E3AFBF114CF675B83ADA018B6B8ECE92A47D3D4E0DD63ED3F0FA42154DE3428A264EB00EBA22DD6C148900D6C78BB412801462EB367D4DEEC3B6C64FBC03EF47B6F5E35BA56D40FCA7B6B8D6CD098FABA72858D64B17A5FE651225705B5D1D8A34F041E1E381DBA4C55BC7D6CD5422C32030F29815B82DB2BB6DDD48AE2C7C30373EC3CFA9714FE3F1C6B48AE7BC2F270A230F7823BE306B12DB65CCBE546E5A8F21CC5CFCF7F12FBEDA9514EE580F60868DB238F0E66DC45D7796F2FDDA77EA379BD7610004571D8A46E16DE17C17CA65F71304A13BC9AD3CC2B04AFE4805FA45EB3878276DDA169525FCBFBFF050694BB724D6D72A132C18A0F3C269AAFE8C79405952769E6BD540BD90D23DD761FA64BD15A25C8F2A21B6F19ACC523F88B68ADE36AD13CD563A76610376658FB939D4CDB1AD7607DC1C669E93A3A9D2BC35D8B1A965351F6801E51EF70A21B567B21166854A0B2AC00557545478E56D4CC34850EC072F2BEF01E48D514D4BCC1346376AA99469BD4890D9B9510091B458AE9206B4CEA1ED1658DE52145286EBD3A443FCD0B7F1F23F54ED3DC2A7BC0872857A1EE6BEFA3BC98E29653B4BF0F4039E6CE2DA68A9DBC77EC583A5C431557543DA8A4585FA86582B22D9FCAB2A877A3DCCB207DB7BD962656D1D73DA3D1BE95496390ED064BAF074ABC08AA4E9AA3D78BA4FC6E43D73FBC7A1E276D52554D5B9CD3D61616FF8574E14A5C958CAFF5D5AEF26234A35C204689BC674D5C5FE3161C897A5EB4A26053A4771FA32420C4194FA99F535B16A632081336DAE3FB74AD5F953C23D94CEB1C2A8DDCED6AAD2C5284EEDDB5ED367EA925E4D7BE8669DB5E79F4A8BA4561E4C843A8A3E27AD639388BADBB5D34FD1EDDF863576C55FB34537BB7D3EE0FCB8294BF10EE68078EAC55622D7A6DC5FB43D3B86C1FC4E9A4ED1E9A2A9DFFC8476C16FB327F1CD86C4F6599CB468759E03267C0071DE2BAF958F095A25458F924A1439BF441FE88E853F4C9D2D68118BCA666D735976C7432705CB3CA3DB40AE80D9CCBD15F8DDA5F62D749790FECFACEF71D9FE00CF689EA108B3DFDC5017DDD520910954A5D9E7C21C6724AEFE55DDD5C6CCFC083F2E3094D5B893E309CD1C3FC8F511DEACE244A95024ADE17187A420EAB82BDA6538BDE26349D158F56B9FB5705F55566C582BE0D1422A00F23FC6EB7D20D1C49735CCF38F9B26B423E28EE070EE2B5624E88F2D22DBCE0FE97AEBA274CAD13F3435F39555B4A9FBA23967DBA59F487A5EE0F97B9E26FDC128F8E061491390C7FC7614328EB2C8B3B9DD8F81F97214450ACC99F986EB719B32A5DA76B5A2659B6C7E192C2163E09FE81DC4C3550F59FCB4C2B6FD2B3FB878A272E0F0D43A04145E43AEB6BDE147E692F3FFF842FC577EF0043656603C41F6FD66A8F805CEF5335BE38A06F5F9009BE365CAAAFE48D956CA4F4BB80F6BA48F00A052B3FC9998D664EBD1A26398D1AE5046C823E1CD94DE75D8A8DB35EB2565E300B943F9A997CDED15D3AA25F7F9EBA5564ECFC1B894F77E0F46D4BAFE4AD4D182B2F9A87C157E5B7D4ED3A5649829D4ECBEA4AC3D24D182075F8448D95DDF6462D65D7660C5F02DD41F9E3A5AF36F4D53432AC845F8ADC4B7E4A291FA152457F3860F72931A109FB05E3CB22A1474D349E5142AFE3C678465D2312910EE533C66AFD45997F9BADDB491CBEAEF020BA7149DF3629EAD180939FE9FBFC5D023C6159A5D32BB4583B246D915452C0C1FD602E03FDA82776BF3FEBD1DB41FDC6324C4B77581FD4DF924951AFDB87724803F556A4D715FAF3DDE2B5C91373F4F7FAE4122C61FA3B89DEACABF8A6DF5569185525E9A1DA319D2AE31B12715F6B573B4FFBDCA4C21F13B5F12367E172ED4C9CBFF34AD5E9DB6B2A98E81AABA57EB3E9DC5B679673EF07B163556ED7CAFFC1007DD36BB5F6CC63B85B0EC7EA3A8836494EFDD6DE6F8716A192C7D0B9AEA99D7BFD5A7C5F8D3E1E4C05FD34EA6B2EC74FA64803F00B5730FE5EFF3EA52F5E6B5F2CE64BAD6F42979AE3C7A4837AA34596F1BFDCBD797723C7B127FAFF9C33DF8128EB52558D2448B6DA9E7B0B2A62B45AB2B5D9DDB22483904E6D58486C04C0262902F3D95FFC2272AB052DF9DE79EFCD19D94DD492956B6464EC41172CF8571690D52BDA2DA2717F675F2AF84205CBDD541AA057A6A60FA281EE9DD9D0747B3142C75F8D926E889F01BA8CCB3F51B1CB287EF9220CA00A97CA3E60FBDDA2307711BEFDA37CFB3F46D4FD7F6F1488F143C8A5D6E2C19817B4ED9C0E9AA7CD4CB36340EDC71ECF81D6FDA08E013662CC031AA064529DF2383F3DFD871487909A607812E6F0FB921BEB3415121768E5CC67597466AED9E4981A4AF0C7CE212F3335967B4FFCD5FA80285800B48010CC307E5B30D32ED2175984A362ADBEA522E4F8970D92A977623CD2ECD7D330654D92954FB397856F2410FE6C0D60A8A85806C0B401930A65784BBFB4BAAE05ADE54E18E2DDECF7ADD2A836499416DD06116FB103ED93DA9655BE03937D6C940C893ED6C3C273C2125BE37200C60ED3156783B0EC029707F2600021571E9BF703F48C6E7FD6B70475B0E92B2D78E5511CBC702FFD1757440406EFF9EF048A1C084A53FF4B17816163B764FC50AF65EF776EBF2F2D3C9AAABA975C5937380B6288DC098A9A68C57818697B8384B108D3630EBC896A0F60FFE23F3F7B050FA0405BF7704FCC7CE2602BF49C0C9AE0D1E9F81C8107D8E8C94CFA51316A4CC6503D0C02EF640B5AB0FD5D95B5D8C070F8988E4B6D93CEECF4B433C5E97C27E60C86625847CF73CB05CC93F9703D02DF391DCC8F6FB10DDB7DCEEBA46BE7B2BF4AD6344BCB395B7FA6D4E4EAF4B4329283DDE2D4C82A194E0677DEA11EDFF530F37C3D821A661B3DDF2677C37B4278217ED815EB26B9252A980D3D96C90D1058923C9C9EDED049A01695072F476A0E72F5CE338A192E4776B4DD2EBD9CD3FF69D4D4C22259261711442BEBD53A643B8FEA404F4FBBDD0515C7FA53CFA817C9F081966D31EA8B8380A53DB6EC7A1666D2F54C773D02F58E8E491723F4F672D4F70891DFD3A77F717174A7B94BE15C3A34F73A84212CE8C49251557D161667494973CA4292C5BFC188E48288FFF3024E4B879613CE49A499EA64AA68CB8B5540D82784073DA8B109DE791D10E329CA48A2AAA502A1A84D974AEAFA8029FDD2F0419730061FA62A5584C5B291F2DBAA59E686699DEFF0F5B3A96F53CF0CC911AD6C91FCD5707E50CEE2C82CA09ACDF1C34F0E51DB19863A0965E16D095A4C26287E5EAE76F1B44DD60A15B1B8484F9BF6174E3A8F39A90E04E8C59A554D92C270D5A51A8E80CB6A1607F06724CE6902AF45260BA6184E869F71541D0CACB1DDE1C7F4832AC0A0A27AF61120968581158A129AFEFAC8EAC7558DF9CF3CFE169A2FCDDEFEEE5AC2CC671D200762493FB8183A37C009DAB325C5D98246E6E97272A4811F3445C647F03140E5EF194C55FA1BD48FF27BCC7BA55FAC4ED88C027A0FAEA96E7FF4B898C778810ED4DFC973EB2643745BB5395867A46287EF48C214C7A4E106EB62C7BAD58801B30E4FD52EDD4C7CAF72DF0E70957304049031E61AFB6F6AD929E8D1E444BD14E7B159414CD16AD5EAA50E89D88A484DD8A91F7BBFECA539182A2DEB85691837F9391BB7EFDD75080AAED3C1FE67E16EDA9B6E4AE20EFF173D4833367C614F6896FAB7939F462790C0B78B18437DFBDB858925D34A95565AB91D951B2AD9DAA564E83FD191DAA29FB810564479AF8C82E8A0CC557BDF7C1B26FFCE56C0D3A15C857A10257C542B55FE2EBE1C52530B4C1FFEA9CD8355FAD0D2DB8E3D457ADC3AF87B352DD3A2DCB48DED9F7AB3DA3985332F26B0ADF04F2D85C5F0E7BFB84C9EF9900137EF5176506C9ADD68A351D5B136A905D4E0EA27B017B21E828C1A7E608235020761BEA98BDE4C9C82A587FFCC24117A67F4587BED491887D9D925CA9477F5128E3519C2F12FEF6671CE2589DB6ED6661C5EF2E4A29FB13F60F23232B682F6A44BE97BE2BEDFF5F9E56F7C3E6F0CA5E2B397D8BEF6CFCE40E8F44D3545A59AC9EFAEA6DB2D3ECCDA6B61CB0A03E0C48B241EB8DF5987E6E74D5ACC56F0A1E7CD9FAD1E714D2C7889DF3571880FAB4D81EBD9229DE0E12172D457364AE659E8F9473F6FEFB3C50CA222B52989526A965F48793DB69335CC3A0FEBCC8B56620C33B6AEC715B28B99EA7506EA09E0765B424C5A132F6B42D1F7ED4A7E351C3A210D638A7D920D2EE25B2BF7EC13F1C2CE8DC408143D2BCE32844CF41C7688410CCBE4B5186C4F239688946C363DD5D5941079681E74BF9F464ABB338EA95E585D21CA0255F1C65601F33B627AB551AA1A4BF1671122E7E24FCE957A34DA09EBD05DA396EB95B598C0F1CD4C64D4A1E67E24CAD1B6B8DFDFD02D61767A81ABB0C4B3DFEEC5446985069198475A87F229D73ECD768EA7FA7D3C1D38595614FF4A8B358BECEC1F1C58DC65E6081014094735CF192008ACAB5AD165674E11B95BA2D5192E6E32B37F64EF64747C6E100C88309D27FE041F4284F9A3D33E6572F238BE1B64EFD849C3D98D57B3718EA02132D0CA83F51735C67C223D61A8047F3466809C342B6EA999CE545D87D5DB5645CDC73B05CE7C96D498464560CBBAB5D3D3A9E56DA7108B7A726DF0BAC914E24454012EE446F1B3665F3C1BD66DC560D4B15395B9B0D2A416236500123CDE75C196A33D8670D1B5B8CB5A3025ADB4F1DBEE975745BF209011568023A678D2785BCF7DE60B734C5DE074082F4CA9CA9903C59B449C96331BB0859D8B85D301AEC8C331D713B1B1A7D695A81B36191047092F228AEDC25BAF0B1E4754D08E053F4675150995A1595125DC48E4598967281F552C83350EACC883121670D09F553231635943A341930897DA17819A3ABB071A4F3C65E6EE2E81FF4B670C77DC754C33B5560BE28D51BDDA24F980402D1C0FD278455C7934188EE2497CC726DE449D8770A9E592B4EC37097DBC514BBA096F1426162F6E939B2A20DC82779C138EBAE519DD0C977405F6F14E5FCD23F65310F50F686FB9400354E9ADB519A9D6B791FA6E640DEEE88E2AEA974CE988F1D70D1CCD7FE3F3F026298DFE7CACE651BCC07362FBE0623EBC413727F8411F659B6E78D40984701BA3235B29D348146F683D07BA1B139AAD59141BA70BBAAD18643F5431A4E2D3CE0126B1E53DA3111AB2101E081CF03B81C0C4BEC28148000D5B800B4C57BB3DAC9096536800D4FC48A1BFDA080DCCF9EAD20469DEC9CC3B5EEF5F44508252BB03EF21021BE815220773B7BA783CD717D161D41F5FCDFA331DCCA13AC0991E60440D52FF08FB2CE8A88D4400F6ACCBCB71E895D6732B5A493CD5C71B7D4A5B4AA6B74CBADD59259887DF6E69DAADC8B6681FCEAE080CA41B7C8913CD4A82676797910914A04F585A08D0DCC3D9D94BA972409B300E828317FBC8F8C6D05A5FCD4E4F1F5C9533A018459D94A756B86C9FF2811A1D16866A356733F7D041D563D5F7C34A4B3C3F922B6865EBC845DDCA37103543D07C419822B808682F11AAA0EDB4C59EDAD1C1710F24C356A0C6C81586A3F4B97A9B3C7413613576048D95F04FFB7DEF523D26F76637625D6E79034EC4686012F5EFE8EAF1F45447CB9A27F7C3BB113DA535638C707A3A8F9E17D68D704553BD805616B2E210BB6D0A572F991EC20542C0A08D87E46D74C859C09940E63CA79DBF3E3B53635871E8E28C83D6DDE44E514174645D6D2B93B656215C0FD194D365AFAF2EB485D61D21970D757ABFDFF2DF103FC99F655BCDE89CD8027B6CA383410933F8825117818EB77675A87736540900AF622C40F55865BC8C8D8EB01DE1EE833D0859D817C563536E9A8CC5788AFAD84A656B6B038E46F2914763776880A20583EF1B08DFAC8A4D731AF03821784540168253481AAD3D415C9AAB3E554BED3DE26CC38937B62AF324F54C87674E995EE9A69CA0E8AA17E221698BB5044FA75582D9A40E274BDB0C4E150CA884E9170D13C49571B7E335BC4956A09E569EAE93CE78B3062F89D2FCF253ECEEF09655089166ACADE1BD7896F8BE546BEC108B666E5847CD68864DFA1267A81FDE1A9CE533085A510EF3223AB5E98DEA58C3B2B2BF64256E452EA71CCAB8312C8090D4669C8759F263CFF7FF369E84C440D50EED19AD2BFA89D1CE2032B7039927B71574092A7791C860E0A288833359BC734CC685F1C69C69EDAE8CDA71F3C69CB2337589411A793B234438D05ACF5DB3A9002DAA343A170D5FE192183902A65544F41D9B12211CD3BB9D29A99683F20D6C087D69C7BC2032E635DA7895FD14EE55D34827E974085E216AADD8331E710BB97C877968BB83628B21B625D97D23F6F40422CDE4FD3FC04A3DBD0A54F007111179DE2E55D910CA83472556331349D19EA5A2D3723699EEF60FB362370D2A81663C75733E10D3ACB86E83A502AB24AD4A9AE8C478291E48CE8AEBF7B9F7B048ECBCEEBA53351FE79D1070D4C1E037C62D45EDC0F597C7C649A4B688E43AC745726E2E8C671A9B181D5B381DF0ABD62D6774AE7BF655A34FCC31F51B2B2041603A1783DA8CC36CF798355CE159C315BE351C61EFEC409D458C5ADAF3C9968340AE37C9D6D941E94743A27E24A8E47A63E5400B7D96517977A8D1538EF3BA3516651CD0E9C7AFBFA24D400FF9921E5963C6ADBD643BC39D6984914E05C711B972FEF3871C1502B123CE0757E120FEF0FAFCFAF26A8FD8106FE9756FF873FC87EBE1754F8D5EBC77EE44180F665E090D55024C6556A3B2E821C657E89B7E780472C7447F53B0B180A5C4818F214F7B72BC9E2AEDEE3E6EC6C3E20EBEB516A8B64A21964DC435040C754F2C11F1AE9669D04B1D9A924EA2ABE4427A71301525AD009840ED67A110FAC22488972B4258B09A81D389C8360C1E671B09C736085CD5ED6ED94A65401C7F4C2C69B50835AE0791B50DE2D2CACA513D87EEF5C2CC86CF6C7DE77FA7B93151AC7248304834F5F9E82D403376443DA630D566A6DC36202C4946A465E9423539D00E0BC435E398CA4E28A34582FE473205802C94F7A42049AD13E5D5E5C0EC3958E3E47C1219F28B0B9BBB41E5AECB1679718A587FDAA0AB65766BAD3DE838C71268E332E24092ADFA95777E7811719CD536954F47976C5A549D9E3A8A06531FDB5EE8C53B1CC42CF9513D7936D6EA57892143E821FC7078FD70FDC3A87B150D7FBE1ABDD8EBB8322F388CCC47890D08DE4E4533C95C0186D6FD2A028E9C0E2E3988F269BAF96847042751995795478661235E93B5A6428D261F0C86C2EFB2567D14FF6A628F28C8AB3A39D19AA7A7865AEC64D00A4BF8F00124438F91069D286EC46CCEEC3B16F9982026446A9E106CEED265CEA1E607D8E171A6FCB8DE74C3916B7126F3972A333647BCAD5B82B43CF142AB7B6DA688D69A018A09A101F625F2635441C33A4E7534D017C285C8A8D8B22D57FCA4EFAD08D8BC2279AA3BB9E60870A20AF66D7434E033CB0A667091CDBD08288F7692BCC86BC925EF5A7011D61DD2CC2F9F6D4FAAB2BD9294EF4D51CF4729AC7C662A95E2D5C6A2B81EF7B02DD4FE630F51D89E06FA977746B8A0D3DF1ACFA7B65784AD6BBDB497AAD2ADD45C2178A10D401AA61A751DFA1F79FA20EC1B62FE17E1936CC08F65C7C94C6FF7305FA3DBEF97BBD97CCF1E99E7EA93E499ADB2A804ABB6C45E638B6B688F59B5459F413BD57751A861D6DC7E2631830B4AC8C8A725A08F1F0B20B4F1807371F7722F69572DC232A2C9E658DB3852FC2F35CB5B2258478936F4A242D72E6AEE9A1594D3470E472D3AF1EA91455BBFC39A634979107A0ED930B9A81C6630A8693BCB166665389D823ECB7C283D7E4C15ADC7146FF99CC6EA1F53C42DCD57DBD20F595F1DAE0EBCEA41B2824E4D4D128BBADB6233019DABCCC59867B88B2F9C3A000842764A31EA43528D09EBD7DD961021C85A1A5C42C63B194CC4EA451B9262E27D4FE723B408C7C0A5615905724559563BD90CC3EA9FC390CEB0F10135DD6A85316889C3EBA8318D13144E39C601864A33781EE2E258AF78AC4BD3F12817BE0BBF5E7BE284C288C3F9C381D59C9788D0A2D2A2A8ADE61162C78CAD92EC81D02CB1BEBC7C11C74FA5EA3EAE2789F02BA4F7A109782C2DD81C0371EDDEC02CA4A27EF4D24FA59BC58A28676FC7137D70D9F1F795A76AD7F1579F5B2C4D8C8147D33D34D3EE5AFE21A73D8634666B1BE502DA4BEAA1AFBA8CEC178C031B28EC1D9FC25C5030624B5B98898A816D7410AC79AC6CDD9058D74D40F1CEA1B434F15B9F1C69E9F78DDF6F8F2700B5FDBE4F1BA6D2F85C23E923EBA5DFC28BD04D3CF244449E0C011C95B227D63BEBF1450FF8C81C6DAD1F198102FA3E1B6FE0CA2EFEB3FC91E77B671E49045E4BDDC6663B12964DFD688070D3A86C6B9C2330F8B54F3DE5AE971D2573CC46C0535EB184FF63C49ACD9C69A9060E2B58C569D950D6AAFA640D84DDE1276C11CCE5344641A98F9DA40E525C2265DE961B3650D235781C4F6408FDCF92F3EBD7DDF389FA3C79F64C13FEECF6F5E718F1B3159D6B3C900AC60F3F63E9AB3F4F04511C7B1CA79DCA086F7C42FC7D46AD56831313C7DBC4DF9FF3C0D078EC289683D2BE9256570CED02CEC419DCB2574471B3FAE5C6D53F970315E6148B72B1DA3C9D9ECEE96085D10F548388F68D43D6586CA88C5EF511395CC7F8A673703A1C1BCDD91C07C91CB437644497EC43B85BADBF5D7E9ECEB74402C3D8459F6F9C5D842A0A678399E5DE6FC299113713733940D7E35B63E0C8F663B7C973E510916888863033DDECDBCC57271C3A5E2F85C7D27BD4DC424251132456825017B43304664E4F6F61DCC9A952A6E6988ED9C2D474DC9119F0D0802B0911305EB46F0577126BF6C209509242DD8000F44F7AB8ED21B69B3F3EFD7A0A024200CA0621AFC29208ECB4A12D86654EF25C4DA129219A249A5A574C08C01172BABC428F4B68B0F86A7C7606C1A9F4A64E015A8AC217E64C99DAE9843AFAA45110D46D38DD488C3BAAB4A157B7B5E02CC91321A4AB855B920875A607355FF9C480AD6766EA2052DC83265D253E6AAD70C6D68AE50FB35D25CB840BD647E38509C68C4DA572DEDDEC1CA00D8F07C60099608518D8C1CC820EAFBB6E1E4DB4F4F9B667DAAE277BF2BE6BEB75A738580C74EB27D5F914C1B637AD86C1C361B029B7ABF95B08B58BD5927E3C6484A861797922E801226F5DB608460A1F72B84B158C5342DFBFF1DD0DDBF8F277CBD56E367E0A7088AE267068AE7D6B3E1B615203C472E113B6489EB7BB74D7366539A1BFF943FAB46D7987086CCBD2DB903D74376CCCEA6EEA1FB8323FA9CBB4E450BB994D2FE25E3B9AD1CAC64952E5AEC1ECC02B9328CA728800AFA3B0D1EC84C3B7B525FCEAEBE44BAE3E30C88B19E1D881BD0C231974DED30BA6078D7B2C046874997A6665B01C04A9D4998B513700E405236E977161EE6A95047B1349E561BB84F8802A955094912B0C728A2FDBF0884E2032B0400A79774C004CE8C19DA3C410CFD80E148BA39A739CBA394668593AF01028B65FC8B4261C400F270D5FF8B39C278433B2E1E5CFE988BE3388819EBCE47B200662C279423C4AC6C154EB549583226EDFB1D5F2D42FB3C30F08F265660CCA5776E284ACBF5425EB0D1FA6659BA538CC201B892538B3A1E58759F44014DD717829631CF2605661A9E541362C3ABD49F62960FBB8040943540F8F38C7553D6B1A71AA8D2EC625FB8ACC886116B8633C8706E2B3B3F17E3F31106B9F1348B0BA9EF5EE5797CCA4CFD8F2574EA112BE7A95DBDBCAAD157543CA509B0B3C72D3E1DF991D843EDC522FF4069A3437104AC0468C076000B73112D4A126DEE6D0A4E5179CA351246A15D2CFA21B7E55EF566A20CB21799B04ED52F1273FA4B35D4C74D66A5EC80BBF766C3C5BAADB8DF55DD841B2C04DA3F84C42D2742E069DB333EFCB98B38E71F55CA8F3D4CB5674AD3BBF2D776F668B7275BF0BF54750F7E90F38846E07959E9E562ABDBAA053F58BCAEC3DA9219C0779AA88DA9A4C4A1DF600824688036B4FC3806B0B2032A097ABF1D83E0193EF73F95FD2AE7E6AC6DE0C9F7A428FD5E26F7EFAEDD7DAE7EBAB555A208CD75FA01950697B7109B8C945A298EA2CCA4A444EEE131F6AF9345D4EE8F0FD0BAAAA95D295449E75D65FA8D761B3DBFBBDB4086484E7C62F04A600087A88174F32D3AFD12AB8A02F2158D1CBCF76611580733029EAC1CE17A0FBBF482AC8E278FD6D1060BC579BDD8F9A8FDE35E3CDB2DE748BB9DF533D06EA9119AF953233DE17E1AACE4E972746A3CE0CB4F5067BAA0703D3C17588ED3D30AB50AC5EE79BD57C0E032DB382A5F02FFE06E2366C611A4D39DE052650B44309DE9C96EA8FB4612B2B78388496AFF8C2A28D2C3AF058FE5A492EF315AB03BF824A6411DE1AAF5C9B090F767BB441BF52B744F2CFE9938F712E7E03ADF857E913B50F3E6ED1205EC45CB99F57B4237EC856A088806D91C4556FF784983361461FB459A6A8E2E80BF9B6976FB71C3E26586B1B9738CD0879DCEFCA7EB6DAC08BEBA2CF6626F42B56277441CC29FDC51CC767FF41FFAD1F03D88C78B1038BA8164A50194DB96EF7D7D56A4113F45774BEDE15222990F1269699EB2FE8089C2DA941DBA135812F24FA97EB47DD395CA1CAF832383EE569F2016BBD09A71120FC800F413584B9D7A7E49263FAFAC1C20B36F069D099ED138BA356409D78A6121BFB3349CB193DD71E402400B0D531555396AE6888CD5A4A5F1E0E9A5064984DF3BC5CEF3E4D77694BE05508ADF06AE839CF49D4865AF827E4A5F5542C36383808A05CF43339F248B10A539F38AD21306C9858DE2B5F6B7DEEB328735F5C1FF6D743733D8226F79BE43C1C7E74F64F24657627CAB786628235855505D5A3A61B114450D010CF82AE0B1DF68D0ACE60DC5B7301645D6FADDB45D4D45FE71A9124C16E73CF1839E77C5963C861F4ED651C6011E48E03C074F36E20B7DD3CFEDA047C196865EC5F5E7FFB0D0B3EBCB0618B1E7AAEC72A46ED866337F8C773A5F8CEAEABF51093D486214F0007EF86768CB0A197A454982576455CA10F5CACC5FFC336F337EE0FBB6BB09EC90118C4FBDC01118CB1A10F60927D38CCA2102539A33173F4A53825427236800B478C3FA7A7D3FE7FFF6F3066446C855B76B380F7D4ED882722DAEFAD1EB468513E59ABCB5BA26E4CC589F6617799DFE22991B3542715C20F957B3EC4CF32FA183B62B586B34E236968D69A3494137E9603AEC925E5A53BC4F5B35DAFBEE2471C8E67C2DE160A9E1C137E6A2FD8636892C84DA4DCC021DD1A620275CA504202A3A40D4AB3010702C8464A10CD980D3E1BDF4648373C5163CF9DE8EFDEF66A5DE042FB3FD84525E6D05BD429989DA15DFF516C2FB1C5383601DB2A88007A800731FEC858C1E99B3CBB593480F1ACB6DE17D9368C19EC08A8F70CE80595A3A1C69C6CD91F9F128B082A80D79997782FF2DD959C2B94895D3DCC90AB8171C2A0F31D828536B68E75943A84F054D45FDA91A8EF64ACEC8FC4F3838C813C91881F498C405CC3DEC4D27468C92519F1C0AB8FA787B13A686BC791C88C3FC37407F5C6CF01241AE5EE2480DA3D28175959E86B93543026444C6838FEF4E5FFF8E4D38FFFF4D9D9479FFDE9D3B3CBCB7C7CF61F7FFAF8DFCF5EBD7AF5C73F7EF0C75717F45F708090926B6E619C520F02CCEA0FFD75C7AE7677AAD3412419A0A9832AAA7556F8DFBF198CA7E5B59FD6CBDA920CA854EE97DF519D62C6EB97DF552597AD2BEC1B6D586B22DE0D46D33BC1461B7B96B17DFF90124ECF53A4683D0B23FAB1D8DB8D3DB536C1DC2FF28E7589DBB2C0D1B4059345E7CFA40ABEB0F19F0C737159C3450F0195D5055BEDD92862721A8AF6C7DF2B8516A8FE9176C6B7E249076FC5080C656B1F78968CB8465F34532D8B6E98C54A1E6DA4472CB21CC42569916CFCF687587C425F037417A685BA9769E445176F5B6FBBDA479A701FB91E0A3C1860B8BB2FEFCB06C48992C06C0F24796707BFF12312D8F12790B19AE944F7419F73D0623F45FCA052A662B58354EF36A83B91E7EC7360075B94CD7E45CF9C540B9DD0BCD6A2C7A5A47D6764C2A22DEB918C1E70B12F56ABDBAD949D24D585285D3D873E6CAB8DB019CC3103B6ABB020D884FF64888E24DA48C604A7F5BFA5A282F7C6ACDD52A531CC9DB0B365075A146C305680B0940F7250AFAF6D7B34C9F4FC7389C0499ACD2CE74C20D83BF52CFA95E302F7BAB8933EF6A0865A360B0EA8A9BECA25DD4B1DBFB42D9D74FEA5EE6FD3DC86793A24D6C5AC2AEC7F55DF481FE603B3E00645D9E0FB5807DE6671EB46A8828BDD72FD2A68E81DA2F4C2529FFCE56483BC0B960A1A78715BAA05607F6B6BB654826375F3B777D6A30155B6019C6BDB24E7BE97D5A52AAB021841F0307F72B8DB17E146CF676705E2D9F942B5B142EE67DA1BC7174E16827D82F42675D1A9728B06108A4AA515188E84B56738052EEF7695BE63D0F47C9DA7D4FDD2975368C1E86BE45A3C1B0DC081152FAE7BFBE8BAE8D2CDB0FC6CC42FE8761F9DEB9C52EA4D320CDEACD6810AFE0EFE9E7E3F5EED76AB055D7C0531CA487DDF1ABA98E804C23FB00581EE8B206401163EE4B0F5CCC0231A52C73358AB452B667B8D7F2442886EABE1919D265E96AED5639C2090AD7BEDD1E494D2D17309FE1AFCD21454621E9966B8F6A9CA89EE52D0D7530B36285C85184705AA22F22EE0613BE164C3376CB9163AE70293502C8AC39B2453CDFC947ACE6EE40B0EEE9C7346026D5D6B7DDF330EEE8598008322364A003C992AF32A7230500ED2F86660FA11C5B341C63143A115181FD40FC2889BB0247B0E5482E49E4ED77F5CA0A1D346A8A3D2A5DCBE306BFAF9269D7009ED64E1F9089D9C7C389F2D6FCFAF3E6447AEAB0FCFF5AF718B3A4FDFBF4AE11825DE449C8A2479DF74FD7D7817DD1200A410FDFC309D1105B6269E5FCB743C5722CBBCDCF6769097259D232957829D88D30C54DDF6A6BBC5FC75B999A5734443E91CFD1003A97FF7C74FE6B40F92E0C37899BEA5D1F10FD06463F2E8057D9CA3387BFB1040F5564451F244298918A43343D3C00365634A0122AB723682A25BFB40CAD8D2AA32FD1FC26233A58E5C3DD2CC9B6B4CE972C53D37DFB3CB4CA56F36E463C577AAD61370644D9730BD880C76EF9F9861BCAF2FDE3FE19421EFEFF4E2F26399C67A1F8EF5C88CD50E8305D198A8AC9AD22BCCEA92EA9CA8E2DB4A4AAF7A2597B0306A7484BE0A69DFFEA7A47C992FE52BDAA57C87B0216D647C784CE2D812364804F41C8408B1D5664B0E219423F467D0CD54783B2432E6E3FB8CF6DF361825B98894C0EA567DF672150001D48A171E1304664433826CBC14F50B23A4E4B3E8C777E41AE624C348467C5B3E9D73B6612AB958DD6FCBFD7A355BD286D86B4B631AEE7DB4E7A93FE75CC454508F4CB2A4F35FDA43D9FC7E03F12227251EFEDC1BBDE02CC9BDB0877CCDBE67599A39EB0F4F0A96798FBDE488391E7B593C9FAA61ED9CA2819978869EE7C97C95A57330F17503DE4A8C5B175C49CD25C2ACBA531BC7283026DD2053CCD4EAED66494EC877669E104D33B34E029C8BEC7E56C0BE862F1223208B149D5E1BE9DE56CE327327716C10AA43AA8C58D266EEDAB4AB9AE059D0AAFF556BCAB5DE4CD4891C944E7099F1823425401EB097A05869DCF6A8E70B4FF37F50F228E1C410CC6911BEF4EC0103A249A67519CF941DE175126004C614CBC15572C7A980D53AE11CBA52999616F58C1371A456A7888460BAC89E97E97CB81AC1CA942A812890F7EA8436204E97F8A69711EBCDF2E8FD7EA58E7E3B7732C267CC46BC522B9A22AEE34EE42585D20B19D3A94F4B15CBC229B3A471594D1ACE66F147BC2D45FE5C127E22D4CA2764BCD60ED23D98F8CE689D97C9847A8735962B0E646347F7C9EA9EC0F742DD0017DCAF11E1852F9C23E55ADDC295B27349353475898316F5E28AA01B419FD32A526E680F832E958441E90DEAC092E0D7B43C8FD4DCC0BC81F1EA8344660E32C0C1D258EDD5864604F50502CD2C4DE00965564E762C2684307D5F6B5B9AD685BF7B076B191B9BCCD6F6330DEDD6ED45F0F247E0FCA60EE73712D669EA40FDC603F5A906F5E9BB401D21A58F437A319857217D5E85F46572CBA53990D394F307D422B45F5FF7A2A06BC08EEE0807F75E5C831381C024C41562B623DC44B2AC0E0F9694936449FC95EA94120764D2331B66BF67DE084BCCCF0506A6089D2D703FE959B08FD8CE50CA79BE55C18B1781E8193AEE396F05032E631879FADFD4E0E7EC8CA05060E2F4D45C596106A2B7517FCCA8A8C539752DDD14C4FBA0B8B9361FAC95C5B97A4B1931956C8A14B9D64D092342C10268B605A7FF0AE7F76D6496543EC7975D0007C32A00BA2EE6BE6559A1D4689A680835020151443938288DDBDD5668DD087A1B24439AE42740E38D896AA4835D0E24616F9CA93BEF9D5D392E60EF3C008E25E9FB3499279C49FE497DD0F11D974F4FFFBD76DFD139CAD6DDC6F184C1AF9DF494AABF42F0ECF02E597B4D52EFEFACACEB4EEF2048CCBC4FE320FAF00239CC097DADA197F084E3F047A1CDB1E8C96AAE5553FD044751D0CEDB37D2B5A41CBC8C3F50DE1424770E83FBCF69A512EF76D0BA0DEF7E731BB2C78C8216754BC4BD31FBA535E248C2083EA32FA18E32961C39EB5D2A224C058DA3BA6DA096B5A016B8F0DD9AF9874DB1BEB409D173D9011274049BBF03825CE84E9698CFB6E25A0105CDB318B3DD5650D57EBF567AC567DD357635C22B7A0E687DE2B1AB4F5626841C1DD4D33E62AC13115CF3937D4270127D5A581E68563EECF7735D95F40B316E0E4B1BB2881A5F0D97885944BDC70223C8793AE1B0CBAF772B629E0A82259DBC7A79753998C5B716D56228E32434C7C6D46D44F67B19CA672377B05009D9C20423A2A9E0699DC27A6E0CABD829644DEE0DBEF454809C6DC4C240E56BFB54BC13327600A3BE7C2A3311469AD9E771AC196DF370F5FBEFA434060B99F82DF5575E0006CCB56E4F47D1A756859BA875129B9646521048350182900246380752A30B11C7A8C6BE4FD6C290511DA1B110DAB052BE5E506F045BE1DC6A45CC8C1CD8B69E89D9AA8DA0DD03E3D963E8B997549C4B9A46A8376EC1592A595B7321A7E5E86D6E33FBF6F980F59889CB72EA3688EC61AE98568116F153DD772C84772BDDD28258D992CF53DB9C26B7B67E2975034ADDC2FD98C8824CC37D7A0CEE9FD35E7EBFC1E6D11D1B0B1F3071F510E3619B1B4EBC0ABF5C2CCA6286BC4E6D358754C6C79170CDF2EF3589EC910A00CC54374587635262DA681590839C7E08E985617DBA4B4B958CC4134D3E87A858F739D240AD0736F3B4FD1C93C36CABDCF8FDB08171756B29F105F2C6097F2B1B7E8CB6CB7667D60D1E37FE7D651D55EA60D6CCE971ADA789D39955491F96C1CA59C007F1E9E9CCF7DEA6799730DAB09B64E94AC7F08046C8D961F8EBCF8861F53DF9F0D0845CAD5439B381DAD9FAA8AD621D609043A75DF4A7DAC50A3150C62336F5F6C36928AB202945A18A1F900C1E0B3558D059C63DD29EC93390063AE4897EA593FDCD6CB23FD8BCA3421D71AD88FAA5250175CCD26780413C73D35F1EEC4A4E3FCCDA8B7363F68B4CEB72A730499BC09FA5EABC0C6B638FFAB051742D022A380821260E861E46ED41D5B0F261588EFA133A35EB0F9349F24FC3588AFA96C534A296FBA9FAE6B67C92E7102914091B6EAFB7C693982E8DD5877E13C5EE155C213C6A690CAC5254F9838CF5271C7225C5D28DE98FD5CC3A92C55C1206D96E722DA6C149AE3E10B904BFF521CD7E615F5642BBF516E52EFD6BF9942090BFBE5613ED4739301721DC2AE294B550EB6D1CA4F31D953BC944767692237CC71CE07C92EF3673BCAAE0C013DEFCDF11DF088524B771C271DFCA42176052148FA58F27BBD9A27CBD4B17EB93B744902084713E0D3C63186556117228B734BA7B087272823F9FD0204FE835FEE1BA56452DF48CA7033266BDDC30CF225F9988BE3D53F9C05D1210EB569085EDA03C5032FD122C72223F346DF3194DCB8FFAF7A793F166B5D04B7A22C69C3FEADF9F4E084D963FF2DF9F4EB6F9A62C973FEADF9F4E762BFDD56F0FCFB700C93456E374B15EDBFDDA1C70D3267826E4C6DC6BB6C7B03055A72C39B051CD069A911654134AD7E92AEB226A06B1446CE60CED9CE688FD0717D19994926FBC52FE03CE4FC9D3646BFFA952FB9BD5BA5239DFD7EA7665BC7B0494E9E0B4F1E096C9B6B0F690B08ADB8A1C194D4F403C41E718908C6960C2A9222D785D9E8E11AC8EFE7E10BFA2BF2FE30B01267D3AC7CFB04347DE1E611F38EDA2242A796E30B1D674070773062A55F01F8A479ED0D73DA573B973E90B7D5545601268D97470501048B736E9D599549AC5173A000D2EB929DF12A4D1CEEA7E1740594EC7E2BB5AF21CD985B6D4EA3D625CADAA897AC20DEF1825F225D76B02E288EEA3D22143C0B7A9E87DDF79BDCC2A48034812B2924EEDF27E29CBE4532D558F2D171F47A817C80C4177CD96E95C0B11C3DA939EB4CE4A2AFB1DCCEBD476B6B89F57DC20B5284FF67BE924B5DE2904A3119656A46AB67DAD6BE0640E955609BF1EA27E31A8B1116169F22437C5DF5AF00167B523DC52DEA007812F7DF950D2EA6C33A80E10B4764B29CC659BEB0D1BD5D5936B3BCF6F5122F52BBE36B40A5A9C914A4E6918F6F3A5706155C71CB0FA11062243683D580070958857527810B29F1FAB1504282BAB606234312BAAE91C7ED09CDFC48682B48F3C64D37C29B3E5200B24FB20CDE22CD3148CB409F7700B46BCD1321D1EC11ED5890CC1DC42E2B7241E56D80331E671241C44D1514586C4665966F2BC104FCFCD3152E7541BFB25CFDFC145A14015F47C8C22F602CDD9EF1F9DEA8C1D2DEAECCDA0C9EFC4D5490618AA1A03F4AFF4A43932D7975AB526EC4285D582EE9D6936394612B63545A9B6B9FB573AF68EB9D73D94DEB4957BD73BEDA0DF1C09230E09B1C30417166613077C4D186013081D362FD3B7A5794CC783D29A585D5CDFC907FA467F625EF16954DDD20D49C52879AE1C649932622FBA1466A77A0C68EB2DDE4F82D43D3A824DD62DF3AEA9B2B003565C6C797C23249347429B598C2D174F54979536B4FB8F1BD30C5877C21352DDF644E5AE55E3C806591DA97E9F3CB302EDF71CCA742A2E82086E268C8A4C7DB0FC92027C06F77E918A41AEAF618E671EF841728D33903D7A6176669BCB2C0120F8C73DD699B02084476F4CBAF7DC335ACE555019395B1DFB7DB505DA3B969AC7BF64665FB1D5E491DA251A256CFB8ED109F50A9D62A3FE4687AAF132ACB14449CBDE9D1ADBD00A61600650FB50A53A48A6D1E8FC1796576B6CA48C9DB248604C8C398EC398BC3F0E633F0A7FCEDD37DD890661D84EF6EDF7015BEB541ED697573ABAD6393BA503BD5F8C5BA8BF308136D091A09A553ACD7C8F0E9DEAA887BFDCDC6F77BAA682D1AD13E13636415B83CD5AEA2BDCDAD0A56BC6ADBCA95FF0009BC5471EF5DBEC9750B56C1A4215B477B0BA29FB7A755C6AE0C8DB67B41B2BABDFD867B6407B5B9D1ACC4212EA11B172FBC66864DE3D010DD0F7766CA39F76C71E41E6DE0478F49E78B2BDAB8B1A363B1CBA9C991407C5F6E1C03B0DDE8DD12D17F3CE3DDCBA47F5D41038B4EE2FD9BA9A0FB47BD79CC0C2895A3651B8449F9B6B1146548C701A4B95298BE6ABAA075EA97EFD04CE462DF842C87BA159AA620A7DEE9AE52E602C5E22054EC3D02315871CE5155570F6BB88BA974770E5BFD4ECD9651F3E49AEF21231D45BD918AF2B9E461B95701C83AA917E25A764C3BEA36A666C381DC26E0D57C5D353896A0413606D02CE067A6331B193512E39FF41AE5248A8CB46705CAD60154912C2C884459221F387A931D62F60CED0E21D58B0759829AB6FBD0E412CCB5A1DAA36B331053A45256CB2BEBED42E1F08BC55B446D9082548440A9B89D64D86148A6C9B63EC35C249CD2E4DD3AC4DA7801A7E85ED51CEBE4107B55AB6B1F1BEA4C65B49801E75B29DA15525969729EE2A378227169198C9297C5A1361356BFA35998DC2D3CA1796C4EC06BDA0EBBD8ADD2BE5D414746914483C2FC7808FD51E3E5851BB258D0BF994AA30A529E22C11039363DEAE1520E15833AC94A2C7D96FAC908F1B53BB440D59549DBF3F5A9F119E609950D0AFEE0B6D2AD7862251D68F7CDF90C6A4C663D0607E3F9E4991B9E3A9B41EA57B36744FDF69E89E572D73752E22A3D1896AAF91E58473C5DB7E1E58FC9425419A659B7DBAD9CDF279B94FB7333AB2D37B3AF1F65931DB1327FA36DDEE81FAF8CF9C30DD1E7295D97CBB1FCF2679CA09877179BF29F7E3D50A26B4928C773F9D106BB6DE2FD2CDED7E51E2C5327DBBA7D30686B9C6AB67BF2D792AF6DBFB05957CDA4348B17F4BDD5811619125E727377F4374DBEBA29B04E180F1D09E6EA2E07CA22659E21BA07C48EF836E99758368787DBD3DBF1A05C4720448AB979CFF7CBDED9EAB195D51B10E8C81F719AC7DE77B766DDD4F37FBD962B217B36158DBA3CFE99E489074118508091F8FBA12213EBA3EBF3A9FCCD40D57A6DF9CAB5BDCB281FFF94CCD71B33FFDC3E0FAA1DB3F570B6937DEE69BD97AB7E7E80FDC4A446597F45213AD88473F88873F27A37D42D7C6D8BC87622B8CE2BDFDF53995B849DFA6FB325FA491D448AFD7788D280254A0F782FA7327A37EF1610706C9C34F3EFDE8CD47D7C3FDD959B4C783D1F508D75754E23D9ACB4D963C4BFAE87878A9820F05379CD061BF9BAD895F7ADF5CBD7F45B3FAE1B9BCBF0A468A70111D68F2D57856CE0B3AE6A58CBB1B29CCB89459A46B79CD1723C5532CAF04E7C85B738DC408045052401C38F8BDBEA4D79B78F8D2BE9315D045F8D22B4ACBDD52D616A4D70CB3F2B5BDF3DBA27E7CD0F87EB7D1ED6DAE5A1AB5F2EA9AB7C76078A10264A719F1D87EFCB098BD957AF8627450DB2C210CF144A8304BB659C5F9A1DD329FF677D6A355E47E27724D2B4A8BAB1D5370815D8A0B333EBE968DCCEF31DBFCC5946F0B87AEEEFD3473ACD845F851733EB47AAE1089FCD741FB2B9DB1328A6D051CC7DA04DCFE083A2DFEB8FED87EA8E504334E5AC6344FC2B11DFD98B744CEF7453F06B2840F2A24044478118F57068D36181B45BA8D9F3B563464A6DF0CE274DE8E4471817777FA06546103EFA623C5D9D8ECDCBD6554FF434F2718373CAE95FA369C696A4923BD83AC1A2098E12C882A7D6986A8F6FD95E89B0D07147EA78F129D6A60852ABE3F5572B90E82FA4368A36DD71F338F72D3D2AC50D623D181D6396B436A2C35A36E701E74B520DDABE8C93B2AD7991822EB69346B930D8CB86C78398A8DA6A191F8DCAFF5573DB39560F5065E0890E0B6CED1E63D4991D86C7FF6369D13D39939675F4E4DEBBFF563807DA41B9AD593FC62DD9CD576550DEC2CB8D5C4DE205425DC4585CE605A6D1A196F9F8931AA9DE8D71C03D9A4D298F2269170FC53F8D1683B071352BFCAE7E70A65300307891D02A2BC1683E4F9A0745C91C88BFAF1711D4FF41BC3D6E9509C10A21A404775AA9E51A7A7BE892B7C2DED7408B753607CA51E74543568E61833C6A0B99F35E0C2561C1D02394E39B80EEC0E619C23863FB0D2091F9105BDA7736170A6A9273C8962CF23341F5472CA9DC2C6D1FADA412265AEA38A1B1F487FEBCCC60219EADEC27768147349E7F0E695470F44B62A1DAFA21974A8866532EBE0E73BEF71C62F1E2E5F717B6FB552937F79A46B4DC8D3486DBD829DB9E2ADB94CEB2FE3D0EB24A170E395C5F7323ADFDDCF55C0B751255AC9BCC98D59E6CAA48F4FDEE9090C98F41740022748FAB110AE699D89CE14187C1874FDA85657843CA100A8B8E9C5E1AEBA38CEBF7267404EB0289D983E36867C2FAC437BDD47527293F8E9412EAB0F6ABD8FF44EBF475250C21638B9233674D4B80D086042B8ADDB9D44052795FF981375F243D8D672E60CAE659A4CF77BA9806DE0A5CE96BA2684423E72B5309BCF786F6C51B4F448996D86A8703A48C7C5E9E9AF386B3BB3D353A6336C19343B4D4AD6EBAAF14165F7346B861B6AE1C80D2EB770A06EE01E90585FEE15A8AA0C86F6442DDC611C57779C7196868C34E0777476EFF76C0012B57A7B8FA3C81CF46BE562AC0C86E3513C763113E71A7EA8F8334FE2AAEABFDA4EC211DC8637FA801B8B4F0E68C4889389567024523A0F67744A139966884C35F5801011DEBBE39E895536CB88B87CEF9268D3F75E120C77E788C25B260806EF452D82B5BAF57665DAAAC507FAF4746A07777ABA16C2C90C0831F5785B4CED30903E95913AD308B44689A65B088867FBFDADAD6C60697C7A83FE575E5EC4D378EA5332A584C871E45E330A934716DD247E51A20595A15908E1DE346B41D5FECEBD41C44DB3EE533FB1829AF271A0635F268189BDE077369A562AABBCEA4F919AD6CCBAF8D91C9B55022744F65F556B6BB86573983224C8E374EFD6B5FE6D1631CC6BDFA7643DBCD3F9943978CCD92583B9891A3F46407A16C679B8745CC3A506C354C17B1C79DB7CC2BB7B0A337B1CDEAEF9E9B0E414CB668D8D4628886CEAA3B13359151CB092401D1CFFAA2694317BDF2555B8E073C0C48F83CF24479752F3BA233561889ACCDAF10D08821071AC04CC13D37C151F014CD138299036978336DD2058079338860E8BACECCC3E5912005A7191966741041C57A9170C6562A917D4EC548DB853F381BE43FB86992AEA540EF3528DA7E12C8AF1994CAC9DF0167135BB81B64863FF2132B89637CEB26520993EB9A4365DE1F022A189D919865A8EE6F215351C62EADB0024A7583AA58D4835F4462A3E62FFD62B568BAFD3E56CDD9AA4C152E956C12227EC65CBB3FFA83F323C0AF16C229C04C5590DA07060C5326DCDFF733A48DBBADCEC3E6665227652255B0DBA2B7AC6FF646FB98C4F12D71ED49BB702D874BC3B6AC3F8FF46A395846C87A8D511B7CA2CA6039BD9C64FBD05D18863230B2B76C88490CBBD05F283F91112CD391A6C957F008F68B16F5EC3BEA09C09B7E2539F66F2EBA89C14795415D5AB46FE0F33BE943D6CF428C4B408FE761C9FFDF932A9D2A3B561A41C45DB64E1F2C129ADF4A6F2AA9F6A81D5B626590984A9084462A2CBE8BD9EB8D071329E266FE0C50FD296D3B0874875001D44AE4A6311FB7358C826BC2D84D637EA0651368075F89D1851769C466DEC9A98D3C154F811A06AB1FD3C6558259FA625EE2C5537CE90E0DA9785B524AB2530B369CFD929B222893C3D9D54DFBE83DE4309223B2D899ABE8B44C52198B2F1542B05CA6E71ECA5535CE5FD1CFB4326299749AA4B4AC21A90650C64952830C066C98517F9F690E99D5F3B71D2779E1EBAC3D59C32C6C6CE96F7143FBF899132CC440D05A9DA78187FE8BC12BA079A553028511B124A3FD9CBCC60752FF89AA62538281A4C60DB80D42F28B615CAF4BEB675E092265A566413D351D655E1982B82E4792596D952ACE656C9FCEC92982C0E0E759754025BAD99C9BCDBEFE748FFD55029AFD913D705E7393D5D6AF05B47BECEB8A6CEB306C344B6DC2151D41DDB045F8C92B5E7999643DD49E0CF69C40A6FD1785FA35FF0BF04D558E134357E6FD0260483B23A1C1FC5E34D00BDB336A602C154841206EC83B406D6A1F59F7914F363C64EB4063BCCAF6EFA37EC6446334E2708828770D04DC64BF0B667CB833110A7702813915DBB2381230B995980977EA16E78B863CDE64F86A6B9B3CBFA20A58F13F594C167F4A23FB6FD99A02A43BF173EFDDE71561315B168E53843CA2B8C054E5330B328A9C8F79B397B19EB6B7909BAD8D512A2293AAC6112E2715EB8B5C840A25118DC73C778129EC3897894574E0D31FA62531941106F5671205781A1D5F0485F06CAA71E626D86659E7EC4644BC0D44B6070099223061E5E69B159ADE5E24B9B4954396D2A87729B266EB1FAD3AB4424B8446B10D44D3D642000C25629E104C25C3AC2433868EB4D8DA85A93721756A982D6CC7A9F64EAD3AC9254EFB32CF4056FD4B386E2393218F7CD8A5E32F7CFD6B3D4A6367AF864B520D6B42C5EEBD402C5F1B761C98204E2634CC47E890088C75E1040339252FB0020BC95934E7FEE69129E68D37E8ACC385631CE49C23E1301B60E34D861992ADE7C9225F48F0ED330F85012339EF05FC91390BC7FF1FE096707E02B495E80CB733AEBBC69C8EAEE571C74E813E4D7AE2674DCEF2B0FCD668CECF7B4A31F367446873A6A188B855CF73FC9EC04448A87C988E7D088C4D7BFED6DA784826F7FD8A46BCE62E00547646E43A8C0D4B977A648B4C193C80924CCF4FD4B792406FF97A591387B28B3DBD9EE2C5B3D9E6D67BF2261845E3A3CEA9F2D56BF1E7B77E4B101F30C6BF22FE7A5F85D2A633D0881DBE08F989234F9A0534B5BD14C51E162BF1E4CE8B53FC3E2403A79AEBEA81A67FC1C06DDD7DD200A079DF563344CCF7EFDB751F73D6DA0F165A6FE92A9BFE2F390D668BFC17AED330E0ABAC77221901A63850A3A18845F66157469F58C553DA51740A35107ED1476183A500F1A2134ABA2A454A6CAC13AA1842FB5603D1F301AFD4E1B18B3C682A067BF479E2A3D4F1CA139003A9930DB775C37C191D216D21C6FE588A6534ED8099D967FD6D76C43856C9ABC789CFE73315B4A9A91316ED247B971CFBDA7E6BB6482FEEB3ACCB3C2FFA654DE57089D6C1995C960124FBA417088E246621D136CC1E0F5636BE517FBAFAF8237DDC2DC210E094291209F18CDEA9443C6F8B3D9F96B7D3A0171E2F471BF14A7296A906694FD50F9253220C865521D003F833898DF05635AE3D7C461719CEA4170592E8218D33DEDAD678F25BBCF76036C39FD41E1D7DC3AD344D4A4F7BB55E09B917D55B10F782638AC332D79928636534C874E01337B12294F0B10F9E4C7D7A1B94A32135242585F676279689C225E085DC5ECEC51E4FEBF3D4A2BF48EEDC74EAACF1C98AEEAA303810D2DCA1ECF57E92EC674F757C4E8CE764F71EF8F880CAAEF92E082EEA1A0344FE01FB1DD7E8EEF924E27B737CA1C0788F10DC31AC2BBF3D93A093C7C1E34827BB67FC2A149118B9AB91F06AC6A3DCC18B77D4B1FD2FBD77C92249224C63D0041CC4FBE5EFDFA71E3E10F7C78D9E7CA6A5B6F1541D67C8655F9625614E5F25B3E17DAF277DA2D370B395A846DFAEFBA82A3DF8CE59BF141F1CEF8CE9CEAC7CA9752BE04AF2E557FCD07CFDFF9A83FF6D554BE9A56AC306715009EFD5F990CEBF7D02AD2622BA9E2BD6A7FDA46A89CA1A397FFD6D73F7A4020509A64CB2B3CADCF4100FD1EE79FE6FC838DB31BA832092EFF0D476AD87C4DBC091FED122C071900C649400D01DCDF5D5CFAC465E94B391967C9EF22A7D4AC36D3BF67E6FF3FA2122F02DBBB85DB2C8979A649C08BC0428B7E72C92754D2E1941D8CECC2B6F99BF9D3ED355013D139EBC90DFD2B80F00BBED8C99536A3D4969EB3A3A87D57D04642CCA9FA04BF6302EC543163072306086958A6C338ED0BDE635057865ECDFA23E0E519649CB5A7EFACAB2DB7DB4112AA6D1FD2752306BDA0220988A46DB7D893238B26C3F1C8503FD0FBB94B0E3CD4478E0C39AB539DCDC3FFDA2B8D8A2C8BACD3A711E99DCED7D3F43A1CFE1C8D5E5CC3E0F81B7AA80FBDEBED0BD823CBCBE85C7DCBA43A06BEE78522AAFE2C1F96E928EAC114FABB23B47FEF456448FEBFD58B204F4094E892BAD0DFB3E4D96285C0A185B7B3ED2C9BCD715A07533E9202655636E05D101CD46BFA98C89A5DB9798D41D0F203B44191FD20983478C57989DE64C93090C38F9AFD96FED1F1487F17DB60E40E89EF9D019FCE87A667301389A88E3CF3D12EBC00AEF99E30851682774D08A54B1C0819E1B4372DC9A2985E7A834C51DD5CD55BD017851362FCA369B8C826832C20BA6032593731BD9AB0650EB4D893913979A0B04684394F44B79A1756822251AC7C30574802465F10B960852212BEBBB64522C5F444EDC5E9E9F71C4BEF5DADAACFB3B0700E6D11B2B09609BE53219DB77EBB9D327271086BB594835C8B850A4F2604C99F885B2F8E4F49E6B5D21840D0F2B46506B2819EA62096BA9C64CD333CFD21AB7037C9775A9D923953A9C1D7E98EF9AEF042158476CE901AEC228ABA6121A176092B4771E6EAFC313348048E640632C609FC6AC26210083A44DA2E393B8268F02A0E18C70B7F72C929A62FFAAF38A259F232D2A8545B1586936E62326EE4DD371C30F702CEEDAA1884B65253F6CC960D34FA0D2ADF98BA3BCDF2BAA35C1C79B8D141FD198184D78BB69ADDC34EA3D7EFACD94CFCC4CDE84FB55542C9C49FB1D49791C469F5141927862FF5887282234736894D99ED9B2E1240A5306676EDE20A59C135C5CBC8A74CFE229D1AD3AEB8B8F2DE323564D0BCCFE496566752F60B10E7A1D71F439823AF61C93A5D57419978273EC21BDB649165D7001B44156DA0050D51C4BCAD6FB6B9DDEAB05B86D9AA32AB16C31AAE95C71AE8C256B0AB935F0697418CB0080745F57E73BFC8E8AC7FCEE988582C397620672398CDE7DFEAB6703B2F1FFFBC593D98EBD72CF594B405F65CA03BE248CB2FECDDCA552014055FD069B9DCE292E061F5C057BF7E89E87D7C05111C424051D7BEE31063CFC26B06B1E31F0781B9A299E369971B04FC789AB7791BCED86DF0839A2DE8BFD7EE53C3E87A6690492D99E1CC0A52F8E46128E48E0EA72376F9F7EE93EFA19B9A4662866E16914084C558E6763A72D20A2B6000BCD3120733BEB4C195085227AC76809D006CCC06653CA30A591D6593A37A992839E76499FC4DA3C93C12F7C1B08489E365F4A22494D8F5A0D5EC2A88CE88EA5F3274049243A3C3E27C8DA7CCAB0E87FBE2CF0494641EF26EC278B6C99003C3CB6174C1C2521B9CD931E48874116258098D7F5A6E1061417542CCC9B6362740D1C8C2B7E539C15AE33FE8C7F97B93CBF5061A6D06AA16E038BEDA06B5FD8E75D650F17B56BBBAB6C8086A96F402DA4D070D922F54E32D183CD3C1B859A473BDAE4CEDBCCEB8D0EB8C314FA06DC4F34158414263ED257A21F6CEB45234AB392241C2E33B66971BA7CA1B06C233133127387BD450B979C34BEAB8C8F7EFCD07DF6A6C6AF1B5232D4E4F25809377160C84BCA7727FCFFCDC2ABABA9FCC5C1CA2D85EDBD800DB967EF0E2428AC5678A59502623E8FD40A3E342FD278E1A84038BE28B484798D1D8CE00074F8F1587B5E06BDD956FF4FC8088AACA44073511A90E7FA8214DDF46ACAD1DF42E2E5F78EB2DEC41EFBD4B3A4A823863941F048D19B2E78581DEA22696659F7E072F59340898DD09AD98AF7B7971F102AEA368805006CB0BA56B0486F62A08FAB94EDBADC2EC2AB9D4E233C88E036D220EBF0D6775FDB5E89D212FAA195F0283359D94A4254346679C53A053B8590A4D6792AF9D6174A5395ACC3122CF764B9D1AD0AEA2CFF57F951119D0223B53ADAB9B39807EB69C96643D3F330CD75F32354C0D5DC775052EA3A4D3AF6BF69C66D9B0E574A959754D923555E3769FA65DEC54B1E77520907BA6BFAC287F3E00ED37D26D0F722F0E678C40AEAFB4EF534935BF191623543FA6DFFD9EFE9EBDE4DF0B8F5D3E28A37D61354DAD67C0DFC90F5954B79EAD23ECE3C6623595070602927C86FCC92E97B10CB7D004A6977DB8D4ACCD7898111732B25B1E7772D49AA18C0D2D670F65D85FF0F6D1BD88DD217A80D55BC350EA8A63A54D899C6A62B87F68F352362D221EBD4DF2ABCBC0D37E3599D482B668522F5BAD6022E5D6301DE844B06838D4E6C468C05CD75DFCBF9746060BF935DF995BF994B3683A6EFF9F1556CA8890CB077AE1E2DFD1913FDB79E588D07DF35096CBE49F99F2CB2544942E0914EF39B30EBDC4778DF31BABADAD56CB395211E91838743627B90986B085581FA4C7F681B1373FD6F690496602B1A59B9DB1F97D908B9CC37A4A25CB2229E4F29EFAC1414E7DB2271F0DC0BA82E8F9EFFF8D488DFB8A01AE58C0C9E8D602F7B69B2E2A324E003A28C4C5549B7DFBDFB820FCF6FD416DEE971500D022F9DF6A4C9EAC68F8893F1BBDE27EC381E86062CFF336F4E67014A6AAB5F48B545DA8CBF677516CAC84695A433399676ED2233A40DC5DB592EDAE5C6B4B44FF91B3C89290EDA67E6352C66A069A49FEFBCE99B4EFF953C2530D50F520D27FA7FCFA926753619D35D30B62A65D1BD272AF87A92C090C12716FE429DA68C47B664A0E0CCB11A63A17173FC749897096A2E204593DC8883089ABCDD48F7F369D7AE4E9B4F5379E50B1B8DABBB0A57B1E39ACBFAB52BDFA61E43065A5FB60C21EBA296FAC7AAF99437B38D885D1EB67431D272D8FA11FE6B04995D1EA1EFBFC1E3FA8188DB7356E4232321679C6D99D6E5A70EE494A330CFCD2F2AEF7C733164BE52B5ABA177CF9DD97D1F94BAE79FC9834804ED99580381B20F45EA67EA1B32497A47A82F9F740CA7BA062E4D2CBF29A6C78106BF1F03E32A264B12071F2E49CEA73396DA992224F86B37CA4CA3C790E5E04F1B08D5E14E4288E2540DDFC8E33590BC6A493353782396D0030FC6054C398A9C3987456D75E899CAEC38C4E17125053A1807FAEE1278245DF2571E52FF9AC27DA7D420DE13338CB118EC62D75A7E4541C93A40B97D07EB13A61C7C2003AEBC9793255062E4DBD6AD21D1B33FC2918EFA919DB393A036784E9E9E9D9D9CCE55F6733895C1F23DDC97E8FB69006548E0BE406A623048CF760D2AD30E071177F616136F28C04C7B93BF10994DFCC1688F3E99FD0EF9918404436BD07C4C0C1699D186E927B6B46ABF3AC55A104A7F0B300299489F892C8B9B25F769397675994276FE0E2570C8DA4B18BBC0B432733A4DBD472C66C836AB881426BBEE0F2EABA31CD0D79E6B999256199336F3C1C4526CF003D21881B01622050356919FA139D2982161813381E09F6CF415A59199DD7E0CC36583181B11EAD805EB50289B8B69CCF5D4512F43DC8432FB523526B63AB0511B131BC5D3863D1A296A19DF3CC6BFB9929AD3BBF44F02F77C38E75532F77BAF26F7CEB41F7CD7E3F03A5A5DC936E572D7BE9FC217DDAFA00D1F6CC7D7476A65CE279EEAA35889F5693B973F4C4CBA42A1D0B8D54007A31DA3B221A602519736408353B9ED3113F5CDB6BE52E7FF4AE7F1A8947614D20A0E6894D517D33F026DF57B1ECF7304475EA8EF84669860A9FCD8D26C267DB458018B100578AB2ADE637C824F255FA44BB8A33A6731DB4B1ABF50FD69A6F8DD74E5B53E1E0D86BC80CED14B9CAEC54582D5BD3501482E3B6F5F2BE76B5C274C29B4AFFCDA5FFE627FFCDCBD121F2A23CB06B3A827C14233A45049996E26DA9ED98F81563CD408E17CC22640084FFEE06184B09812BEF03FE4EAE69CA90316CE305E5DEC0621A32EDD9F2BEECDF216AEC0A31C637A7A71B66121DC754E8F478378973C5A9E7BF5B4591B7C6A1072475588878FECD3ADD8853F9F366601682E6018145EF9031959F4471DB3657488902F19B299674EE2275378009B9618496BD0226E2DED2F15BC317A9E67B21041B79FB2C6A61848CA55A453E47B98268EFE0ADE42A9A248454EF0698CBF88278A025215CBCA13508F1101251A6A5E1C931E183C73CD1BF9E3A86F08BD9DAB8C37950094B72533D46049DBAE828A9E0655F729A330520D084DC2FCAF1E063D1B770A25779994050405BA82371123916FDD8E44F44819A40B51009AA883258888AA37EA27D9521EAB4DF1623D7CD7124BD456E0A938E86D87BBA2A3504A2C349E9C67DDB3C46F85C2A72E3B18313E0D3725C6E36C802D0B299754F664C551C388DA67B89EDA84FAFCE65DF9C8D59F21E61571CFEC4C379AACC1B59379001DD1BCB5B9D09D975EE9E80E618279767052BB467C94D6F070ACDF9CB694987793E9C8C60AF19BA601353DA50BBD9F809DE163403C31B5A6FACC2E5158CCD06791CC2237FBB9ABF2D6D911147DB3D105A9F82905DCC080A242D52AA33EC386DD601B4223173DEB3CE857AD6DEE39F31998D240DC86867E2107F2706C2B3721B67F6E1B7C210C6B9B25313DBC933F311E7766A948C3846B02B47BB3A6ADDD3586A91048DED067CE796650D72D9AB74946918FD4238043B8F76E675782CA2893822BDD7A0A1A7E1D4980D6A4B15332E342022C13ED91D1EA9CA8DE79F5DC65C96F1D20BEBD45C26459824C663A0D5CA53CDFD222BE40DF33ED216EDFDDBD6714755AAACC82D597643D4B3F9C65167A657E21075ABA63952D1559CDB4C332C12403263776B72B0F227C417C1BA78135AF09929036BE972B6208A80A99C58D7C037A06878601C3ED1B465EE23C1D5FA29AECDA0F3D5628D3D1CF5C6E96C6E4AE0DAEE77FD4CEE20CDFA883AC10097385B50E426C14235E26156A62045D021E4024C84128EE105EA24AF164918BFA6D4C92F8D2313B01E316F8CD872F6081DEA7B2204B79C1F35133FFAD6744AD9A0C86D41E2FD0B1DDC20D532710282D20F2FEBABF953A456AD873F1DF81B9F2A7C36331AC31E05D1A24427E5CD0171E66EFBA64AB6552C45339D4EF273B787E8F9C15A7FD8CD9E30A0ACC6E3C1456C9495B657AED8C05DC6EE12278530E018EE76E05D0F5D296455B5CF5D28191D16B8308C82BE60FD9BF8ECC9BD700BC43DCD0B6498D4D3A2DCA57F5854C6CCDF44D0B4D0AF1385A132AE1A363E4529A43E333BFA39BC550F5509FB3825FA7ED5A215F5C584DA53FFFB88296A6B57A02E0C31040A030720033E617EA3F9CF0E4AF47007A5DF1DD3BF26759A2F8D38921B4FAE642F061D50A7A6123AA47984552883194858BA18735C2418CF96B3ED94954AB0D45CAD430EB9AD478ACC70789F4C900077EC16ED72A025A0F9349C6861B9CCAD2EA426511DB357F6852F0E925E4B5A90BECD7C803B852006A6374D57F45313F617D8C184FE85CEB023D17FBD6EA5881CFC18A8E1E8483460E9045BE568611ED5D30D1C2F1BF0DC3396DD7A31F418C8E4509A0C91D2167FB9F3048BE144C235985CD712B5A55930CF8D798DFB488EB5B1C5666767FD688C4F80D63B1289432C76B8AFFC8A7B0B0B0EA2E8F801204C9615A97061FF3C3699C24B85A80A8840D3C9A3C6EE48392E81AC7EAB5CAF63B27E267A6ADF35AF9CBDC39B2FD0674333BB018451EE56267B549DED6250380A80E9570399B4628683978EF312B37B8DCCADFC7A4EDB7060CDDCC46632B1994C6C22138BF9CC4616DE0169FCC0CD27BB489BB9CC782E457874415440C6812D0A7614C25FDDD9CA8D87A30CD09B411DA28AE581663C95B0964A98CEBAFD81104DECF89B8DFAFAD73F942AEA2791B8D3C2B5E8C4F276371DD9E4069D4D72844C40DE3AD157794AD9ED9CFAF729E2E45321CD1A2B7EF8FD9A1F71FFF5A337A2ADC3633D4C9A56C2BF5F2E9D6197D471E0E7DFDEEFBC175C93BCD015B977BABAC36FFB463791BB19656650350F4FA01176B19AE0CA6FEBC8975A70609B6B81A29343F6739B299529D53401B7A552083E70255B373360959F9D1160F5CD27C0DD2C00E72CD34ED2E9D17F15BC6A3A62A815B463B4192952C1C7AE04AAD4157126A4B7E93CB9FC40B9D2FE487F21A411FE9225DB72F7A52E1CDA29A95612995AD16BBF0E3681B25FFF42ECCF2F1243C594670A2221685A3DC47FBA20062EDDEEE2977461B54AAF2E2EF4C94DFB277D4AAAEB6C1015133D156A0592F49463B664FA54F00E0ACFC4C63BAE3C613304ACFDBC7D3CA68C8E74D4040ED1CEF6DFE1CE462D79161CF93CDD6E21C7A16DBFFBFFC9DDADD155134147693781E37E2C3AC02702911C6D474793435B0D572676F781C7C82D3E7EED4D0DBD939C297686204FC4D7C9397D756E62484C2AD3C905D09DDB1E66E81B361D9BFD4AD47B709E8AA979F50394128B3D4CDAB74B4EA0CBF14BD9BAC9052B2D6DB0527A51D2B263AA3B9DC68C8C39879229A1729B211A071957F9A97D50DA97347D8D9A4C14BEB40632DCBB80D59F10ED522171DE4B6B439372F85EE2B2D28436EA421FA92AC95B83FAF8EA1FA67C62E3BB1AB7ED799E9C5F6FCE27FD0A414D45DAD4F11CF61B5B0F56316C8F5A8F9E633898A4C60DB5911A7AAF96FDCBA416A68CA56B054CC7BCC02DC66603D80771A6B58AA21CD0C882267744CFBB78E1A476DA4A5A98F7B22D6A9D0910459FA5ECD81CF1E9402D7A0608A89F85BFD5C7467E5B0B82C41A6D6DF0997946B099D5D9AB5299A535B9B0657DCB4887A4B1D2934A67CA969E94EFECC6A4D90D0EC30C3B0CD78908C2B19CF687EC9A563B2A637036CF39FE94CC5B8E79CB4DF8400F94ACD93733A8EDA60540FA7E4070DD19DFE2A0C31601DAC64E4715E4D8D34A7672B3662B8E541CAECD185FB0CCC1EC7EB6DA667B317E70A6A5F2A90E6673715582631BA0033127A91F13605DC686BA55B3848A0C88E41E94F0D3BC9AF567224FCA25266427ECE4B6B1D3D399281AC20AE61838AC12CB4893BCB6F9CD7B5A1F98247AF1DDCC9B4AD834BF046CE8252B003C619EC5E49B769FEC24E2320D74F5752AF8CCEA832747AD2D756A7733A363DE56B7A5B151F3359FA2809E889F13749F1396A5EB28A30E7A75650C8E05FA75955CB0157461E72FC9A1851173E86984176C2A21D6FA2200F70A772E0DF8E49CCCB9B2E4C9D9253C880F15C25DF0A67259BE463E4950DBF2A3BA758647C4F8F67A031B663BF1860D358B2C408681DA701AEEE8624B836A8BEC967F14711D3B3106C8A11B1BC41FE9883E8B5C2D73B5CA59BEB7DEF0CE936C376AADED3374B7F766E2A2F7CE67EA2E4F1A87BBDAE0219F5DD5830495BED3F871C1ED1EB7307426B26D4C6D2B03BBF0EC6A3DDEB882951AFDAA6A489CCAB8EFBC2EC6E26C413F2FD936C3F4E1C9A5C070D40E22AE2E5806AD6B8F396827C7E8AA441A87F5422DB633E08457C3DADE877A8D169CC9192CA0895A3158E6F1A262709F0F0A87EB0B638805AF8B429BE867EC72C147A18F73B3C81EA952595C46161D71A55B5BA9EFCC5158C7055D718D28A1D17741DCE43691A1B73EDC9B23CB5C4536D00865107AF124849F49F8B2D3D3AA8A5F2743CA93B10417C65C62153E9F3DB21C395747A6328F069BFCF4F40E02DD756E9FB1260F012387BE6E30D01CCD59D0CDA351620A2DCC54F2B1A89A5928EEE8F08C5990689637966CDF2D9864C6D1B71DFD46F36F5365D6B38F18DAD299C2F35EB73699AD5462C62686A12127216F3A083E5CE64DD4860D62C9101628D6D69196B77502AB6D77EE72F4BDBA24F4E96FCC6F8ECCD4C8836B70757315B7ABFB4D5E6AE838BF7EE89E4FA25691CB2AD7FE2C16F8FBFC2869741F7961FC29707E3656540FB99DD4A8A492D2CA2373FDCDA0B6BF794FE9D2639C41C7E63937FBF0E8E464D1A8B5762CA2194DE82113BDD4EF5ADC56B8E28E84D59C0C0992CC633173BDFF510B1A96468F809056B25490250744C9236F4EAB40C3EF997E6BC940E3402BE7908E32C20CB4BFA122137627CA9A07248167E60EDE55DE9B15B4969C310FBFF96AB529B649EB10FAF5350A5B47954591751EE6CE0CF46F6C242796FA9144C86D4E36664FB7D46EBBC1B6C2D06D8E674C4F4A23BE5391ACD341F9E0A03D36CB62C68288F625B30B2C4E29089F2B4BEDE82631C350C602A3E96AE51F678D562CF069DFCEE6012236C1EE08B9009A8A8C00A106E322546830030E17FA220B63EFD346E8B67F41B045ACA126A2B69A5292D4714227ED4D6E93BD2CE95ED4894C3CED74F9748F027854A59780177F835E1263E377D34BDF55ABA9C8D60CEA65A15ABB0A004437B3F9E9488B2C8D398A7EAA49F00C1E8935CA4A570F97D7159C82116DF573BA52221A839BB015911D5463BC3583C7764A6C2294D84428B189A1C4C6094C5A2784C02B3416DB4065DEC881FD33F60AB336D7EC78E839C3948EDA297D6A47E4468EDA2908371344E771E968AED2D15C28EE682E292C8336877F9A89DBF0EFE38AA938BB9A069E81047BCC7DC9A98E2E2FA278ABCF2ECFA26CBFDF351F72BAD14D09CDF2D9E541BBFF55656C3683F050C46A2AD86EF296CDEDCFE23BF6DDA4BAA75F399F432B95E39DEC19C21B4EEEC8ECA41E976B27E494833356B8FB6A4E26FFAE5A5008E0AA2A472F10846A655A7CBB9C3F213C48FAF815EF398075399FEB2023FAEE3B6D644C9FAC1EE8D512CF57737D75BF2DBF4ED774C1D1433F16E779659CE73FD3A8B8CE791AD815115445B6C3B2339EC972998BD422B41F58D16640172BEE9660AE7BC244C3EBDDF5E67A793D1ED5058034824FB04D8F4901BD041BDC232D0CB969BADD412B6BCC213F7795BD239233604ACBFA4C37425F14A85D9D2C1A3162B29B48F479AC3A0E22CB27C078A43FBB9A9A1C1E3A71EB74448C16980717909F4D806DBD0398AB74BD07F0AB743185EF89C8872321FEC078CFE43581D1E098590FE7160E7F4CFEFAC30BD84E7413B9EB432BCDE2AC02E6B7B621C16D7E5F08C95503DDEBB042FFA9356287E5DAE101B7B2FF9D2BE7F5EFFFE8C53BB27672DBB682104AC1D4C5D464DF28BDA29CF144D614CEADFFDAB28A0EB4BEAC9ECF8A5E1A6361D1D006677E4475646913BB0FB791223F4E7CF59966ACAAA65CB617B95B5CAF976155485F5D5CB09859E4F137DAE0DAF5CF00AC5882E9FA59005301009DE118CEB9581D24F4DB4AF3C4A29595C1105752BAE16662161B2270C05F2BDA73C93A57EDAF0B2BC4C3097EF9C5BEFAE597A00EB9B5FBA47A4BC495B0C9AC83385EABF8BE734E093DA676117602404B19D09AF9238C21E5CCA58681AD9CEFF7405F9BC7EFDE1316E6592E696C7B2F34C4752EBDE331C8E6F79B933131645BF90B1365FCAEEE7727F3555A9C6CCA2D51122722A63DB95FF2C37C3ECB6F4F8A6C2E178B151D8905F1767275BF965F2CA95CC119405F51BD7C01A6453FA3F5A482F9345D4EA8213ECE4FB6F7D962B63BB92D9FB85EFA5DC3421217547DB9D9AC6833E1C07DDC1112BC0F3CF3C436E383AC6A7CE0689A3A057E21BB0DA8D02498C8F5E6DAE99CE059D448AF34C500DBA97EFED48D1842633768980221950568C263ECBCE98FA8CB844757F7CBC627B50FC663FB05A792909CF3B546EA46183C6C632A77BF3CF295FDE6B2E5181A78CD072F5E047AF2F080AA46EADF178188199888799B1B430DF50045E6E05C3DD26FA8A27D783DDC3FD3CF613F8AF60127D60EAEAF41EE8CF6D7D7435C9F67E3E56687DBFBE175919E8D3F3AFB7CF4FCEA10BD08AEB72FE2C11E19B5F7E39410089B6DEDCF06E1A073715D44D7451769B47BF4BB8F5077F9D9084E8A037EC0C41493E57F79FDED370E7444A897F6F014E4377EA59C0DADEE3D0BC167DA941B92A4AB34F482BCD35F952E65686977F3635E0D2CC01EE64E5AC03E6FB4BDD505BB4BA4ACF2035B44C449677CD6291563A56860CF82407F8CD0126C89C2DB280CBE5CBE2576A13841CFE313C8A42018E021100B5619BD1E0BCE7B24CF6DD80766661E30584E1093F63EFDF6EBEF50D76640FD8567A87DC071EA245EC866B578CD754156805D7DFEB8400E5E8C0ADF7C445D785BFEA8AD3283AF67848FB6ABF1AE0726F1DBAF2159E8A5DBA7659E04BCDC38B681AAE83544382EA54C6E4C787CB94B2DF635AD467EC474827BBBE189F31CD71A5349CDCA4CAA5CDC669F72F56BAE3E22D0FE43EFC57BE7EA6300F970703A8A7E49863F9F8E5E9CAB4F58B2D07B3188E2E1C9F56E84788D0CED2FA2EBCDE0BDF3C9427D6A840F19E1D17DBA5EE3DFD976B7DAA49372DFEB9E3142DAD262EDC774DEEE0965EE1F66050D258AA9D1CFF4E77FFEECCDFE8BCF3EFA14DEBA9FE3D9F5F9F5F9B9FA33BF1E5E3F5045A36E8C6D8117BCF3AECF077F18BDF89FB457E43AA65ED18B38A4FD12EDE97FE7EA8B1CBE8C5FF2DFBFD03ABC380F8C4B25F27D3334FC9A27F355CE66CBCCAAEA75F92BE1945F5BCC5E525AD75F732E09692015D17787A73CF9B3F61EA34715764A080E03B5275FE51E0FEB601968AC09BED6BC957BACC518A2B8A83652236F6B34761E19FAD3683182AED8BAD82893D80C850D2DC929D195781DA5EC9A06875463009F631FD4DEB19E37F71DA4BECE1D526721B784510111F365EEE66302BD2BDECF2CF641F02836EA649A20E5D852C38A94407F72934CB511B4215FEB3378B3DF8FF7FB7278331A8C079D7096DC18815F8CCC194443819CD9DAA1DD446A823F70DB89D4CCAAADFDC270CC42D0487646383D9D3038B9717F53770C83F2ED267D7C5DEE76D4B76D6F3C4F77DA4907D16D7D5F4467CD41134B8B1F96F44BB85412893C13FAC4AC679C48DC210CDF6108F4819F93FCDB76AF5F443412F9C09683B7D9C169CA98869448FCD968D693A9F13482624F4324F56CA1F3CEB1CDC7DFCBED9A06557E51A6059116814EA3738622085CC996271C3653F287D3FD94B305E3AF8D2EF83CB3AB3189FA19EDC0DB0395445FE8AB3C1A73B7C485D156968B7A6BA6F3CCD3D8880222FA663B9C70F022BC18B1479CAE1192A102DC127B761666A1C78370DC91819F9EBA8E205218B2701A61B19DDEEFEA40EE65B22270BFF5A756EF2EC9153DBC1CB9A9F03B1CDD0C2775794C7540844C925BB32826F769C484C046AFC0E7B3725E6C25BB673E6C794E40147176E4027403BAF8397B33B060D37F002AC90E21625F3DE535CF298D1956C658189BAD989E611AC53C652CC94B939BE18C17630CE730DA3D7CA93A1397CEF48661022251473E4F69AA44D1ED5531C57ADA5AF88E20670206E9628062E528C69F0E1EC0743B4119756B5714B5461E784DB8249A278E3A1D06BBE966F5B00D4651964CA016E181E1C8907B7D50CC0D267FDEEE409856CE63C53FF164308F836F5627B284380C4FC6445E00286928BB1566E1703854EBD9DEE739F11781C2D4C7999FAD3C65D223BE50C474EDBE5E15ACA08909D8CA5D0A0F41E5239BF8F97E338FE9A867A57040276DA066DBAFE8CC9BC79F6A19EE538EB950920E0BE126D79B151A87272E6E998EC185C6186FB82A5888CFE4E83C7F3C7B7878388361E31935C772C1B2E88385A2D9D825DFBFF9FCECDF0325496E11BBF24510FF85BA44238A85B8220A73B60C2409A23CC165A01E715F6969315727961E53375B0EE5EC15C0135DE2267D9BEA7C6507D3776A1D75E2EB73698E5B3A979AF8EB73C8C2FCED229F04E621D15281EEBB79042D8EE98C7906EA55DAD51B17E3E68E05B1909642589EF04831BD728B5AC0E05B725F3FC778634706D351EA8E115965B3428F08337AB070707F44FF930DE8A4E2C3AA7A3E41C2127F839022FE5398BC708DDF591739A264BEC061430FDF6CD2250D7BB3C3C32FF5C35AB34D27384136BEE30ECCB17560174FE2C8212A6EDD317ABFD6EEB248BBAC87BCDFDFAAA5BBA5AAE7565AB1DFCF7B3777F7E5E60971BBE6CC6A201BB25A25BEA7B25AD3ED27E97C8E989B70E85AE6E5C9A25CAC3688C27007A4479BF37EFB0955CB19253740F15BFCD9114D769F04794A9FC0A64EBD4D9E21DD7F7ACDDBF942354EC7A68C15C7C24BC85AE428BB899E71845849D5279ABC1C47744264CDE4984415BC1C1D32427D69ED8D39DBC4162713CBC3EC803E7D349F57BBD59686833B35186B05F31623A1C9DCEE1A03F155CB952E185A6507ABB90422A344D272A60A516D701689B412728BCDAC28BFD684459BDE67C7C68E86F44852F3AD5B9CF6B9658FFC9757BBC8061448A33B486286F8ABA04913AAE2E4ADF1614D876FF59A3B7A4B1A238E67D3AA40DAEFEF4D499C7E3D2E08FB4578AB9B711ED09F9575097F1B39E7C635448D8A9A950320792B7EB76F85A3A35B38D9E21CDBCC9310B26DBEDCEF7FCD11D4D2C9DE3E628B217BFB79AE18CD7783F37336E366154ED65B94BBE9AA00FD267A9E5BFB448A50494BBF1851817BC46C42749C13098291B600A38D490CF2F6D3D582103D7335865DE2FED7382655299EC0E215B9AF980EE06110934CD02E772F85C8E1404AC174B75BC72C8C4544A1E0DF2F823878F5EA03A23EE9194EBA5AB1A746396E1D033C3DBDED7927A113835BE6C294D3339230764ECD046192615F050081178CFA1AF852DD12B9F83652B2D335A4BCED4F6102C907B09A4A00582485C741DFED3281CF79DD8DC82F6044089F1CB796F2534D1600056CBAD56478D2F94C1FF85214CE1B3CF99552BCB9F4B0F4FB6E123E58EFC441704A533508A2AE1EA5D6E3CB1DAF1C316DE221CA330340FDD87DEEE4491F1384BE77F94B1274DF42D21C97DDD666025B82BD19C686E23945025F9F04628FCAB7BD3A7E0A832FC767A6CCD9EB1961E84035BE640934D14FEFAAE41BDA888857964F03579A7A153A7871F3883B8F5E027579896DE63D8BDA5BAA704DAA524BA4DA3EF888E9AAC0DFAACCBEDCF634C535ACBE190D8EBEE96AC2BDFA7810282252FF927783FEC95D72D1BBE0B8B951ECAA61B77CC7C8D244C86912B5F417EE31FA35F3B1E0867A92F2F43511B80C34EE56944173F556DD46894CA26C1DBB77348A8DFA7400F365603BF2ACB1687CA969F14B65FDEC2F0FD15B6A9F3831DD8959F2356817BD4109A1F7DC099E5C625B2E6B1BB044EAD621F56C04D0643219B3BE1317B0AB0BE658B6AD41CA4CAF035D388860A7AD6F22114EED10C28DE68F88FE8D7A342CC78390077C9245CCA59C3CF41FC3B34B85887C7C7EF11D580E4B96055E34D2C72AC77AA3366AABEED5837A4CB23ECC5F403CED929788275371699B80FBD3D63B638E8F43748E3F49E9D5C5E015113B377495BCBCA0F17F7071714567D40717AF209A67EBD0FBE45B44CF78AB605D779F7C879B7BBABD89D4CD20ACEDF0073AF05A040B5FD1E6B57B9A50E0431B32481EE845FBF7D8BBF633BD91A9386165E9280D0DF2481C10822B078F88C1A5776210EBF1C8D3DDC274240E1F937B26184AA20DEF053F6EE982818FA6A5B385E46C9B3C2A9CDC9D47280CA90ECD2ED2549DC29BFA026790213C68D6CC25DB8A4145F388A39E666B5589643257430213F57614C52B3F96C91C20FAA8B623572988A410A19BCC725680FB6620E0AD59D098EF3E933E02DAA9E54D8CEAD61C19CD6B849E2123756D9F7CA2B79CDD2B6767E670635175DBD1B662D7121B54988955D6071C51FD2C8C55142CA599858AF89BD7CCFFB53340E61B3D0799CB6E5D31D8811196424AB51633C4BA22AFE2625D13C1F2818AC017707D57B9657A84AD0999854B854FCF9441BF712912805C195456D45CC31D29A0DCDCA9DAC4FB4B58595CE53059D30CABAEA86C53CEE9CE98ECDA6DA55B062882083B4833F146D47069851184C7B424063C6D540BD3F1B049D7C884ED37FA9FB52FD175556D4B8C31092BBA2F46D6882E3C92BE3D42AAF88BC8E5C9EE9B62557B313FDFB7AD5C65EC48E89F1229E223E3BD6603532F25BC7154704F9CCF425A796E1892F46032F9C998AB962298802F97CBF237FC628E9A73D4E692AB6ACC665C1B5D664D3438E79516D2C04DDEE86F73B732516C92E685129C026F5A6D1C2B5DEC1F5FFFBCB9FE59D54B348AA5A9FB65B5B1EACCC8EA22E24BC375C81ABF737D3AE923927E4BB35E0E776D3B8215039CD0FAE80832C61E76BDD13167B626FE5ECB4A5512477C985C40BEEB2712A24774F4B860FD95249C61E4458A34D93B6C0A1897A7AA256DC5A1DE454EAB362F5BFAD8691D0CD694253F7FCB93F37F7B79713E517F870A7E783D7AEF5CBD66B7E2C1F5921EBFD17A4331CA3046D1B305948E7422963BD636B279F4F7EF34A7BE2D9F26E5323A9F39EAE81F7581BE51A6D960F91AF356A2044091BBDFFFDD18C546038250644E406DDD6018105D5D977E95830C4474371805AA141387C88ACFA932F34187B340D03768BB60D45C8B269345B69992AB43DE37A95173A4B5B808C6020021B06AAF6A9B278B065968DC7133581ED1D13434AEAAA3A46451EFF77FFF12470D81CD1283EF06C4B1B5BCC922967B582D121BD6D69463E0752BCA329F85566E1DE0E8966AA19E8E7DF51D64C8364C9259A6D4B77A954DC8EE18626BC54E0D76E2BDE08D34A3B9E2208D585C83418ADECD6AB60C8937759295BF11C1D10DEA2713A1F719DB3CB7600C2326E01ED882322EECA3EAA36328A7F5A8D00E82826A4A6D2EE0EC3A6049E89C6AB5951E61191DC9AAF5E461D8ABA0D0251BB6750C069B6DC32076DEC4A7A7DFEB6D20859D7978E78DDD1FD6504EFB83EE3B3F985711A7FBF4C6E689152B1EFBA64FC6579CC59A0E42F268208EF9BED98A55D7600C749A302488674B6A57F435AD280C1D980E8C5B8AE6ED45999CD4C8BA02C38FD34D6235BB69AF623B32682C6F8767462B694E4F097D51BD7BD09F7BB0CD7B203211BAECB5B334309D37E53B912DFC33474C99F7E8EF21FE67CE98F50718FAFDC816113FE575B534F59226B5D63DDA8F3011A3EE05626B17F8FBC9D812A6D8343FE6D18FF9301DE90DCEB93A581EB4DA6C934EE727245D7CA063EE934D49D87E4720BE8573C34F39FA72CB7DE162EAA7DC6001CBBF86FE1282FD4D7D0121849568C5087BF51A837376BBC757D1D222F06811FABCFB43CE7E9FBDD51A6790483D53968BA5C2D3E38EF62403001C04B6DB87D5A680372655222A22A7C1AC3C045BE93DA0DBBE539A9F9E8E7B757977DBB3D07D82362BE3CE87C18F675ABC521667A022024E34D6F63C097EFCFAAB2F76BBB57EA1232796A23F77BE2A2C031B370537744A21A128ECC4C62296482B022FD1134B40328EAFE5A65E678F634D0E661BA89F582170D1634F82C0EA642D5024589A10F6B5020782412EC8ECB51867B2A9DE6A4DB5BFEA542B42FF8D58880D05581B3FA532C2003783508C7BBE328FBA77D3039990549F8B606666EBC1332D97B925C04C82E0302564969AEDCBB6086EC106972F5F7E907090FC709ABCBC7815C5D3441A1ABCBCB8885F5DBC3ADC20FE9BA8BCC6BD56150D1F121A3607F5291C78F2A62C8A5BA78DA736C9E20C019F6A9A0C22018841F1F7309C6ABC5C36B976E732D8B77C2098AF0296EFCC653F7CAFF5C377D9D17DF1E6CD7741E45756D1005A75B2308F5A6FEC94BEEAA4A2173EF2BCCC17ADCF1FCFDC9B8AFA58B7063334D4B947B1481E9ED7D4BDACB7D555B431550B2DF2FF0CE71982731DDCE161D5ACA1658E2B8C8E21A25291B74370A425EF9DCB1A9AE077AC2310B63BD5CD2662E45447B5ADEDB1758957A7F50B499E58980B8626C0058771DAEF9FEA368CED4899C5252DA1B08C20865862B1A2E48CEDF2F413B12A00F1D8331606B5771C456B033524D078467B00475792B56D068FCE206E10947727F3F6D37E7F8E6F89463192631D58CA2FC4F923DFDD8C983E1F771BF3B37AC3C9413EA0DE9421229E598310ECFDBC2A3FA055F098FD635B5AF7AEB1B3B18EBFE4E005A8EBE761125D0FC24172BA7F2FDA5F0FAE07E7FDCAA683686D1D07B9D6928BD1C3DA28CDEBDC7D9AFC924B603916F47128F25537F845143A3E51092D30D6B87503A00DB68B58073ED35537BAA289E7421D1397B2302B4550100D02FACB9951AB883FD3CA9B4E5851CE88D390F5D6F94D6B1710BEAE41D68511BD835F477EC3274A8601EEA7AA6281A750AF3299354EACFA1231002A0F4208472A4FD47490C192127F2CC19A1650BAC1E23AAECD565653F59959337A385D5C983B6C3087EA867ABF8AED8A2731B4986EE26C92E123F2906E4F96ABDD09C08805F8139A8283AA4E4922725C8E875F423F5F566A9E3853FF832A5AA2CCCB07CC0CF3F0AA939BD726EB171DD119366E1389A962E71ED1F9C7E18465749364ECD2CB583CE5E725640B1D0ECFE7B3304A5B28A62D56EA69C54ABDD5054B9B0103B7B391CC93180343B700253AA7ED43D8E8A1CD64560C86590DAD22EF77348A392D41764FB8E2F34D3AE137B4FD98D195A8A9C2DD83F42F8DDF5D88912DCACDA4FC7F2ABB969EB861207CAFD41F41C421D17AB770ACB721125CAAF650DA22B50871D8C4C9129ADD4585964AC07FEF7C337EE5B1957A8175D67136F6D8F3F0F8FBD22BA0F445512A1BB529D12A79C0586496FED3541F4CA1F896C683469969F0D16594BF2A5C3548628D8ED385697692F3A14897AFB0B2899737CA0183331AA1BB7CA4501E863D6C87DB20BD2E2740BC85633639FFF4F50222EC8FEC38EFA517F16EA268B7E4B619C9ECCB068418A46CEB20DAD42C6AA7A620FDFACEB4BF4F121FC38D440D7E331FECC61941042C7D4209B8EEFBAEF45A022315F09CA3D45098B2C00000A986CDA81984E92C246A1FB9399832B4C400444D804FC3321D0293BCE8D54CF960FBCA667A01E8C2990B23BBC11B90C6F49ED7DE7FA3F7DD3D22DAB6D26FF318B3A708C0226DFD08235C34ADDCA10F8EC992949828434748F073B4B5D44B98F6396836F049FE3887A51264A1C147565B646B25D0F96DC53B876C7749E0D4D5CE939F75B782C98BC4D6BCB3BF2215546FDB346F7EA9365CE8EA06B6D06D4E7AA8BCDF75BF1E383EFB03D0A5ED1F5A4051600067070626F016EAAA51ED7576323FC6D6AAA1C7B9DFC1AE2F692B384F39C279CD43A6D3759F1C199C193DBEE41697465385A378A5E322A878365974BD05C32F633F707727A5F90DFECED6A10A9ECD75F0C196A916FE41CF243803B866944152795C708FDA66BAE32EDA0A7448147EDB0D47542CD83DE092C198E6D36253C49FBC1F26AD2EBCC4D8250A27DA6479629B247F0266E991C21BE8A39700706929DFFA3B461C7B08708CCD50FEE9BD609590C97DCF71E62275F1633887A72006A72E39EB5AAAFB85962752E71F79F1DBF33DB2ABAADC30230CFF50968219E3FBADEB4B79310620765482D91C961137402596007E35111B77E7F7E19D601B8C6E4511F7BE64DABC2827878383BCB6A3ACF1885938EC4CE3D142A5CBC20490D962E2995994825036D50B3AB5E14D19D473BB81A3CAF82A6BBD805E843194C59B9993F395AF86E35EE8463767B9A6B010539F090D31636557D26913F5D041A1A21D1C9933DCF6DCBFA010D05D609BF7C00D869D37D2FCB02A9A4EACC5AFE2F7FDAFD8F2A8B79E9F2BE3F62539061FE33C493771D29C5B1027D64EDEA88CDBF4916A34DEDBE97E0A6285347B2F7189F2922AD7AD0C8F689F2584FCE6D2F96FD97284031E8E9F8E99948D0B6235396BA2E570F1A88BA6E0B4D2A60050BC6EF6EA34F053E1E4145B8D2955F7932DAD48CF3759348548526B5515B58EAE5FC0A3CAB809D0343100FB706DE3F57508228FC4005626FFA6AE6732EF3B9A58DDB91DA9B87A0C274693E003931B67EABD25B246DC1D21E3A06AA8C919682B75005BCAA271956D49EDA09E144F026D11A0C6D0ED729327FB6630EC64B672111A0D82749DEC4847E272743FBB8B3CE4261EF230ACC32E84D51D9DF0F7E62A536E547C7E086746C845E7FF856386D47646078B74284DBDFDC5B145835DB7FDC293C8824A2F77CD664F19CC1E7622870AC4B365950B6C3EB3B3464284FB55DD2BB90A32215D857E293C3C73A399E3BCAF4C6EBCD81AF9F5C2D326B821E00129555318ED62B95E38DDC1759CE99F701B79C9B1A6A2545C6DCDD7BA6BC4D520193885EF96B83B836D4EE65FBB256D2BFF17AB8D719FD344760D4104A2C68FDC58555EC328BDFD8C9AAAC1E7C33050DBDDD96EDB90F31041A7C6E85E8758ECD8FA3BCC1B237C24B62DFF8D2DD6F4F5E645398F2217EDEDBF460B1BD4C896AF5FFD05504B01021400140000000800E1909553CCFE9D2D9882000031760100220000000000000001002000000000000000496D70726F76652057656273697465206F72204344204456442048544D4C2E746D70504B0506000000000100010050000000D88200000000"

Str_filter_js = "504B0304140000000800E29095533073CC455E0800008815000022000000496D70726F76652057656273697465206F72204344204456442048544D4C2E746D70BD58DD72DBC615BE7666F20E5BC4E3012710A538CD45A52A333409599850A44A52563D995C2C8185B016884581A57EEAE8C972D147EA2BF43BBB0B12A07EECF6A21ECF08D8DDF39D73BEF3B7E0BFFFF8D7ABFD7D3654E57D25AF32CDFCB8C7DE1EFC70C07E91B9E405FBC0F3EB4CA5DF7E43C732ADCBC3FDFD6BB3756377FAB15AED93C4FE277EC3EBB892A5DECFD4ED9E567BCBB5CC933DBE97F25AEFD57255E6622F97784E65AE45B5772B75B6F7E91F6B51DDEF7FFB8DD5712EAA95AC6BA90A266B96894A2CEFD955C50B2D9280A595104CA52CCE78752502A615E3C53D2B4555ABC202A8A5E6B290C515E32C865F745C67C0AA55AA6F79252091305ED72A961CA02C51F17A250ACDB56C30609FA899AF33C1BCB913F37A465D2278CE64C168AFD962E4885A6B2B5C895A573226B40027E37C9D9035EE0CCBE54A5A5D06C3D05E13F2BA16814520B303B652894CE9AF30AE96EB25B8CB029648C25FAE35166B5A8C450151726B5F55AC1679BE819170C3F8BF35D61C247D2531AD1D77C682DB4CADE8AC15DF7807EED2755540B9308289029746F727116B5A21FC54E5B9BA85A78DF22291E4657DD8847681537CA96E8471D0E65BA134ECB7265190CA6DF8DD569DF13C674B6794E513762004B4DEF8589139B5469A48C4A7549551BDEB7B7F63CA69C8E6D393C5E56016B268CECE67D30FD1281C316F30C7BB17B0CB68713ABD58309C980D268B8F6C7AC206938FEC97683272610AFF7E3E0BE773369DB1E8EC7C1C85A3804593E1F862144DDEB377109E4C176C1C9D450B202FA646ABC38BC2B90501EC59381B9E626DF02E1A478B8F013B891613023E01F2809D0F668B6878311ECCD8F9C5EC7C3A0F61C8C84A4FA69368723283BEF02C9C2CFAD08F35167EC00B9B9F0EC663A37470016766C6D2E1F4FCE32C7A7FBAB000A7D3F128C4CEBB10860EDE8D43AB148E0EC783E82C60A3C1D9E07D6844A7809A9963D64E8B70791A9A75681EE0FF70114D27E4D5703A59CCF01AC0F3D962237F19CDC3800D66D11C465B8493D9148A886C884D0D128427A185A24074E38523F47E31A747C7A23161140EC6409D13425BC286DD4FD785A94AE6BFEEB1CF66CD34BF4AA00FD81C367D09A95CAD906025AAB5CCD7288D5BC5506F9A32CA348FC4D4814C8EBD5AF02ACE3C2672413D04790A61C146D333F4019EDCA352188A8C97250E520F5285A848F10D777A8ED96BDFFB2B3DFEECF5FA5CEBCAFFECC5391A9477E8598368D30B3C6EACC7EA7778A9F57D2EF0BC422394C5E141FF27B1F21E7A470D769C43A10337AEB4D0F57D49A2D62560A195AF69616864E6D6A5AD8A5B99E8ECF02F5D7C4BCF8BF85ADC69C0747D3167095CFE93CEFCF9E0B12F3F9577472538462F397C8BE7A5AA1251D123F8CB65D23603255F7DC10C3406F4B9969B7323F3756EBA8C38B6FEF601E1F78E5EB97F94BB76DFA6812385FC26790A5B9F225F24BE0947AF7933E7366FC687E66DA17CF8F29DCBAB9EB5C420A53C11D8F5689A7AC141FF6DD710EC76F29712142D38A6DC9605E5CE8DB039FFE96F3471FBE2AEAC7E85DFBFF587AAA09959C3CDA6467C1EC86085323115B2AE3526435CD78C8484EDCFD0422396D7620FB29841925450E337607E8F74BDAA84C6EC603EEF132DA489CAE4F7DF19EFCB02B5B0C02ABD7A889B5617E0A01A02D2EF613B1177D3D45FFDFAE36FDDADDECFC707869707EBD0A6B0E9726123E2D32399BF2188166894D17D615D9894C218A1556327053B57EA7A5DDA6CEA6732C1CC3FDA020CF232E34B81A1C4C6F62028A6531BF99257BCDE04C54A6DD6014BCAFA29FCF2BD12D0644D8D9949B3ECBD5257B960C3AC522BDC27325140EA0A771DE444BD5120B558ED28D8AE771570F009BD201B094B5DA854B52ED17DE0BC96B9EB6774E948B6F0C4B873FF248BE86D4CACAD7347044D1CBEC2BC357B3B343253E81B305BCCA67270B68FE4F15D81E36A585A40E0513F95B800517261BD1133B56AB09EC8FD1FFA07EDC05C14E94BC9DF4EFD6DAA54EBC265CA364B086CB6B6F73257D116D488BE9229F35D288F8FE17C2240B54820FF6C841F8EB6A22E48BBA25F8C5D83F1642BDAC2DBED9633B63DD1B8C23DA91D36AB51675C836D0D27B7A3CFC2B9E10433491B9D6E0C3B6C5A85EFB1EF1BC6BF675EAF6DB103B182B8C5F906AA672AAAE99E74F5C0AB516DEDC141A79352A2C627446BD36C385CF3DCA7035B5D86FF8E82968E1A0D08EE9B20E14BA2CCEC1447F2AE3858172EEFB7D9D738F064E2061E5A2F86C446B7ED1ACF29271F1E750E2BF9805B03B47FEEF0E5FC6AC1B811B3CC79714D856CA87932A61D321E03CD49F01932E8A3852E2EFF1D15F67997896734BFC484FD13E7AA16975CEA96B42D4A679D6B5A3920726BB74BC1A5BAB3106EDCA41CCC5AB31E762BBFA5A5E1DE4C675351DD3BD03659E742E32343C25B9E77CC30D3DE9812AB5CAD5D0599916E013BB78D862AAB90F8C45D0F72155DC7721E5F23BD5294D8DEADA0CF23ACDA2C6DAE240DF2FF2269DBC6B39DF4C946FAD5A42E05A87996D4733C22D369DF6BE92352BB2145DFEE1CA6D158B909D526B50BF83CA7907DC4CB52E5C9CB7C7E59AACB250D7173230B3653A5196F8FAE65A6D83063D2F6C5F1AB69363E5253DF995A03BB4D57B26E063B7EDB561B02BD5685D1A76C4574B63E813605D5192DAECE5BC1EEA05CF2CADC282AF3630297FA256F1FBEDA6913A22F38DDA9B28ED3E62BC10EF3E746A7DB7EF3A639F8A763D61EA72655CD8629767187516DDB4F22D354D0D863292E6ECDD7DF4E3BC4278BB828B75C111CAD31BA423EDF14FF4F34BBB2C9657CED6FD2AB6DEB4E429993F45B1C4691306963B5063065C7AEA0335A28FD037B537CE3AEDAC6005781C6804DA83B067483DB36C070EBC09E34C03634A3B921E9D1CDCE31F1BAF5034193EBAD0F0AFA2AA357FA26DBDA362DB6DFFAF46B9FA4DF9FA4AB25E3AB8B89FD783723DA769107DF7E87994FBCFF00504B01021400140000000800E29095533073CC455E08000088150000220000000000000001002000000000000000496D70726F76652057656273697465206F72204344204456442048544D4C2E746D70504B05060000000001000100500000009E0800000000"

Str_fhpopup_custom = "504B0304140000000800E290955323705620F2060000A826000022000000496D70726F76652057656273697465206F72204344204456442048544D4C2E746D70D55ADB6EDB46107D4E81FEC384402CC9B644394EDA5AA21438B603A748DB207191B6411050E252DA64C925C89525C7F197F5A19FD45FE85E488AD4C51E2A76823E58DACBCC99EBCE8E48FFFBF73FF7ECEDEFBFBB07DBF0CC0D28BB80539A081E5337849FDD73F7F530A69100F88BF300B6404E396300CF037744E0258F26113C9B844341796850FC71A456EBD46B80703F920424921B0EC73C96F311504FCE3C18C6C41572538C099C9EFDF202122348708849E8911868A837351A4C69E8F16926212609FD44EA9FA44E0D70BD0F93441824B50CDCD763AA55BC06C5CC52148F08120734240520A5673276A31C72154A12B88C91B8DED0E4FE784047233D4DC6310D3F82349B84CC8DA52EB95619EF905112CA553A1A8B1CC02C4EA927C6722D2662121B1B8C5C30E49A5813812F45043C113088F9342171A2E16DF9E9A7912906452E5F2A827337069F3212BA01811E787C3809A4DCD688881346D4F0E9C5734F71A8A54321623A980852B7A4F77DABD1CD30866EA445548110543052C0484DEA2DB924A73096F616DDA3F7A90FF514C1811FDAEDC61C4FCE72120391526478864091F08884C6C33DF3D5522BF55A6DB7A67D27BF8763370C090BB8477A21DFF5278CC9AC25245433C1391BB8B11A323E74954FD4D8A33119AAF34412354D842B267A24DD3349E9137DA8E424E95D90645767B73B6044CD6AC6C6B976ADDCCDD3980AC2A48ACEFDE3DF8ECEFE7C790263113078F9FBD317CF8FC06ADAF69BFD23DB3E3E3B863FF419DB6BB5E12C76C3842AF55C66DB27BF5A608D85883AB63D9D4E5BD3FD168F47F6D92B7BA6B0F614733A6C8A0267CB139ED54729A7759A052C4C7A2B24ED1D1C1C1801383870C6C4F570A4E0E844EBEBF839B69968CECBD393C3E32B0C4256962E22D2B3049909FB83AC8A6615A7B16D3BF7DF1E1D1F9E1DBED5E43732A87C970933A2D2CFEFF354AEED98E14EAD8B915A02C9B2BDB6A3471520027746834930576341B1CA40992A65DDD030BA7CCEB5695764CCA4E3F9F4459033DCC852A8B8C54B0A23ED5213D9F64D3969CAA1DA9DFB61E92AD9811F1F77AB03AE29B312EE211ACED4DAA27EFDC5AC692CE7558963035146F3FE425E3596F2AE488E4A022D4405111C9906A848C2258AAA808C05C6222F9E939C46AF276FDBEF5A15CE6F8E973971055C0587C2158E4CBBA65736C55EC81CA4C4DCD37DD86B64C07B48E694BCDC30E2787196129610142132FA69CD527AE2D4BC7B1357644C222E18696529A535D8868303596BAC07164EF65AD43CF12D7722380EEDAA72852F3A0B230117BE4255A89CAB95235FA8FD82474AD063DCDD58E44CA847F03AAEBABF4A677CDB18BD5350AC32729656C5BAB588ABD4C601AFBAD2CA7508157FECF95DF4CE46256FC1110BFA370BCE6D48CF14FD6497C3B181BF70354195BD555778E9CABE0BC7663E2909C259B6149BB2F2CDA2AFE67ECD2FAFA29BABE737CEAD855310D0501928D5DC7F58FD58076E3CA2EA873DB6242C1F13674193BB88E6620B998AC2A9FC4D8F4956AED7E490F17FA39C3648E46AD7062EB1968EEAD788EE42DFBE5170BFC961FD9F0537DD313F5ACF7849EBDD921F917D61FAE012DD8A546FBFF227AF18785CD6A531D35FDBB02FA3F308A5BC3E1B9A4B376D290C3240F9A302F581F36E7567658FA531E89BF8EA91F4D53E4AF7AF636FF979084606CEEA34ADFDB14F9920B1B464C2445247F166878C8621894F4D9979B26AB103ED5D1C62BE960DD207EF1277DD56CBB866735103EE5D14F1D57C09148579B7C14F1F5E61447CE5D8BFD177C193156B1B84A372E43796744DE0734C14E45DC5BD1C9750DE5EE12E84EF250F616AA014BEC57C50BD72F8DE88939550CB93FE31DF1DE443667D75A43AC2D616D4EFE7909F3FAB9D74D2CF0C69345026405935CD8A53284D73E3AE9B54D22E6D68AB357927178B12868CB16DBF7B877AD902E0D8E6E50C8EDCB1F1AF931C6D200F1977BD9E95DF62CD8306EE4510383E8F03D04FA87A56C4CDBBB48E4F67C4EB826C2C3B0FA3591718F185197D6A4A2832EBEC752D70758EF7ACF9DBA7CE39A75EBD8D150E0E0DA349F6266B30118287964C613691D3572421C292B6C9D33CFC58304EC2837D0B025E9B5EAD2422EFDF6E47C453DDE19424644DCFED0838623C2105FC422812C27C5909E57E05618EADF20149EBD1F3A5CC710709671341BA607E4DC89213CDA0943A6D995864269A2EA3A3B03394A024EEA23326CA44FA3C144D95109D9FDA0F24FF563848A2AE634768A4BE43831124F1B067D576B2FF3BD8A959A0DFCAAAC5F41F09D49ACBC4C28ADDAF266CD02FB03BF600CFEED8D2D55852551150B4B2CE88805D479A66CFE2BE2FF7937A5624D736B86AF3527DAC6B52F45EA506D470E4FA6503749BB11E0AD5406A1EE38EAB35C6A70DDE06B65FDF807DA9E56B91300DD4B576A31A9CB93F6E6C5034D5060D88B16B4583510CC3173710A90FEEC9BFFF00504B01021400140000000800E290955323705620F2060000A8260000220000000000000001002000000000000000496D70726F76652057656273697465206F72204344204456442048544D4C2E746D70504B0506000000000100010050000000320700000000"

Str_fhpopup_screen = "504B0304140000000800E39095533E81CFF27D030000EF0B000022000000496D70726F76652057656273697465206F72204344204456442048544D4C2E746D70AD56516FDB36107EEE80FD872B81C1769B8A098A3DB8950CA4768AA4C8B660F3900D4150D01265B1A54881A4A278417ED91EF693F61776A4ECC6CEB28D06F662F38E77DF7D77E49DF8E7EF7F3CA32FBEFEEA19BC80F7AC167205A7C23A6D0453F081DDB09F72231A07E7CC2C39A0C0B982B39AA170A19BB681F7ADCA9DD0AA8728ABC66B87A21881639FB90584612AAFB4417909A240A90084610E375DC5E174FEDD39D83E8AD360B82AB801A1C26640834EA842779B08865BF11B1F8E80159F5AEB7A944E14AE0AD81517CBCA812E835E04AA88AB3833985C29A45C3B784C28788301855A820E118501661B9E3B300CD3B22128C5DF729DE7768AA8BEF30637CC7860AE58CD218342E76DCD954B96DC9D48EE97EF566785F7F0AA63E78C58B48E0F09E65292D1DB0D46CE9A10621F08279CE46B0C8DB9F47965FD5FE235C3C1E0601038E37F5E31A5B8AC75C133A50FCA564A1B0ED54B4E6BB960C62FA5CE7DFE415D088305C12BC1AD17AD63AE0D2BA4D5AEED11444BEF6CB315B707E18CD842722F0D1EB34BBEA4D719E1B8448AE9F3D90FD3F9AF172750B95AC2C5CFEFCECFA6405E517AF97A4AE96C3E835FC24D394A0E616E98B2C2D36392D293EF0990CAB9E60DA55DD725DDEB449B259DFF486F3DD691775E2F5FB92DCFA470059944910B9C6E6BA96CF644A4A3F178DC07888383B4E2AC883385341CF0249C5F4A7B2178DE9D9E1CCFEE631036CDB56A78461CBF75F4133676AF8D634C69FAFC6A3A3B9E1F5F05F3FF74D8EA964DBBC6C4B98B310AADD2EF7E5C37FB56C32C74B14A7229707D1A36DFEE8BD98F92A7212FFD5E3C62983E4F900C7A7B75789D547B72EC11FF46F101B0DB8F611FFF63187608B84398EE56391E34707884D953A63B458E4314250C77684EB60344DD2B88BB584FD5D3BA95E4C9972324E3C36F481CEF7F46DB1C1F61ADD39168F751565C5A1E65F8FF15648F1C222A32FE36B6BC5105B98F1B57945E5F470D429CA6B41F9C71E6298D1FF5A99F339334472D37912EA53635B0306A33F230D5DFDC68510C0F4771D31D9312AA69375F087C5738AD0876B26C519C4A6D378FBDCB0041F0AD84E330FFBC13D27259E29444E3E188008D8B9C529F41A46D334945BD046BF28C0C5E6E1E5C2F0704C267D12BD72F28AF63D23DD26825352B32F2F04D22B0D0069F9B1939F29453DAC453594CB6C053BAD8C39BAECF18BDFC91C738E145C2F7C5BF99AE4BFF78BFC47DDBABF1B1F017504B01021400140000000800E39095533E81CFF27D030000EF0B0000220000000000000001002000000000000000496D70726F76652057656273697465206F72204344204456442048544D4C2E746D70504B0506000000000100010050000000BD0300000000"

Str_fhpopup_zoomer = "504B0304140000000800E3909553C9A9F23DC2040000770E000022000000496D70726F76652057656273697465206F72204344204456442048544D4C2E746D70B557DD6EDB3614BECE80BDC3096F6C378E68AF18B0D85286D44E916C5D1B6C1EBAAD28025AA22D26142990546CA7E893ED628FB457D82125275E96750AB6DD182475F87DE78FE71CFFFEEB6F7BF4D9E79FEDC13378C90A21377026ACD3463005DFB01BF6436A44E960AAAF34FCA275C10D9C176CC9E1429755092F2B953AA1558DB0C84B7FDA15590F1CBBE6161085A934D706F74B1019EE32480D670E3FBA9CC3D9ECBB57606B12A7C17095218550E16340839550995E6D190CB7E296777BC0B2ABCABA1A6525329707EC9C8B65EE402F9A737F15169E1FB72268EEEFD768F5E748975C753B9D7E57F1154C51B56EAF172DB99B890297FD4E14459DDE1896E20695E62CCD1BC518F80B8A15BC0F1AF1CD4A581E886E6B4F9522BDF6D65850DA35B6F1ACE63E431FDF6AE598F4E66B29E7CCD046DFDA1CEB8494E166AA8DE1A9837DF8BABEFC569B6B0B6FBE0D96BD14862FF4BA0F93DC202D740B6D9DDCF4FA30AF1CBC7E3383F353180EA15B29C9AD8573E5B851DCC19C595E4704FD3DD145C99C980B29DC060A9DF15EE0A2F8BB68A2BC1B603CFEE0056E98818590DCBB0112C8745A155C39EFBF53C9FDF2C5E63CF337FCD1897346A05ABC4B30920BD21B6F315256068AA74038E1240F1894D6283E948D139387E1ED04DD31927B94EE3A0E98947A65C17A0BEAC86226CE3906ECB0B23E5E1EFD1E394AA5B6981841F54F11FE5D3EA539538A4BEFE344E9FEA29212538073E5774E6B9F0A7E2975CABC4FFC3A133E033067B8F55BEB98ABC20ADD5335F2777964930DB7FDF052D85C72BFEB3C5437BA73F3CA08C7256A1CEF4FDF4C663F5F9C42EE0A09173FBE78753E017248E9DBE7134AA7B329FC14DEEB301AC0CC306585578F494A4F5F1320B973E588D2D56A15AD9E47DA2CE9EC7BBAF658437FB9591EBA9D9B51E63272DC4AB9A0D3BA90CA268F300D8F8E8E6A82767010E79C65ED44210E89761C7223A6F526DCFC70767A32FDD806410A750D6E53F28438BE7634B5966082C98458B7C1679973EE08F83791900C8B2D72455EA6AD86DB127ACF7085D5BB3E25604D7A0F7B85CC9882C6729790CA2D0EBF22C731AD45FF633A5CFCFF74AD40288DF7DF4DA627B3937741FC1F2FECD4BCA6E578DE5E1BAE0F6D8442B90A0DE9B2E9593B952F9CDB7783F751FD6DFC44C4BA813C0A183EB5C37BE47648D6E84E61C22AA7C9BF44DB2AFB14B0E64B1D9999EEEE987DF0FCCB417FD7B10747835E3BD4A60F5D72EC3A9F68440465C81321B746EE2A4ACA754B73B74A3DF0D81D703B94D0AAB5292E255FB807BA1C0D9EA0CEDD9147DB8964837BC7D10AED63BBF748E9FBF7AD5E3A968B27559798B6EF04F15C671BD04A6A9625E47E186D578320CEC40D045725A4D4750F1CB1B9D512C7993114CC2C851AC1A05CC3107FC6707B88587C3D1A8C5B32405C1EC7A2F0A376420ADE94E2CEC176423BE81008FDCB1F3623973F63D23D38996B83D36A42860428D6EBB2357FA0F62F646B6948B0D170C00B6FE2FAB07E95A32F708F9D607EBC431BD3797BAE98A23B5B8AFA94FC8BE7B1FDE27C75839E77BA1C61D9D875F9708C5E091D2021F7CD6674A345D61DB40D38C44295D5B671E1D0EAB422F80E6585DB891F239BFF516F0304C1D44A25FE69F813A5E572B19D397D305A31C7D49BDC56D6A7752B597C2C38627D4AF4F1E1182B455AD9FA18E7A53F00504B01021400140000000800E3909553C9A9F23DC2040000770E0000220000000000000001002000000000000000496D70726F76652057656273697465206F72204344204456442048544D4C2E746D70504B0506000000000100010050000000020500000000"

Str_dojopop_css = "504B0304140000000800E4909553892BC372220100007E02000022000000496D70726F76652057656273697465206F72204344204456442048544D4C2E746D707551414EC330103C53A97F5835428243AA14A448718E80C4A9072E9CDD7A9B181C6FE438A46AC5CB38F024BE406337695AC8C99ADDF1ECECCECFD7F75CD01B6D5FB0923B7CE65A2884FD7472B551C42D0323B3DCA6075C5225AD24CD80AF2A52B5C5B6EADA0CA272DBA215594B450F1B296CCEE0FE0873F4E40EEF42A9056E19DC45EE335FBF67866A2D4259F00C19D446DDCC5A772595F35267B3DB0B5E6BD9EBF5A24A6A0CBB49BEF6399D0C775CBEBAFDD6B5A9C830D04D685CFD1FE6D339133B26FCA19E6B36E3C425EC61A839CEF4593C28D23E903E80FEFE60A964510A0A37B67D5D0246A0618BC34504AF721410C471EC5ADDB99324394E0B0AAFEC735A44D1F520A6236C4DB9381E0DCF323423564E2B15F481E9C5B8B3D458C039F7CABF504B01021400140000000800E4909553892BC372220100007E020000220000000000000001002000000000000000496D70726F76652057656273697465206F72204344204456442048544D4C2E746D70504B0506000000000100010050000000620100000000"

Str_dojopop_png = "504B03041400000008006C9C73533C8FC243330100003F01000013000000696D70726F76655F646F6A6F706F702E706E67EB0CF073E7E592E2626060E0F5F4700902D20220CCC10624E53FFF4F04529C051E91C50C0CDCC220CCC8306B8E04509025DDD1D7918161635FCDEFC0C940BE42B247902F0343952A0343433303C3CFFF40FA250343A90103C3AB040606AB190C0CE2F993E28FBA01D56EF574710CA9B895F4E7FF7F7B665506858619121A2C0C8C2E5B18D3CFCF2B657A34D9614E830E9F80C3921D0BF83ACE36ECE08E145068F0304C9014F8DF7AA98041C0A1670A9B9203C3C6079F8D2764B13F7A79ECD831EEB4B3B3589F2F5FBA54B761253387829AD09F1E531E06A68E4E16FB645EE606864516201E67B8CDF2E5CBAD193F7A2AB07D9694949CDBF0434560F112A07C92D2C1F31187414EF1F8607CCD808143A10BC4D338E70374D7464606463686C6E94EBF7BA60797013DC0E0E9EAE7B2CE29A10900504B010214001400000008006C9C73533C8FC243330100003F010000130000000000000000002000000000000000696D70726F76655F646F6A6F706F702E706E67504B0506000000000100010041000000640100000000"

-- Dojo resize png icon above for corner of image dragger --

-- Main code starts here --

	local intPause = collectgarbage("setpause",50)									-- Default = 200  Aggressive = 50	-- Sets pause of collector and returns prev value of pause	-- V4.5

	local intStep = collectgarbage("setstepmul",300)								-- Default = 200  Aggressive = 300	-- Sets step mult of collector & returns prev value of step	-- V4.5

	fhInitialise(5,0,9,"save_recommended")

	PresetGlobalData()																	-- Preset global data variables

	ResetDefaultSettings()																-- Preset default sticky settings

	LoadSettings()																		-- Load sticky data settings

	GUI_MainDialogue()

	SaveSettings()																		-- Save sticky data settings

--[[
TBD:				Add large trees to ToC;
@V3.3:				Update library to v4.1; Prompt to run GEDmill; Hex encoded image & JS & CSS zip files to reduce size; Count changed media popup files; Fix text with tabs into table columns with better cell wrap and cell borders; Centre windows on FH window; Check for Updates button;
@V3.2:				Aggressive memory management; Check version monthly; Fix some Media bugs; Only count changed pages; Cater for foreign languages; Add GEDmill minitrees; Add UID & FSID;
@V3.1:				Updated library to Functions Prototypes v3.0; FH V7 Lua 3.5 IUP 3.28; Support relative URL to items within same folder;
@V3.0:				Updated library modules; cater for Home image _h1_ prefix; 'Close Window' button; fast non-image icon setup & icon files from embedded code; more generic toc[0-9].html Locations database;
@V3.0:				Allow alternative to index.html; Custom myimage.jpg & mystyle.css; Set length of Surname in Index of Names; iup_gui.Balloon = "NO" for Crossover/PlayOnLinux/Mac;
@V2.9:				Updated library modules, corrected Help page button Media Popups, removed trailing space from filename, "Turn non-image Media into icons" button always active.
@V2.8:				Add magic code {{MEDIA:file|text}} and support icon hyperlinks for non-image Media files.
@V2.7:				Str_filter_js has start button with "type":"submit" so that Enter/Return key triggers Start Search.
@V2.6:				Revised general & encoder library modules.
@V2.5:				Both ANSI FH V5 & UTF-8 FH V6 IUP 3.11.2, new iup_gui module, Index of Names search filter optional, revised for large lists, tooltip advice & hides Alphabet Lookup,
@V2.5:				Hyperlink/Text Tab separator = None reverts to original, os.setlocale() replaced by encoder.StrUTF8_ASCII() for Unicode, XP setToolTip(iupItem) function.
@V2.4:				New library modules, iup_gui.Balloon = "YES", auto Plugin Title & Version, GUI attributes mixed case style, Index of Names search filter, new Popups = Dojo Zoomer & Popups = None, ignore URL in javascript.
@V2.4:				Change GenDex help page from creategendex to savegendex, update to use new TblCP1252 and StrCP1252_XML(), adjust text with tabs into table columns, add Version History help.
@V2.3:				Add 'Table of Pictures/Reports/Downloads' pages, remove Folder selection from tab, plus minor improvements.
@V2.2:				Replace integer with string parameters, add Custom Large Screen Popups, convert CP1252 to UTF-8, add Create GenDex tab, minor string library updates,
					and swap first DOCTYPE line XHTML Strict with Transitional depending if target="_blank" is enabled (alternative is onclick="window.open(this.href,'_blank');return false;").
@V2.1:				Improve analysis of anchor tag attributes without quotes, and fix indefinite strHyper loop bug.
@V2.0:				Change GUI to tabbed interface.
@V1.9:				Support more URL syntax options, replace {{DATE:QUAL}} with today's date & {{FILE:QUAL}} with file name/path, and other minor updates.
@V1.8:				Ensure HTML symbols in Identities are escaped, and gsub pattern symbols in abbreviated URL are escaped.
@V1.7:				Prototype ProgressBar, allow Identities per Name, abbreviate long URL, convert URL & popups on all HTML pages, process my locations database, plus bug fixes.
@V1.6:				Improve fhpopup.js XHTML compatibility, exclude URL in image popup title, minor GUI changes, and update to FlgFolderExists().
@V1.5:				Popups allow multi-line titles & single quotes (') in titles, retain original page position, and reduce initial zoom of small images.
@V1.4:				Check HTML folder contains V5 XHTL, and fix minor bugs.
@V1.3:				Provide alternative image popups feature.
@V1.2:				Index of Names tooltip title="Married/Alternate Name", choice of Style for added names, Check Version in Store bug fix due to "-" in name!
@V1.1:				Better name sorting using setlocale() with non-alphabetic surnames first.
					Use XHTML anchor tag id="letter" format instead of deprecated name="letter" in _nameindex.html.
					Convert user URL into hyperlinks optionally opening in a new tab/window.
					Allow user HTML anchor tag format to specify Hyperlinks.
					Made all window positions and settings sticky.
@V1.0:				Initial version.
]]

Source: Improve-Website-or-CD-DVD-HTML-1.fh_lua