--[[----------------------------------------------------------------------------

KSBlondeTest.lua

--------------------------------------------------------------------------------

ADOBE CONFIDENTIAL
------------------
Copyright 2010 Adobe Systems Incorporated
All Rights Reserved.

NOTICE: All information contained herein is, and remain the property of
Adobe Systems Incorporated and its suppliers, if any. The intellectual and
technical concepts contained herein are proprietary to Adobe Systems
Incorporated and its suppliers and may be covered by U.S. and Foreign
Patents, patents in process, and are protected by trade secret or copyright
law.  Dissemination of this information or reproduction of this material is
strictly forbidden unless prior written permission is obtained from
Adobe Systems Incorporated.

------------------------------------------------------------------------------]]

local KSBlondeTest = {}

local blonde = require 'blonde'
local WFTableArchiving = require 'WFTableArchiving'
local WFPlatformInfo = require 'WFPlatformInfo'

local debug_timeNow = assert( debug.timeNow )
local DEBUG = _G.DEBUG

--------------------------------------------------------------------------------

local function expectError( func, message )

	local success = pcall( func )
	
	if success then
		error( message )
	end

end

--------------------------------------------------------------------------------

local function expectFasterThan( maxSeconds, func )

	if WFPlatformInfo.isWindows or WFPlatformInfo.isAndroid then
		-- SPAM [arahn 2012-05-08]: Our unit test runner is slow on Windows and Android
		maxSeconds = maxSeconds * 2
		if DEBUG then
			maxSeconds = maxSeconds * 3
		end
	end

	local startTime = debug_timeNow()

	func()
	
	local elapsedTime = debug_timeNow() - startTime
	
	if elapsedTime > maxSeconds then
		error( string.format( "Test consumed %.3f seconds, should have completed within %.3f seconds",
			elapsedTime, maxSeconds ) )
	end

end

--------------------------------------------------------------------------------
-- Decompose a single line of BLONDE text (8 bytes) so that it's useful for
-- debug log output. Like a typical line of hex dump output, except that we
-- use decimal numbers so we can recompose the string more easily later using
-- Lua's \nnn notation.

local function decDumpLine( str, index )

	local decDumpBytes = {}
	local asciiDumpBytes = {}

	local bytes = { str:byte( 1, #str ) }

	for i = 1, #bytes do
		
		local byteAtI = bytes[ i ]
		
		if byteAtI < 10 then
			decDumpBytes[ i ] = "\\00" .. byteAtI
		elseif byteAtI < 100 then
			decDumpBytes[ i ] = "\\0" .. byteAtI
		else
			decDumpBytes[ i ] = "\\" .. byteAtI
		end
		
		if byteAtI >= 32 and byteAtI <= 126 then
			asciiDumpBytes[ i ] = string.char( byteAtI )
		else
			asciiDumpBytes[ i ] = '.'
		end
	
	end
	
	local nBytes = #bytes
	
	if nBytes < 8 then
		for i = nBytes + 1, 8 do
			decDumpBytes[ i ] = "   "
		end
	end
	
	local decDumpByteStr = table.concat( decDumpBytes, '' ) .. string.rep( ' ', 32 )
	decDumpByteStr = decDumpByteStr:sub( 1, 32 )
	
	-- GRUNGE [scouten 2010-11-05]: Yes, this could be more efficient, but it's only
	-- supposed to fire if the unit test fails.
	
	return string.format( "%10d: %s   %s",
							index, decDumpByteStr,
							table.concat( asciiDumpBytes, '' ) )

end

--------------------------------------------------------------------------------
-- Decompose a BLONDE string so that it's useful for debug log output.
-- Like a typical hex dump output, except that we use decimal numbers so
-- we can recompose the string more easily later using Lua's \nnn notation.

local function decDumpString( str )

	local strIndex = 1
	local decDumpLines = {}
	while strIndex <= #str do
		decDumpLines[ #decDumpLines + 1 ] = decDumpLine( str:sub( strIndex, strIndex + 7 ), strIndex )
		strIndex = strIndex + 8
	end
	
	return table.concat( decDumpLines, "\n" )

end

--------------------------------------------------------------------------------

local function convertTableToStringForDebugIfNeeded( value )

	if type( value ) == 'table' then
		return WFTableArchiving.tableToString( value )
	else
		return value
	end

end

--------------------------------------------------------------------------------

local compareValues, deepCompareTables

--------------------------------------------------------------------------------

-- Performs a deep comparison of two tables, nested up to 20 levels deep. Returns
-- true if every key-value pair in t1 also appears in t2 and the number of
-- key-value pairs in t1 and t2 are equal. Returns false otherwise.

function deepCompareTables( t1, t2, depth )

    if depth == 0 then
        error( "Tables are too deeply nested to be compared" )
    end
    
    local t1count = 0
    local t2count = 0
    
    for k, v in pairs( t1 ) do
        t1count = t1count + 1
        local equal = compareValues( v, t2[ k ], depth )
        if not equal then return false end
    end
    
    for k, v in pairs( t2 ) do
        t2count = t2count + 1
    end
    
    return t1count == t2count

end

--------------------------------------------------------------------------------

function compareValues( v1, v2, level )

    if type( v2 ) == "table" and type( v1 ) == "table" then
        if not level then level = 20 end
        return deepCompareTables( v1, v2, level - 1 )
    else
        return ( v2 == v1 )
    end
        
end

--------------------------------------------------------------------------------

-- Specify decoded value and expected encoded value and make sure that each
-- translates properly to the other. For convenience, we allow the encoded version
-- to be specified as a bunch of strings (see usage pattern below with comments).
-- This function will concat the strings and use that as the encoded value.

local function testEncodeAndDecodePair( dec, ... )

	local encArray = { ... }
	local enc = table.concat( encArray )
	
	local encResult = blonde.encode( dec )
	if enc ~= encResult then
		local message = string.format(
					"blonde.encode: result was incorrect\n\nexpected:\n%s\n\nactual:\n%s\n",
					decDumpString( enc ),
					decDumpString( encResult ) )
		print( message )
		error( message )
	end
	
	local decResult = blonde.decode( enc )

	-- GRUNGE [scouten 2010-11-05]: If (as anticipated), we add ability to describe
	-- userdata values for intra-process transit, this testing approach will break.
	
	if not compareValues( dec, decResult ) then
		local message = string.format(
					"blonde.decode: result was incorrect\n\nexpected:\n%s\n\nactual:\n%s\n",
					tostring( dec ),
					tostring( decResult ) )
		print( message )
		error( message )
	end
	
end

--------------------------------------------------------------------------------

-- Same as above, but expects tables to decode in the same sort order that they
-- were encoded in.

local function testEncodeAndDecodePairExpectSort( dec, ... )

	local encArray = { ... }
	local enc = table.concat( encArray )
	
	local encResult = blonde.encode_stable_output( dec )
	if enc ~= encResult then
		local message = string.format(
					"blonde.encode_stable_output: result was incorrect\n\nexpected:\n%s\n\nactual:\n%s\n",
					decDumpString( enc ),
					decDumpString( encResult ) )
		print( message )
		error( message )
	end
	
	local decResult = blonde.decode( enc )

	-- GRUNGE [scouten 2010-11-05]: If (as anticipated), we add ability to describe
	-- userdata values for intra-process transit, this testing approach will break.
	
	local decS = convertTableToStringForDebugIfNeeded( dec )
	local decResultS = convertTableToStringForDebugIfNeeded( decResult )
	
	if decS ~= decResultS then
		local message = string.format(
					"blonde.decode: result was incorrect\n\nexpected:\n%s\n\nactual:\n%s\n",
					tostring( dec ),
					tostring( decResult ) )
		print( message )
		error( message )
	end
	
end

--------------------------------------------------------------------------------

-- Same as above, but the first argument is an array containing arguments to be
-- treated as a tuple. Note that this implies we can't test tuples containing nil.

local function testEncodeAndDecodePairViaTuple( decTuple, ... )

	local encArray = { ... }
	local enc = table.concat( encArray )
	
	local encResult = blonde.encode( unpack( decTuple ) )
	if enc ~= encResult then
		local message = string.format(
					"blonde.encode: result was incorrect\n\nexpected:\n%s\n\nactual:\n%s\n",
					decDumpString( enc ),
					decDumpString( encResult ) )
		print( message )
		error( message )
	end
	
	local decResult = { blonde.decode( enc ) }

	for i, v in ipairs( decResult ) do
	
		if not compareValues( decTuple[ i ], v ) then
			local message = string.format(
						"blonde.decode: result was incorrect\n\nexpected:\n%s\n\nactual:\n%s\n",
						tostring( decTuple [ i ] ),
						tostring( v ) )
			print( message )
			error( message )
		end

	end
	
end


--------------------------------------------------------------------------------

function KSBlondeTest.testNil()

	testEncodeAndDecodePair( nil, "y\001", "z" )

end

--------------------------------------------------------------------------------

function KSBlondeTest.testBooleans()

	testEncodeAndDecodePair( true, "y\001", "t" )
	testEncodeAndDecodePair( false, "y\001", "f" )

end

--------------------------------------------------------------------------------

function KSBlondeTest.test1ByteInts()

	-- One-byte ints.

	testEncodeAndDecodePair( 0, "y\001", "\000" )
	testEncodeAndDecodePair( 1, "y\001", "\001" )
	testEncodeAndDecodePair( 99, "y\001", "\099" )
	testEncodeAndDecodePair( 100, "y\001", "\100" )
	testEncodeAndDecodePair( -1, "y\001", "\255" )
	testEncodeAndDecodePair( -2, "y\001", "\254" )
	testEncodeAndDecodePair( -42, "y\001", "\214" )
	testEncodeAndDecodePair( -99, "y\001", "\157" )
	testEncodeAndDecodePair( -100, "y\001", "\156" )

end

--------------------------------------------------------------------------------

function KSBlondeTest.test2ByteInts()

	-- GRUNGE [scouten 2010-11-04]: The spec says that the encoding is little-endian
	-- but the library does not yet have byte-swapping code. If these tests fail,
	-- we're probably on a new OS that is big-endian.

	testEncodeAndDecodePair( 101, "y\001", "ie\000" )
	testEncodeAndDecodePair( 259, "y\001", "i", "\003", "\001" )
	testEncodeAndDecodePair( 32767, "y\001", "i\255\127" )
	testEncodeAndDecodePair( -101, "y\001", "i\155\255" )
	testEncodeAndDecodePair( -32767, "y\001", "i\001\128" )
	testEncodeAndDecodePair( -32768, "y\001", "i\000\128" )

end

--------------------------------------------------------------------------------

function KSBlondeTest.test4ByteInts()
	
	-- GRUNGE [scouten 2010-11-04]: The spec says that the encoding is little-endian
	-- but the library does not yet have byte-swapping code. If these tests fail,
	-- we're probably on a new OS that is big-endian.

	testEncodeAndDecodePair( 32768, "y\001", "l\000\128\000\000" )
	testEncodeAndDecodePair( -32769, "y\001", "l\255\127\255\255" )
	testEncodeAndDecodePair( 1234567890, "y\001", "l\210\002\150\073" )
	testEncodeAndDecodePair( 2147483647, "y\001", "l\255\255\255\127" )
	testEncodeAndDecodePair( -2147483648, "y\001", "l\000\000\000\128" )
	testEncodeAndDecodePair( -2147483647, "y\001", "l\001\000\000\128" )

end

--------------------------------------------------------------------------------

function KSBlondeTest.testNonIntegers()

	-- NOTE [scouten 2010-11-05]: This test also represents integers that fall
	-- outside of the signed 32-bit space. Those get encoded as doubles.
	
	testEncodeAndDecodePair( 0.000001, "y\001", "n\141\237\181\160\247\198\176\062" )
	testEncodeAndDecodePair( 1/0, "y\001", "n\000\000\000\000\000\000\240\127" )
	testEncodeAndDecodePair( 2147483648, "y\001", "n\000\000\000\000\000\000\224\065" )
	testEncodeAndDecodePair( -2147483649, "y\001", "n\000\000\032\000\000\000\224\193" )

end


--------------------------------------------------------------------------------

local function negativeZero()
	return -0
end

--------------------------------------------------------------------------------


function KSBlondeTest.testNegativeZero()

	local encResult = blonde.encode( negativeZero() )
	local decResult = blonde.decode( encResult )

	-- NOTE [matthewj 2014-05-14]: 0 == -0 so we can't just check equality, we have to
	-- ensure the sign is correct as well. Dividing by 0/-0 should result in inf/-inf 
	-- so we can divide and check the result
	-- WARNING: On Android versions pre-Lollipop, both GDB and Halid will show this 
	-- -0 as a 0. Division is the only way to verify the actual value. Beware that this
	-- may lead to issues printing the value out.
	if decResult ~= negativeZero() or ( ( 1 / decResult ) > 0 ) then
		error( "blonde.encode/decode failed for -0" )
	end
end

--------------------------------------------------------------------------------

function KSBlondeTest.testStrings()

	testEncodeAndDecodePair( "", "y\001", "\128" )
	testEncodeAndDecodePair( "x", "y\001", "\129x" )
	testEncodeAndDecodePair( "This string is 27 bytes lon", "y\001", "\155This string is 27 bytes lon" )
	testEncodeAndDecodePair( "This string is 28 bytes long", "y\001", "s\028This string is 28 bytes long" )

	testEncodeAndDecodePair( "This string is 100 bytes long....This string is 100 bytes long....This string is 100 bytes long.....",
						"y\001", "s\100",
						"This string is 100 bytes long....This string is 100 bytes long....This string is 100 bytes long....." )

	testEncodeAndDecodePair( "This string is 101 bytes long....This string is 101 bytes long....This string is 101 bytes long......",
						"y\001", "\sie\000",
						"This string is 101 bytes long....This string is 101 bytes long....This string is 101 bytes long......" )

end

--------------------------------------------------------------------------------

function KSBlondeTest.testSimpleTables()

	testEncodeAndDecodePair( {}, "y\001", "kx" )
	
	testEncodeAndDecodePair( { a = 4 }, "y\001",
		"k",			-- {
			"\129a",		-- key: "a"
			"\004",			-- value: 4
		"x" )			-- }

	testEncodeAndDecodePair( { 1, 2, 3, "four" }, "y\001",
		"k",			-- {
			"\001",			-- key: 1
			"\001",			-- value: 1
			"\002",			-- key: 2
			"\002",			-- value: 2
			"\003",			-- key: 3
			"\003",			-- value: 3
			"\004",			-- key: 4
			"\132four",		-- value: "four"
		"x" )			-- }

	testEncodeAndDecodePair( { 1, x = true }, "y\001",
		"k",			-- {
			"\001",			-- key: 1
			"\001",			-- value: 1
			"\129x",		-- key: "x"
			"t",			-- value: true
		"x" )			-- }

end

--------------------------------------------------------------------------------

function KSBlondeTest.testTableSortKeySequence()

	testEncodeAndDecodePairExpectSort(
		{
			[ true ] = 2,		-- NOTE [scouten 2010-11-05]: This is not the sort order!
			[ false ] = 1,
			[ 42 ] = 5,
			[ -18 ] = 3,
			[ 0.17 ] = 4,
			[ "" ] = 6,
			[ "a" ] = 7,
			[ "abc" ] = 8,
		},
		"y\001",
		"k",			-- {
			"f",			-- key: false
			"\001",			-- value: 1
			"t",			-- key: true
			"\002",			-- value: 2
			"\238",			-- key: -18
			"\003",			-- value: 3
			"n\195\245\040\092\143\194\197\063",
							-- key: 0.17
			"\004",			-- value: 4
			"\042",			-- key: 42
			"\005",			-- value: 5
			"\128",			-- key: ""
			"\006",			-- value: 6
			"\129a",		-- key: "a"
			"\007",			-- value: 7
			"\131abc",		-- key: "abc"
			"\008",			-- value: 8
		"x" )			-- }

end

--------------------------------------------------------------------------------

function KSBlondeTest.testTuple()

	testEncodeAndDecodePairViaTuple( {},
		"y\001",
		"p\000"			-- tuple: 0 values
	)

	testEncodeAndDecodePairViaTuple( { 1, 2, 3, "4" },
		"y\001",
		"p\004",		-- tuple: 4 values
			"\001",		-- number 1
			"\002",		-- number 2
			"\003",		-- number 3
			"\1294"		-- string "4"
	)
	
	-- FIXME [scouten 2011-02-01]: Could do better at testing error cases.

end

--------------------------------------------------------------------------------

function KSBlondeTest.testEncodeRejectsFunction()

	expectError( function()
		blonde.encode( function() end )
	end, "Should not encode a function value" )

end

--------------------------------------------------------------------------------

function KSBlondeTest.testEncodeRejectsTableWithMetatable()

	local t = setmetatable( {},
		{
			__tostring = function() return "table with metatable" end
		} )

	expectError( function()
		blonde.encode( t )
	end, "Should not encode a table with a metatable" )

end

--------------------------------------------------------------------------------

	-- NOTE [epoley 2011-01-18]: Bumping the two below up to .4 from .25, as
	-- the "optimized" BLONDE is less optimal for encoding single values.
	
--------------------------------------------------------------------------------

function KSBlondeTest.testEncodeSimpleNumberPerformance()

	local testTimeout = 0.3

	expectFasterThan( testTimeout, function()	-- sigh: simulator can do this in .02s
		for i = 1, 50000 do
			blonde.encode( 4 ) -- arbitrary number
		end
	end )

end

--------------------------------------------------------------------------------

function KSBlondeTest.testEncode4ByteIntPerformance()

	local testTimeout = 0.5
	expectFasterThan( testTimeout, function()	-- sigh: simulator can do this in .02s
		for i = 1, 50000 do
			blonde.encode( 1234567890 ) -- arbitrary number
		end
	end )

end

--------------------------------------------------------------------------------

function KSBlondeTest.testEncodeSimpleStringPerformance()

	local testTimeout = 0.25
	expectFasterThan( testTimeout, function()	-- sigh: simulator can do this in .02s
		for i = 1, 25000 do
			blonde.encode( "foo" ) -- arbitrary string
		end
	end )

end

--------------------------------------------------------------------------------

function KSBlondeTest.testEncodeLongerStringPerformance()

	local testTimeout = 0.3
	expectFasterThan( testTimeout, function()
		for i = 1, 25000 do
			blonde.encode( "we wish to test encoding a string that is well over the 27-byte limit for BLONDE short strings" ) -- arbitrary string
		end
	end )

end

--------------------------------------------------------------------------------

function KSBlondeTest.testEncodeSmallTablePerformance()

	local testTimeout = 0.8
	expectFasterThan( testTimeout, function()
		for i = 1, 10000 do
			blonde.encode(
				{
					[ "name" ] = "Foobar Baz",
					[ "id" ] = 1234,
					[ 42 ] = true,
					[ "abcdefghijklm" ] = "01234567890ZYXW",
				}
			)
		end
	end )

end

--------------------------------------------------------------------------------

-- See KSBlondeLargeTableTest.lua for performance testing on a large table

--------------------------------------------------------------------------------

function KSBlondeTest.testRejectsSelfReferencingTable()

	local table = { a = "b" }
	table[ "dangerousReference" ] = table
	
	expectError( function()
		blonde.encode( table )
	end, "Should not encode a table that references itself" )

end

--------------------------------------------------------------------------------

function KSBlondeTest.testDecodeBadBytestreamNotEnoughBytes()

	expectError( function()
		blonde.decode( "y\001\001n\141\237\181\160\247\198\176" )
	end, "Should not decode a bytestream with too few bytes" )
	
	expectError( function()
		blonde.decode( "y\001\001s\033This string is 28 bytes long" )
	end, "Should not decode a string bytestream with too few bytes" )

end

--------------------------------------------------------------------------------

function KSBlondeTest.testDecodeBadBytestreamTooManyBytes()

	expectError( function()
		blonde.decode( "y\001\001l\255\255\255\127\000" )
	end, "Should not decode a bytestream with too many bytes" )
	
	expectError( function()
		blonde.decode( "y\001\001s\028This string is not 28 bytes long" )
	end, "Should not decode a string bytestream with too many bytes" )

end

--------------------------------------------------------------------------------

function KSBlondeTest.testDecodeBadBytestreamTwoValues()

	expectError( function()
		blonde.decode( "y\001\001n\141\237\181\160\247\198\176\062f" )
	end, "Should not decode a bytestream with more than one value/too many bytes" )

end

--------------------------------------------------------------------------------

function KSBlondeTest.testDecodeBadBytestreamUnrecognizedType()

	expectError( function()
		blonde.decode( "y\001\001y\255\255\255\127" )
	end, "Should not decode a bytestream with an unrecognized type marker" )

end

--------------------------------------------------------------------------------

function KSBlondeTest.testDecodeBadBytestreamNoVersion()

	expectError( function()
		blonde.decode( "n\000\000\032\000\000\000\224\193" )
	end, "Should not decode a bytestream without a BLONDE version specified" )

end

--------------------------------------------------------------------------------

function KSBlondeTest.testDecodeBadBytestreamNewerVersion()

	expectError( function()
		blonde.decode( "y\255\255n\000\000\032\000\000\000\224\193" )
	end, "Should not decode a bytestream for a newer BLONDE version" )

end

--------------------------------------------------------------------------------

function KSBlondeTest.testFuzzCrashes()

	local crashes = {
		"eQFr8HAA+YGCAWvxcDEAAP//AAABAQCBeQEBAIM2gP8fAAIAgTaMjIyMjGSMjAACjIaMjIysjIyMjA+MH4yAgT/j4+PT4+Pj4+MkJIyMjIyMZIyMAAKMjIwBAIyMjIyMjIxwcAEAZAD1AQAAgXIkgT8Ba/FwAQAAgACMjCQkQAAkJCQkJCSAgX8Aa/FwAQCBAPX0//+AciQkJCTxcAEAgQD1AQAAgXIkgT8Ba/FwAQAAoAABAACBcnIBAAAAApB3EA==",
		"eQFr8XA1NTU1NToAEAAANQEAgf////9wAQCBEP5q8XABAKE2eHg=",
		"eQFr8XABAIF5AWvxcAEAgTYBa/FwWlpaWlpaWlpaWlpaWlpaAQABAHh4",
		"eQFr8XAZBBkZGRkBAHSEAQAfAAAAgTYUi39wAQDNNnhWeQFr8XABAHSEARsf9/8AgTYUi/FwAAAAAHhW",
		"eQFr8XAbAIF5AACAAAEAgQAAgAABAIE2AWbxigEBeHg=",
		"eQFr8XMAAoL///FwGACBAaampqampqampqampqampqampmvxcAEAgYEBpqampqampqampqampqampqama/F56X4AAQCBNng2bXg=",
		"eQFr8fFwKysrKwBAgTYBbAArKysrKysrKwAAAECBAGQgAAAAa/HxcCsrKysrKysrKysrKwAAAECBNgFsAAA=",
		"eQFrLgAAAABccDssLnAuo6Ojo6Ouo6OjwqOjo6Ojo3CA/wAAAACAAdnZ2ZOlXKAAgABwLnAuAAAfAACAAf/Z2dnZj/E=",
		"eQFrTGECc/AiZA==",
		"eQFrY3BjY2NjY2NjYwD/Y/FAAAAAY2NjY2//////Y2NjhWNjY2MScQEAgTYBa/GNAQCBQ3h4",
		"eQFrZmECc2tmYQJz31B4",
		"eQFra/Fw6wBw6wCBeQAE8fFwYGBgYGBgYGBgYGBgYGBgYGBgYGBgYGBgYGBgYGBgYGBgYGBgYGBgYGBgYGBgYGBgYGBgYGBgYGBgYGBgYGBgYGBgYGBgYGBgYGBgYGBgYGBgYGBgYGBgYGBgYGBgYGBgYOsAgWEBa/F8AQCBNgGBYQFr8XABAIE2AWtw6wABa0DxcOtwa3D1AAFra/FwYHDrAIFhAVrxcAF5AWtrsesAgWEBawCBYQFr0HABAIE2AYFhAWvxcAEAgTYBa3DrAACBNgFrcOsAAWtA8XDrjmtw6wABa2vxcOtw6wCBYQFr8Y4BAIE2IGvxcBAAgXh4",
		"eQFra/Fw6wCBeQA7BNzxcOsAgWEBa/FwAQCBNgFubm5ubm5ubm5ubm5ubm5ubm5ugG5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ub25ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5uZoAAAmZmZmZmZmZubm5ubm5ubm5ubm5ubm5ubm5ubG5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5Abm5ubm5uVm5ubm5ubm5ubllubm5uAAACAG5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5Tbm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ueG5ubm5ubm5ubm5xbm5ubm5ubm5ubm5uboE2AVxw6wAkcOtwa3DrBAHxcOsgAHDrcOsAcOsAgW0ABNzxSUlJSUlJTUlJUUlJSUlJcOsAgWEBa4yMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMbm5ubm5ubm5ubm5ud25ubm5ubmxubm5ubm5ubgIAbm5ubm5uTW5ubm5ubm5ubm5ubm5ubm5uXW5ubm5ubm5ubm5ubm5ubm5ubm5ubm5usW5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubl9ubm5ubm5ubm5ubm5ubllubm5ubm5ubm5ubm5ubm5ubm5ubm5u/wBubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm4AgfoAAPpmZmZmZmZKZmZAZmZmgAACZmZmZmZmZmZmZm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5sbm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm6Kbm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubkBubm5ubm5Wbm5ubm5ubm5uWW5ubm4AAAIAbm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ublNubm5ubm5ubm5ubm5ubm5Obm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm54bm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ugTYBXHDrAElJSUlJSUlJSVFJSUlJSXBeXl5eXl5eXl5eXl5eXl5eXl5eXl5eXl5eXl5eXl5eXl5eXl5eXl5eXl5eXl5eXl5eXl5eXl5eXl5eXl5eXl5eXl5eXl5eXl5eXl5eXl5eXl5eXl5eXl5eXl5eXl5eXl5eXl5eXl5eXl5eXl5eXl5eXl5eXl5eXl5eXl5e6wCBYQFrjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIzxcAEAgTYBg25ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ud25ubm5ubmxubm5ubm5ubgIAbm5ubm5uTW5ubm5ubm5ubm5ubm5ubm5uXW5ubm5ubm5ubm5ubm5ubm5ubm5ubm5usW5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubl9ubm5ubm5ubm5ubm5ubllubm5ubm5ubm5ubm5ubm5ubm5ubm5u/wBubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm4AgfoAAPpmZmZmZmZKZmZAZmZmgAACZmZmZmZmZmZmZmZmZmJuZmdmZmZmZmZmZmZmZmZmZmZmZmZmACBhAcvxcAEAgTYBbm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5uAABmZmZmZmZmZmYAAABkAAAS//9mZmZmAADxgAQAZmZmZmZmZmZm//9mZmZmZmZmZiD5ZmZmjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyM8XABAIE2AYOMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIykjIyMjIyM8XABAIE2AYNubm5ubm5ubm5ubm5ubm5ubm5ubm5mZmZmZkhmZmZmZmYMAgAAZmZmZmZmZmZmZv9hAWvxcAEAgTYga/FwAQCBNnhmZmZmZmZmZmZmZgAAAIAAEv//ZmZmZgAAj4AEAGZmZmZmZmZmZgBmZmZmZmZmamZmZmZmZmZmZmaJZmZmZmZmUmZmZgAAAAF6ZmZmZmZ+//94",
		"eQFra/Fw6wCBeQAE8fFw6wEAgTYBa3DrACRrZmZmZmZpaWlpaWlpaWlpaWlpaWlpafFw6wEAgTYBa3DrACRrZmZmZmZpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpS2lpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaXBpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlXaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlmZmZmaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlLaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpcGlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWZmZmb//3g=",
		"eQFra/FwwQBwFxcXFxcXFxcX6+qBTwAEAAAAAQB1YesbAY5r8XDrcOsAgWEBa/FwAeGBRiBr8W8B6wCBPJR4a3DrAAH/UfFmy3CBZCBr6FcBAJ02eHg=",
		"eQFraWECc7NDZA==",
		"eQFrcP8AAACMdIFrg/8AAACMdIFDdGt0gUNeYdOCdBDjeEN0a3SBQ15h04J0EON4eA==",
		"eQFrg1hzc3Nzc3Nzra14",
		"eQFrgAABW1tbW1tbJIAEAHRrg0ACdnAkgAQAdKSkpKSkpKSkpKSkpKRwL4A=",
		"eQFrgQJh0HPyAHg=",
		"eQFrgWEBAAAAAAAEAABwbJYUAWuBYQEA9gJsZABkWXBslnF472YAAABZioFAAP8TmGECbGQAAAJZcGyWQ/1qbmEBAABhAGxhAllwbJZxygBrfJhDeHg=",
		"eQFrgWECa4FhAnMBQ3P3Q3g=",
		"eQFrgWH3dAAAA9hhdABkXXBhAmQAAAB0JXRhAnSBYQJ0AnSBQ4D/dIE=",
		"eQFrgXR0dHR0dHR0dHBha4FhAYyBYQJAdHR0dHR0dHR0eHR0VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVO1VVVVVVVVVVVVVVVVVVV1VVdHR0dHR0dHR0dHSBAnSAYQKRjUM=",
		"eQFrgXR0dHR0dHRrgXRwaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlUaWlpaXNpaWlpaWlpaWmBQw==",
		"eQFriXFw6wBw6wCB8XAWFhYWFhYWFhYWFhb8FhboAxZzc3Nzc3Nzc3Nzc5Fzc3NzcwEAc3Nzc3Nzc3Nzl3Nzc3Pj48zj4+Pj4+Pj4+Pj8uPj///j4+Pj4+Pj4+Pj4+Pj4+PT4+Pj4+Pj4+Pj4+Pj4+Pj4+Pj4+Pj4+Pj4+Pj9+Pjf////wAQawCBYQFr8VwBAIEseHg=",
		"eQFrnnACdIFDeA==",
		"eQFro2ECcABkeA==",
		"eQFwDHAPIFCuYSBQIFAF/wD/ZF5eXl5eXmkgUEBAQEBANShAQEBAQEBAQEBA",
		"eQFwDQFwDSBArvsgQK77AWEAQyBArvsgQK77AWEAQwFhAEN4",
		"eQFwEzETExMjExMTMxMTExMTExMTExMTExMTExMTExMTExMTbRMTEyQTExMTExMTExMTExMTExMTExMTExMTExMTExMTExMTExMTExMTExMTEyMTExMTExMTExMTExOrq4qrXm5Vbm4BcG4B",
		"eQFwGAAAYmJiYl9NAgFwX00YAABiYmJiYnw=",
		"eQFwOVZWVlZWVjdWVlZWVlZWVlYAEPFnAQBrAIE2AWvTZwHugHx4eGsAgTYBEABwAe6ANnh4",
		"eQFwPDw8PDw8PDw8PPn6/g8PDw//BXo=",
		"eQFwX00CAV9NAgFwX00YIAABAHBfTRgA6gAAbAACfA==",
		"eQFwX00CAXpfTRgAAAEAbEAAfHBfTQIBev9NGAAAAQBsQAB8cF9NAgF6X00YAAABAGxAAAABAGxAAHw=",
		"eQFwYKurq6uCq6urQAAgq6urq6urq25uX01ubm5/TWQAAASrq6urq6sQAKurvKt5AXBdX02rq6urq/4BcHBfTW5ubnkBcHBKSkpKq6urq6urAP+rq6ureQFwcF9NboFueQFwcEpKSlxKSkpKSkpKSkpKSkpKSkpKSkpKSm5AAAAAXm5ubm5fTW5ubm5NXm4xCG5u/25u/25ubm0Abm4CEXBuSkpKSkpKYkpKSkpKSkpKbvQAAABebm5ubl9NbiBubk1ebjFubm7/bm7/bm5ubQBubgIRZG4BIU1ubm5RX2Fubm5ubm5ATW5ubm5qXm1ubiBNbm5ubk1ebm5ubgFwbgE=",
		"eQFwcF9Nbm55bl9Nbm5u9/f3bvf39/f39/f39/f39/f39/cABAAAA+j39/f39/f39/f393dNXmJubm5ubm5ubm31bm4C9/f4BAAAA+j39/f39/f39/f393dNGPf39/f39/f39/f39/f39/f39/X393dNXmJublRubm5ubm31bo0CEF9Nbm5u9/f39/f39/f39/f39/f39/cABAAAA+j39/f39/f39/f393dNXmJubm5ubm5ubm31bm4C9/f4BAAAA+j39/f39/f39/f393dNGPf39/f39/f39/cABAAAA+j39/f39/f39/X393dNXmJublRubm5ubm31bo0CEHBuAQ==",
		"eQFwcFNNbm5uiV9naVhubk1eb25ubm5ubm5ubQBuDAwMDAwMDAwMDAwMDAYMDAwMbgIBcG4B",
		"eQFz4P8CdIECeA==",
		"MNpmbrzTeB6B2iDThGHT02HExMTExMTExMTExCBmZoRmYsTExMTExMTExMTeZP8AAACA",
		"eQFrLgAAAABccDsgLmQucC4AAAAAAIABBASAAQQE2QQD5wQEAYAAAAAEBAQEEPoEBAQEBAT2AwQEBGZmZmZmbgQEBO0EBAQEBANmZmZmZm4EAQCAAQQE2QQDzAQEAAD6BAEAJQQEBKGkWA==",
		"eQFwLgAAAABccDsgLnAucC4AAAAAAIAB2fT09PT09PT09PT09PT09NnZBAPnBAQD6P0E7QQEBAQEA+cEBAAA+gQBIyVePj4AAPoEBO1kBAQEBAPnBAQAAPoEASMlXj4+PgRABASPBAQEBO0EBAQEBAPnBAQAAPoEAQAlBAQEBAQEBAQEQAQEjwPoBATtBAQEBAQD5wQEAAD6BAEjJV4+Pj7/Af/Vq6GkWA==",
		"eQFrLgAAAABccDsgLnAucC2AAgAAAIDoBAEAJQQEBAQEBBD6BAAEBAAAcwQEEPoEBAQEBAT2AwUEBDo+OgQEBO0EBAQE/wAAAAMAAPoEAQAEOjo6Ou0EAIAEBDo6Ojo6BAQ6Ojr/Ojo6Ojo6Ojs6OjpDOjoaOho6Ojo6RgQEBO0EBAQEBAPn7gMAAPomAQAlXj4+q6GkWA==",
		"eQFrLgAAAABccDsgLnAucC4AcDsgLnAucNnZBAPnBAQAAPoEAQAlBAQE6QMEEPoEBAQEBAT2AwQEBARABASPBAQEBO0EBID/BAPnBAQA5PkEAQAlBAQE5wQEAOT5BAQEBAQEBAQEA+cEBAAA+gQBACVePj4+/wH/AEChpFg=",
		"eQFrLgAAAABccDsgLnAucC4AAAAAAIAB2dnZBAPnBAQAAPoEAQAlBCYEBAQubC4AAAAAAIAB2dnZBAPnBASPBGZmZmZmbgQEBAPnBAQAAAQEBAQEQAQEjwQEBATtBAQEBAQD5wQEAAD6IwEAJV4+Pj7nAf/Vq6GkWA==",
		" ",
		"eQFrg3lpgAICAgJhg2UBAgLodHAN6HRwDXANgGGDaYACDYBhg2lqAoACDYBhg2lqAgICAmFKZmZmZm6AYYNpgAICYWZmZmZmbgECAuh0cA2AYYNpgN8D6HRwDYBhg2mAAgICAmECYYNlATvZ",
		"eQFrTGECc/AiZA==",
		"eQFrgQJh0HPyAHg=",
		"eQFwPDw8PDw8PDw8PPn6/g8PDw//BXo=",
		"eQFrgWH3dAAAA9hhdABkXXBhAmQAAAB0JXRhAnSBYQJ0AnSBQ4D/dIE=",
		"eQFr8XMAAoL///FwGACBAaampqampqampqampqampqampmvxcAEAgYEBpqampqampqampqampqampqama/F56X4AAQCBNng2bXg=",
		"eQFr8HAA+YGCAWvxcDEAAP//AAABAQCBeQEBAIM2gP8fAAIAgTaMjIyMjGSMjAACjIaMjIysjIyMjA+MH4yAgT/j4+PT4+Pj4+MkJIyMjIyMZIyMAAKMjIwBAIyMjIyMjIxwcAEAZAD1AQAAgXIkgT8Ba/FwAQAAgACMjCQkQAAkJCQkJCSAgX8Aa/FwAQCBAPX0//+AciQkJCTxcAEAgQD1AQAAgXIkgT8Ba/FwAQAAoAABAACBcnIBAAAAApB3EA==",
		"eQFr8XA1NTU1NToAEAAANQEAgf////9wAQCBEP5q8XABAKE2eHg=",
		"eQFr8XABAIF5AWvxcAEAgTYBa/FwWlpaWlpaWlpaWlpaWlpaAQABAHh4",
		"eQFrY3BjY2NjY2NjYwD/Y/FAAAAAY2NjY2//////Y2NjhWNjY2MScQEAgTYBa/GNAQCBQ3h4",
		"eQFwOVZWVlZWVjdWVlZWVlZWVlYAEPFnAQBrAIE2AWvTZwHugHx4eGsAgTYBEABwAe6ANnh4",
		"eQFr8XAbAIF5AACAAAEAgQAAgAABAIE2AWbxigEBeHg=",
		"eQFr8XAZBBkZGRkBAHSEAQAfAAAAgTYUi39wAQDNNnhWeQFr8XABAHSEARsf9/8AgTYUi/FwAAAAAHhW",
		"eQFr8fFwKysrKwBAgTYBbAArKysrKysrKwAAAECBAGQgAAAAa/HxcCsrKysrKysrKysrKwAAAECBNgFsAAA=",
		"eQFrgAABW1tbW1tbJIAEAHRrg0ACdnAkgAQAdKSkpKSkpKSkpKSkpKRwL4A=",
		"eQFwDQFwDSBArvsgQK77AWEAQyBArvsgQK77AWEAQwFhAEN4",
		"eQFwDHAPIFCuYSBQIFAF/wD/ZF5eXl5eXmkgUEBAQEBANShAQEBAQEBAQEBA",
		"eQFwGAAAYmJiYl9NAgFwX00YAABiYmJiYnw=",
		"eQFwX00CAV9NAgFwX00YIAABAHBfTRgA6gAAbAACfA==",
		"eQFwX00CAXpfTRgAAAEAbEAAfHBfTQIBev9NGAAAAQBsQAB8cF9NAgF6X00YAAABAGxAAAABAGxAAHw=",
		"eQFrgWEBAAAAAAAEAABwbJYUAWuBYQEA9gJsZABkWXBslnF472YAAABZioFAAP8TmGECbGQAAAJZcGyWQ/1qbmEBAABhAGxhAllwbJZxygBrfJhDeHg=",
		"eQFwcFNNbm5uiV9naVhubk1eb25ubm5ubm5ubQBuDAwMDAwMDAwMDAwMDAYMDAwMbgIBcG4B",
		"eQFwcF9Nbm55bl9Nbm5u9/f3bvf39/f39/f39/f39/f39/cABAAAA+j39/f39/f39/f393dNXmJubm5ubm5ubm31bm4C9/f4BAAAA+j39/f39/f39/f393dNGPf39/f39/f39/f39/f39/f39/X393dNXmJublRubm5ubm31bo0CEF9Nbm5u9/f39/f39/f39/f39/f39/cABAAAA+j39/f39/f39/f393dNXmJubm5ubm5ubm31bm4C9/f4BAAAA+j39/f39/f39/f393dNGPf39/f39/f39/cABAAAA+j39/f39/f39/X393dNXmJublRubm5ubm31bo0CEHBuAQ==",
		"eQFrgXR0dHR0dHR0dHBha4FhAYyBYQJAdHR0dHR0dHR0eHR0VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVO1VVVVVVVVVVVVVVVVVVV1VVdHR0dHR0dHR0dHSBAnSAYQKRjUM=",
		"eQFra/Fw6wBw6wCBeQAE8fFwYGBgYGBgYGBgYGBgYGBgYGBgYGBgYGBgYGBgYGBgYGBgYGBgYGBgYGBgYGBgYGBgYGBgYGBgYGBgYGBgYGBgYGBgYGBgYGBgYGBgYGBgYGBgYGBgYGBgYGBgYGBgYGBgYOsAgWEBa/F8AQCBNgGBYQFr8XABAIE2AWtw6wABa0DxcOtwa3D1AAFra/FwYHDrAIFhAVrxcAF5AWtrsesAgWEBawCBYQFr0HABAIE2AYFhAWvxcAEAgTYBa3DrAACBNgFrcOsAAWtA8XDrjmtw6wABa2vxcOtw6wCBYQFr8Y4BAIE2IGvxcBAAgXh4",
		"eQFra/FwwQBwFxcXFxcXFxcX6+qBTwAEAAAAAQB1YesbAY5r8XDrcOsAgWEBa/FwAeGBRiBr8W8B6wCBPJR4a3DrAAH/UfFmy3CBZCBr6FcBAJ02eHg=",
		"eQFwYKurq6uCq6urQAAgq6urq6urq25uX01ubm5/TWQAAASrq6urq6sQAKurvKt5AXBdX02rq6urq/4BcHBfTW5ubnkBcHBKSkpKq6urq6urAP+rq6ureQFwcF9NboFueQFwcEpKSlxKSkpKSkpKSkpKSkpKSkpKSkpKSm5AAAAAXm5ubm5fTW5ubm5NXm4xCG5u/25u/25ubm0Abm4CEXBuSkpKSkpKYkpKSkpKSkpKbvQAAABebm5ubl9NbiBubk1ebjFubm7/bm7/bm5ubQBubgIRZG4BIU1ubm5RX2Fubm5ubm5ATW5ubm5qXm1ubiBNbm5ubk1ebm5ubgFwbgE=",
		"eQFwEzETExMjExMTMxMTExMTExMTExMTExMTExMTExMTExMTbRMTEyQTExMTExMTExMTExMTExMTExMTExMTExMTExMTExMTExMTExMTExMTEyMTExMTExMTExMTExOrq4qrXm5Vbm4BcG4B",
		"eQFrgXR0dHR0dHRrgXRwaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlUaWlpaXNpaWlpaWlpaWmBQw==",
		"eQFriXFw6wBw6wCB8XAWFhYWFhYWFhYWFhb8FhboAxZzc3Nzc3Nzc3Nzc5Fzc3NzcwEAc3Nzc3Nzc3Nzl3Nzc3Pj48zj4+Pj4+Pj4+Pj8uPj///j4+Pj4+Pj4+Pj4+Pj4+PT4+Pj4+Pj4+Pj4+Pj4+Pj4+Pj4+Pj4+Pj4+Pj9+Pjf////wAQawCBYQFr8VwBAIEseHg=",
		"eQFrLgAAAABccDssLnAuo6Ojo6Ouo6OjwqOjo6Ojo3CA/wAAAACAAdnZ2ZOlXKAAgABwLnAuAAAfAACAAf/Z2dnZj/E=",
		"eQFra/Fw6wCBeQAE8fFw6wEAgTYBa3DrACRrZmZmZmZpaWlpaWlpaWlpaWlpaWlpafFw6wEAgTYBa3DrACRrZmZmZmZpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpS2lpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaXBpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlXaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlmZmZmaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlLaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpcGlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWZmZmb//3g=",
		"eQFra/Fw6wCBeQA7BNzxcOsAgWEBa/FwAQCBNgFubm5ubm5ubm5ubm5ubm5ubm5ugG5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ub25ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5uZoAAAmZmZmZmZmZubm5ubm5ubm5ubm5ubm5ubm5ubG5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5Abm5ubm5uVm5ubm5ubm5ubllubm5uAAACAG5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5Tbm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ueG5ubm5ubm5ubm5xbm5ubm5ubm5ubm5uboE2AVxw6wAkcOtwa3DrBAHxcOsgAHDrcOsAcOsAgW0ABNzxSUlJSUlJTUlJUUlJSUlJcOsAgWEBa4yMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMbm5ubm5ubm5ubm5ud25ubm5ubmxubm5ubm5ubgIAbm5ubm5uTW5ubm5ubm5ubm5ubm5ubm5uXW5ubm5ubm5ubm5ubm5ubm5ubm5ubm5usW5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubl9ubm5ubm5ubm5ubm5ubllubm5ubm5ubm5ubm5ubm5ubm5ubm5u/wBubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm4AgfoAAPpmZmZmZmZKZmZAZmZmgAACZmZmZmZmZmZmZm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5sbm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm6Kbm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubkBubm5ubm5Wbm5ubm5ubm5uWW5ubm4AAAIAbm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ublNubm5ubm5ubm5ubm5ubm5Obm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm54bm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ugTYBXHDrAElJSUlJSUlJSVFJSUlJSXBeXl5eXl5eXl5eXl5eXl5eXl5eXl5eXl5eXl5eXl5eXl5eXl5eXl5eXl5eXl5eXl5eXl5eXl5eXl5eXl5eXl5eXl5eXl5eXl5eXl5eXl5eXl5eXl5eXl5eXl5eXl5eXl5eXl5eXl5eXl5eXl5eXl5eXl5eXl5eXl5eXl5e6wCBYQFrjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIzxcAEAgTYBg25ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ud25ubm5ubmxubm5ubm5ubgIAbm5ubm5uTW5ubm5ubm5ubm5ubm5ubm5uXW5ubm5ubm5ubm5ubm5ubm5ubm5ubm5usW5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubl9ubm5ubm5ubm5ubm5ubllubm5ubm5ubm5ubm5ubm5ubm5ubm5u/wBubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm4AgfoAAPpmZmZmZmZKZmZAZmZmgAACZmZmZmZmZmZmZmZmZmJuZmdmZmZmZmZmZmZmZmZmZmZmZmZmACBhAcvxcAEAgTYBbm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5uAABmZmZmZmZmZmYAAABkAAAS//9mZmZmAADxgAQAZmZmZmZmZmZm//9mZmZmZmZmZiD5ZmZmjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyM8XABAIE2AYOMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIykjIyMjIyM8XABAIE2AYNubm5ubm5ubm5ubm5ubm5ubm5ubm5mZmZmZkhmZmZmZmYMAgAAZmZmZmZmZmZmZv9hAWvxcAEAgTYga/FwAQCBNnhmZmZmZmZmZmZmZgAAAIAAEv//ZmZmZgAAj4AEAGZmZmZmZmZmZgBmZmZmZmZmamZmZmZmZmZmZmaJZmZmZmZmUmZmZgAAAAF6ZmZmZmZ+//94",
	}
	
	local decodeBase64 = require 'KSStringUtils'.decodeBase64
	
	for _, crash in ipairs( crashes ) do
		pcall( blonde.decode, tostring( decodeBase64( crash ) ) )
	end


end

--------------------------------------------------------------------------------

-- FIXME [scouten 2010-11-05]: Test that encode properly rejects other unacceptable
-- value types (esp. userdata).

--------------------------------------------------------------------------------

-- FIXME [scouten 2010-11-05]: Test (more thoroughly) encode/decode performance.

--------------------------------------------------------------------------------

return KSBlondeTest
