#BUGFIX by cg
class: LargeFloat
added: #numBitsInMantissa
changed: #mantissa:exponent:
"{ Encoding: utf8 }"
"
COPYRIGHT (c) 2003 by eXept Software AG
All Rights Reserved
This software is furnished under a license and may be used
only in accordance with the terms of that license and with the
inclusion of the above copyright notice. This software may not
be provided or otherwise made available to, or used by, any
other person. No title to or ownership of the software is
hereby transferred.
"
"{ Package: 'stx:libbasic' }"
"{ NameSpace: Smalltalk }"
LimitedPrecisionReal subclass:#LargeFloat
instanceVariableNames:'biasedExponent mantissa precision'
classVariableNames:'Zero One NaN PositiveInfinity NegativeInfinity Pi_1000 E_1000
Ln10 DefaultPrecision'
poolDictionaries:''
category:'Magnitude-Numbers'
!
!LargeFloat class methodsFor:'documentation'!
copyright
"
COPYRIGHT (c) 2003 by eXept Software AG
All Rights Reserved
This software is furnished under a license and may be used
only in accordance with the terms of that license and with the
inclusion of the above copyright notice. This software may not
be provided or otherwise made available to, or used by, any
other person. No title to or ownership of the software is
hereby transferred.
"
!
documentation
"
Attention:
Experimental & Unfinished Code.
The implementation is neither complete nor tuned for performance - still being developed.
This class provides arbitrary precision floats.
I store floating point numbers in base 2 with some arbitrary precision (arbitrary number of bits).
I do inexact arithmetic like Float.
But I am very slow due to emulated (Large) Integer arithmetic... (compared to IEEE 754 hardwired)
Unlike Float, mantissa is not normalized under the form 1.mmmmmm
It is just stored as an integer.
The sign is stored in the mantissa.
biasedExponent is the power of two that multiply the mantissa to form the number. there is no limitation of exponent (overflow or underflow), unless you succeed in exhausting the VM memory...
Like Float, my arithmetic operations are inexact. They will round to nearest precision LargeFloat.
If two different precisions are used in arithmetic, the result is expressed in the higher precision.
Default operating mode is rounding, but might be one of the other possibility (truncate floor ceiling).
Instance Variables:
mantissa <Integer> the bits of mantissa including sign
exponent <Integer> the times two power to multiply the mantissa (floating binary scale)
precision <Magnitude> number of bits to be stored in mantissa when I am normalized
[author:]
Claus Gittinger
[see also:]
Number
Float LongFloat ShortFloat Fraction FixedPoint
SmallInteger LargeInteger
"
!
examples
"
1000 factorial as a LargeFloat:
(1 to:1000) inject:1 asLargeFloat into:[:p :m | p * m]
1000 factorial as an Integer:
(1 to:1000) inject:1 into:[:p :m | p * m]
compute 20000.0 factorial:
Time millisecondsToRun:[
(1 to:20000) inject:1 asLargeFloat into:[:p :m | p * m]
] -> 210
compute 20000 factorial:
Time millisecondsToRun:[
(1 to:20000) inject:1 into:[:p :m | p * m]
] -> 160
"
! !
!LargeFloat class methodsFor:'instance creation'!
fromFraction:aFraction precision:n
"Note: form below would not be the closest approximation
^ (numerator asLargeFloatPrecision: n)
inPlaceDivideBy: (denominator asLargeFloatPrecision: n)"
| a b mantissa exponent nBits ha hb hm hasTruncatedBits numerator denominator |
numerator := aFraction numerator.
denominator := aFraction denominator.
a _ numerator abs.
b _ denominator abs.
ha _ a highBit.
hb _ b highBit.
"If both numerator and denominator are represented exactly in floating point number,
then fastest thing to do is to use hardwired float division"
nBits _ n + 1.
(ha < nBits and: [hb < nBits])
ifTrue:
[^(numerator asLargeFloatPrecision: n)
inPlaceDivideBy: (denominator asLargeFloatPrecision: n)].
"Shift the fraction by a power of two exponent so as to obtain a mantissa with n+1 bits.
First guess is rough, the mantissa might have n+2 bits."
exponent _ ha - hb - nBits.
exponent > 0
ifTrue: [b _ b bitShift: exponent]
ifFalse: [a _ a bitShift: exponent negated].
mantissa _ a quo: b.
hasTruncatedBits _ a > (mantissa * b).
hm _ mantissa highBit.
"Remove excess bits in the mantissa."
hm > nBits
ifTrue:
[exponent _ exponent + hm - nBits.
hasTruncatedBits _ hasTruncatedBits or: [mantissa anyBitOfMagnitudeFrom: 1 to: hm - nBits].
mantissa _ mantissa bitShift: nBits - hm].
"Check if mantissa must be rounded upward.
The case of tie (mantissa odd & hasTruncatedBits not)
will be handled by Integer>>asLargeFloatPrecision:."
(hasTruncatedBits and: [mantissa odd])
ifTrue: [mantissa _ mantissa + 1].
"build the LargeFloat from mantissa and exponent"
^(aFraction positive
ifTrue: [mantissa asLargeFloatPrecision: n]
ifFalse: [mantissa negated asLargeFloatPrecision: n])
inPlaceTimesTwoPower: exponent
"
(1/2) asLargeFloat
"
"Created: / 26-05-2019 / 03:54:31 / Claus Gittinger"
!
fromInteger:anInteger
^ (self basicNew
mantissa:anInteger
exponent:0) normalize
"
LargeFloat fromInteger:123456
1 asLargeFloat
2 asLargeFloat
1000 factorial asLargeFloat
"
"Modified: / 27-05-2019 / 16:47:15 / Claus Gittinger"
!
fromInteger:anInteger precision:n
^ (self basicNew
mantissa:anInteger
exponent:0
precision:n) normalize
"
LargeFloat fromInteger:123456 precision:6
1000 factorial asLargeFloat
1 asLargeFloat == 1 asLargeFloat
1.0 asLargeFloat == 1.0 asLargeFloat
"
"Created: / 26-05-2019 / 03:54:44 / Claus Gittinger"
"Modified: / 27-05-2019 / 16:46:59 / Claus Gittinger"
!
fromLimitedPrecisionReal:aLimitedPrecisionReal
|shifty numBytes numBitsInMantissa maskMantissa numBitsInExponent maskExponent
numIntegerBits numBits biasExponent sign expPart fractionPart fraction exp|
aLimitedPrecisionReal isFinite ifFalse:[
aLimitedPrecisionReal isNaN ifTrue:[^ self NaN].
aLimitedPrecisionReal > 0 ifTrue:[^ self infinity].
^ self negativeInfinity
].
numBytes := aLimitedPrecisionReal basicSize.
numBitsInMantissa := aLimitedPrecisionReal numBitsInMantissa. maskMantissa := (1 bitShift:numBitsInMantissa) - 1.
numBitsInExponent := aLimitedPrecisionReal numBitsInExponent. maskExponent := (1 bitShift:numBitsInExponent) - 1.
numIntegerBits := aLimitedPrecisionReal numBitsInIntegerPart.
numBits := numBitsInMantissa + numBitsInExponent.
biasExponent := maskExponent bitShift:-1.
shifty := LargeInteger basicNew numberOfDigits:numBytes.
UninterpretedBytes isBigEndian ifTrue:[
1 to:numBytes do:[:i | shifty digitAt:(numBytes+1-i) put:(aLimitedPrecisionReal basicAt:i)].
] ifFalse:[
1 to:numBytes do:[:i | shifty digitAt:i put:(aLimitedPrecisionReal basicAt:i)].
].
sign := (shifty bitAt:numBits+1) == 0 ifTrue: [1] ifFalse: [-1].
expPart := (shifty bitShift:numBitsInMantissa negated) bitAnd: maskExponent.
fractionPart := shifty bitAnd:maskMantissa.
( expPart=0 and: [ fractionPart=0 ] ) ifTrue: [ ^ self zero ].
numIntegerBits == 0 ifTrue:[
" Replace omitted leading 1 in fraction (Notice: quadIEEE format does not do this)"
fraction := fractionPart bitOr: (maskMantissa + 1).
] ifFalse:[
fraction := fractionPart.
].
"Unbias exponent"
exp := biasExponent - expPart + (numBitsInMantissa - numIntegerBits).
^ (self basicNew
mantissa:(fraction * sign)
exponent:(exp negated)
precision:(aLimitedPrecisionReal precision)) normalize
"
1.0 asLargeFloat
take a look at the precision...
1.0 asShortFloat asLargeFloat
1.0 asLongFloat asLargeFloat
1.0 asQDouble asLargeFloat
1 asLargeFloat
(5/3) asLargeFloat
(3/5) asLargeFloat
(1/2) asLargeFloat
2.0 asLargeFloat
20000.0 asLargeFloat
2e6 asLargeFloat
1e300 asLargeFloat
2e300 asLargeFloat
0.5 asLargeFloat
0.25 asLargeFloat
(1.0/20000.0) asLargeFloat
2e-6 asLargeFloat
2e-300 asLargeFloat
-1.0 asLargeFloat
-0.5 asLargeFloat
Float NaN asLargeFloat
Float infinity asLargeFloat
Float negativeInfinity asLargeFloat
"
"Modified (comment): / 17-07-2017 / 15:09:30 / cg"
"Modified: / 28-05-2019 / 09:04:35 / Claus Gittinger"
!
mantissa:m exponent:e
^ (self basicNew mantissa:m exponent:e) normalize
"
LargeFloat mantissa:1 exponent:0
LargeFloat mantissa:2 exponent:0
LargeFloat mantissa:4 exponent:0
LargeFloat mantissa:8 exponent:0
LargeFloat mantissa:1 exponent:-1
LargeFloat mantissa:1 exponent:-2
LargeFloat mantissa:1 exponent:-3
"
"Modified: / 27-05-2019 / 16:48:33 / Claus Gittinger"
!
mantissa:m exponent:e precision:p
^ (self basicNew mantissa:m exponent:e precision:p) normalize
"Modified: / 27-05-2019 / 16:48:39 / Claus Gittinger"
! !
!LargeFloat class methodsFor:'class initialization'!
initialize
NaN := self mantissa:0 exponent:999.
PositiveInfinity := self mantissa:0 exponent:1.
NegativeInfinity := self mantissa:0 exponent:-1.
One := self mantissa:1 exponent:0.
Zero := self mantissa:0 exponent:0.
DefaultPrecision := 200.
"
LargeFloat initialize
"
"Modified: / 10-10-2017 / 15:56:36 / cg"
! !
!LargeFloat class methodsFor:'coercing & converting'!
coerce:aNumber
"return the argument as a LargeFloat"
^ aNumber asLargeFloat
! !
!LargeFloat class methodsFor:'constants'!
NaN
^ NaN
"
LargeFloat NaN
(0.0 uncheckedDivide:0.0)
"
!
infinity
^ PositiveInfinity
"
LargeFloat infinity
(1.0 uncheckedDivide:0.0)
"
!
ln10
"return the ln(10) as largeFloat with approx. 500 bits of precision"
Ln10 isNil ifTrue:[
Ln10 := (10.0 asLargeFloat ln_withAccuracy:(LongFloat readFrom:'1e-100')) precision:100
].
^ Ln10
"
LargeFloat ln10
"
"Created: / 17-07-2017 / 15:15:25 / cg"
"Modified: / 17-07-2017 / 16:42:27 / cg"
!
negativeInfinity
^ NegativeInfinity
"
LargeFloat negativeInfinity
(-1.0 uncheckedDivide:0.0)
"
!
one
^ One
"
LargeFloat one
"
"Created: / 26-05-2019 / 03:47:18 / Claus Gittinger"
!
pi
Pi_1000 isNil ifTrue:[
Pi_1000 := FixedPoint pi asLargeFloat
].
^ Pi_1000.
"
LargeFloat pi
"
!
unity
^ One
"
LargeFloat unity
"
!
zero
^ Zero
"
LargeFloat zero
"
! !
!LargeFloat class methodsFor:'queries'!
defaultPrecision
^ DefaultPrecision
"Created: / 10-10-2017 / 15:58:03 / cg"
!
radix
"answer the radix of a LargeFloats exponent"
^ 2
! !
!LargeFloat methodsFor:'accessing'!
biasedExponent
"anwser the raw exponent;
this is not what a standard floating point representation expects"
^ biasedExponent
"Created: / 27-05-2019 / 16:38:43 / Claus Gittinger"
!
exponent
"anwser the raw exponent;
this is not what a standard floating point representation expects"
^ biasedExponent
"Modified: / 27-05-2019 / 16:37:35 / Claus Gittinger"
!
mantissa
^ mantissa
!
precision
^ precision ? 200
! !
!LargeFloat methodsFor:'arithmetic'!
* aNumber
^ aNumber productFromLargeFloat:self
!
+ aNumber
^ aNumber sumFromLargeFloat:self
"
1.0 asLargeFloat + 20 asLargeFloat
1.0 asLargeFloat + 20
1.0 asLargeFloat + 20.0
1.0 asLargeFloat + ( 2 / 5 )
1.0 asLargeFloat + 0.4 asLargeFloat
20 asLargeFloat + 1.0 asLargeFloat
20 + 1.0 asLargeFloat
20.0 + 1.0 asLargeFloat
( 2 / 5 ) + 1.0 asLargeFloat
"
"Modified (comment): / 17-07-2017 / 15:06:20 / cg"
!
- aNumber
^ aNumber differenceFromLargeFloat:self
!
/ aNumber
^ aNumber quotientFromLargeFloat:self
!
// aNumber
"return the integer quotient of dividing the receiver by aNumber with
truncation towards negative infinity."
^ (self / aNumber) asInteger
"
8 asFloat // 2
-8 asFloat // 2
9 asFloat // 2
-9 asFloat // 2
8 asLargeFloat // 2
-8 asLargeFloat // 2
9 asLargeFloat // 2
-9 asLargeFloat // 2
"
"Created: / 10-10-2017 / 15:50:01 / cg"
!
naiveRaisedToInteger: n
"Very naive algorithm: use full precision.
Use only for small n"
| m e |
m _ mantissa raisedToInteger: n.
e _ biasedExponent * n.
^(m asLargeFloatPrecision: precision) timesTwoPower: e
!
negated
mantissa = 0 ifTrue:[
biasedExponent = 0 ifTrue:[ ^ self ].
self == NaN ifTrue:[^ self].
self == NegativeInfinity ifTrue:[^ PositiveInfinity].
^ NegativeInfinity
].
^ self class
mantissa:(mantissa negated)
exponent:biasedExponent
precision:self precision.
"
LargeFloat unity negated
"
!
raisedToInteger: anInteger
| bitProbe highPrecisionSelf n result |
n _ anInteger abs.
(n < 5 or: [n * precision < 512])
ifTrue: [^ self naiveRaisedToInteger: anInteger].
bitProbe _ 1 bitShift: n highBit - 1.
highPrecisionSelf _ self asLargeFloatPrecision: n highBit * 2 + precision + 2.
result _ highPrecisionSelf one.
[(n bitAnd: bitProbe) = 0 ifFalse: [result _ result * highPrecisionSelf].
(bitProbe _ bitProbe bitShift: -1) > 0]
whileTrue: [result _ result squared].
^ (anInteger negative
ifTrue: [result reciprocal]
ifFalse: [result])
asLargeFloatPrecision: precision
!
reciprocal
^self copy inPlaceReciprocal
! !
!LargeFloat methodsFor:'coercing & converting'!
asInteger
"return an integer with same value - might truncate"
biasedExponent = 0 ifTrue:[^ mantissa].
mantissa == 0 ifTrue:[
"/ INF or NAN
^ self class
raise:#domainErrorSignal
receiver:self
selector:#asInteger
arguments:#()
errorString:'Cannot represent non-finite as integer'.
"/ ^ self asMetaNumber.
].
biasedExponent > 0 ifTrue:[
^ mantissa * (2 raisedTo:biasedExponent)
].
^ mantissa // (2 raisedTo:biasedExponent negated)
"
(self new exponent:0 mantissa:100) asInteger
(self new exponent:1 mantissa:100) asInteger
(self new exponent:-1 mantissa:100) asInteger
"
!
asLargeFloat
"return a large float with same value - that's me"
^ self
"Modified (comment): / 12-06-2017 / 20:56:44 / cg"
!
asTrueFraction
"Answer a fraction or integer that EXACTLY represents self."
biasedExponent = 0 ifTrue: [ ^ mantissa].
mantissa == 0 ifTrue:[
"/ INF or NAN
^ self class
raise:#conversionErrorSignal
receiver:self
selector:#asTrueFraction
arguments:#()
errorString:'Cannot represent non-finite float as fraction'.
"/ ^ self asMetaNumber.
].
biasedExponent > 0 ifTrue: [
^ mantissa bitShift:biasedExponent
].
^ Fraction
numerator: mantissa
denominator: (1 bitShift:biasedExponent negated)
"
0.3 asFloat asTrueFraction
0.3 asShortFloat asTrueFraction
0.3 asLongFloat asTrueFraction
0.3 asLargeFloat asTrueFraction
1 asLargeFloat asTrueFraction
2 asLargeFloat asTrueFraction
0.5 asLargeFloat asTrueFraction
0.25 asLargeFloat asTrueFraction
-0.25 asLargeFloat asTrueFraction
0.125 asLargeFloat asTrueFraction
-0.125 asLargeFloat asTrueFraction
1.25 asLargeFloat asTrueFraction
3e37 asLargeFloat asTrueFraction
LargeFloat NaN asTrueFraction -> error
LargeFloat infinity asTrueFraction -> error
LargeFloat negativeInfinity asTrueFraction -> error
"
!
coerce:aNumber
"return the argument as a LargeFloat"
^ aNumber asLargeFloat
!
generality
"return the generality value - see ArithmeticValue>>retry:coercing:"
^ 100
! !
!LargeFloat methodsFor:'comparing'!
< aNumber
"return true, if the argument is greater"
^ aNumber lessFromLargeFloat:self
!
= aNumber
"return true, if the argument is equal in value"
^ aNumber equalFromLargeFloat:self
"
LargeFloat unity = LargeFloat zero
LargeFloat unity = LargeFloat unity
LargeFloat unity = nil
LargeFloat unity ~= nil
"
!
hash
"return a number for hashing; redefined, since floats compare
by numeric value (i.e. 3.0 = 3), therefore 3.0 hash must be the same
as 3 hash."
biasedExponent == 0 ifTrue:[^ mantissa hash].
biasedExponent < 64 ifTrue:[^ (mantissa bitShift:biasedExponent) hash ].
^ mantissa hash bitXor:biasedExponent hash
"
LargeFloat unity hash
LargeFloat zero hash
3 hash
3.0 hash
3.1 hash
3.14159 hash
31.4159 hash
3.141591 hash
1.234567890123456 hash
1.234567890123457 hash
Set withAll:#(3 3.0 99 99.0 3.1415)
"
! !
!LargeFloat methodsFor:'copying-private'!
postCopy
biasedExponent := biasedExponent copy.
mantissa := mantissa copy.
"Created: / 27-05-2019 / 14:56:59 / Claus Gittinger"
! !
!LargeFloat methodsFor:'double dispatching'!
differenceFromLargeFloat:aLargeFloat
|otherExponent otherMantissa e m|
otherExponent := aLargeFloat biasedExponent.
otherMantissa := aLargeFloat mantissa.
otherMantissa == 0 ifTrue:[
otherExponent = 0 ifTrue:[^ self negated].
"/ INF or NaN
aLargeFloat isNaN ifTrue:[^ NaN].
self isFinite ifTrue:[^ aLargeFloat].
aLargeFloat sign ~~ self sign ifTrue:[^ self negated].
^ NaN
].
mantissa == 0 ifTrue:[
biasedExponent = 0 ifTrue:[^ aLargeFloat].
"/ INF or NaN
self isNaN ifTrue:[^ NaN].
^ self negated
].
otherExponent = biasedExponent ifTrue:[
m := otherMantissa - mantissa.
e := biasedExponent
] ifFalse:[
otherExponent> biasedExponent ifTrue:[
m := (otherMantissa bitShift:(otherExponent-biasedExponent)) - mantissa.
e := biasedExponent
] ifFalse:[
m := otherMantissa - (mantissa bitShift:(biasedExponent-otherExponent)).
e := otherExponent
]
].
^ self class
mantissa:m
exponent:e
precision:(self precision min:aLargeFloat precision)
"Modified: / 27-05-2019 / 16:39:06 / Claus Gittinger"
!
equalFromLargeFloat:aLargeFloat
aLargeFloat biasedExponent = biasedExponent ifTrue:[
^ aLargeFloat mantissa = mantissa
].
"assuming normalized numbers, they cannot be equal then"
^ false
"Modified: / 27-05-2019 / 16:39:09 / Claus Gittinger"
!
lessFromLargeFloat:aLargeFloat
"return true if aLargeFloat < self"
|otherExponent otherMantissa|
otherExponent := aLargeFloat biasedExponent.
otherMantissa := aLargeFloat mantissa.
biasedExponent < otherExponent ifTrue:[
"/ my exponent is < than the other number's exponent.
"/ left-shift the other mantissa
^ (otherMantissa bitShift:(otherExponent-biasedExponent)) < mantissa
].
otherExponent < biasedExponent ifTrue:[
"/ my exponent is > than the other number's exponent.
"/ left-shift my mantissa
^ otherMantissa < (mantissa bitShift:(biasedExponent-otherExponent))
].
"/ same exponents
^ otherMantissa < mantissa
"
(LargeFloat
mantissa:16r73419B6C66183FC9AFD6C972CA17C5BDD9A3E1E589CCECF3D0934A9820699D6471CB8F5C0DEF275FA663B9BEB4387344FFFA2A9CFC8F38D9D45D2249228FCA5F6BA914F5B15F16A9DA13944E435769F32175977EFD55CD5DE8C1EEEBF127F8D4F222F63109CD9C7153E9C3D436D958404340F1A6918F7853DC28F1F6BB2BEBE93274C7E8BF88AAF6846620F323E2A9745CC6B79A230B35D8623FC8BE9DFFA01E93159C01BB42C0C072B101C42F461DF587EF2DA06F67C2E574D53346018E0D58D7FE0C38F1C3EF198C5628D5890FD8BCEE3E0E8CD4ADA9788E43B2C16D9ACA7E90921D1E41E14D2291440A5682AD65DF6769B2C9927E2104A533A4038B708EC6A554F9BB81F5CD026FCAFA11EE5316A2C3BB1FCE935D91E14123ABDA667BDB9CD8FBB08D3EF0A21000B2B1B0F98812B26B600D207685F1A15C4D8FD48D87E255A983D53565A546FA4C56240FCF68A17791768C90979043CE183112C0F8EBE52EF8AEE81CF0DFD8D22D77FEE27837CFC8EE9FECD043E7169972B048697E657F3B6088C929C3E5D17666EA540491782334587DE7263DE82778ED04DDE009F050905515F4525B2BC20EC274626C10C7873E1D80639FD9B2E5B25DD58EEBD5BCE8560F05B3A066E2082F1E01BFEEC9776A25E7CCD13F0264146748BF6F09721FAB18DBACD9C797ECD5B1896B0194266DA6FA0CD8DB214BF362D7145AF5D697EA98B99896340439387B6BAD623B59E50E54310AA8FD38D3B222519E37B55078020AD751CB029AC8B067C557F1E939003F8C88DE55842A485BB736CDAFD1FC0ED330A7BCD0E1D5727393201090FBB03B12D4C8F9B7D05843BF755DF745AD0F8EFB8F33FDD06B072BD79BBABE06CDEF89E3B7B02D951D7669C95F9FB3C602DC192960B534AB7729C0233C6B348DC1505806BCEF16C8E9548BB9A6F80E9D09E6D65ECE1F3CEAE137C9D8F5BD821C26E85D80196DB83BC4EF9ECD128BC5989C9237D7917D2FD9B14A69AF41373496945F70EFE605B681DA9DB61A0CFB3C8330EEF93D7238B7BD2116BA96A7AA9F7844FC3983D09E8A6D2DBE7BBA585D8802773B1E7E9FF846091D181FD532575186BE4A02F62C04D157AF16190B98A3E32C591EE8D4E01FB55351744B829C20D30834D3C423D5D708DF4A64DF51E65F28AC2752AA170B81962E14C618C7A916CB2B68BDCA92E8A9133B4AADBBCC0A13A85BC1F925E4CD9956C0639FA8EEAA72A975F7952E5DD960F8647CCDBD44D34E0B4591B3D8A905686E45F12D2D4FE4B6DA9D026089074D7ADA26BC7A18FADC641694A549EFABA3079387A31A1269E8FB0410A31BBD2D7ED12C8E07978FE61AEED0D546CEA13961D1C294FC277B57C7FF7CA5B0CAA9F714C673848B8C91D4162752A54EBF5F17710D19C62D78892EAF86EF1222C70B1F4986BB7F51876AC419B1CA90894E88328371AFBAD15433C2741830E870700635AA19F71F69A772F920716FBAF780343937AEE25CA0C50C93E47ADBAEC1D23068AD703CEDFD597229B8F84E74B2FD99D96707097310246A9581912298E6B6BAAF1D46F0A2454CDCDC5D62A0738B60D39DB542FC72142CAC9583DC3FE6664C30E42405664696A43AD55633E3380930805D0B33ED87FC6CED153BD9AC623F926273AEF825F8E6AF3080C731BE88705D314CC4275B9A0A959AB99F8B9D312208BD64E5C9848993F2E876EB9C4C3908D8946F9831B31D2124DCBC129EA20D4742CDAA19967BBEFA5135A9D7E546E22B607D3541D8FACC46E241D22CB1120A51AA6A761918F791EDEBD0CCE46CF287C9C5E97D1470A086216EC47EC7896650926123B3C2D0BDEC68B192490FFE4B164D6202E9AC38FFC9ED01A936667A02C6BDA448CC453ECAB674048C1C4F9464683E29A056510797ABC115E99642899463FE9CD0E3553A5D5940B4475555B2B27FCD407402EF9988DBCC49B8E213951C9C8303B1538A9E34310404DBDCB8B29B22822764779F4233DDB802ACD78434888EFC63B09F9F2283A015415D25B182DF6B8A5A6CA584012BFF5D7DBDDCDD3117375293BE18D64C5CB32D9356564DD2D1765C160846BC2F42FBD191802E0B30F6F543C103C93EC9A38306C8092A179895E1CE645ED100E1FF51F12E83EC97B0F9360B5E35959C667648D1343F228C05D3AFB419960153BC780908D62DE5A7B033C0926EBA69610B7F206E9C0A157650F85D05EE12831C254AECD2E3A013B8E0A176B205979B46F60F3104E46A6E667AD4613DB62038A09A7B772DB38AC81CAEA8538B0C266D1B604C9C24F1CCD9F891DF587CA169EDFA45AB7F57E71775D20238079F17433D1BFDD7FC537BF7A6BC02C627EBF7AAD3E5030E788EECEAE1CE0FE09CD0F46941272A54010756593FFA80669955701EA66AEDD96DB6CDAACC9064039C1C3A0D4250CF75A133D5D4314FFC9D678FC1B761B0652DE9DB14CCF1C0546BDC0BA6464EEB9667CFD3E6CF44A476471F0E1801F46C9F7FDD8094C2D08A668FF57A771B64CBAB9241CCDAB6C3A2112059BB67D8044DBA7A95C04FF9AE6D0B5C3FD3F8D76D83BBF28F4D44334895F9468708432BBCAC62458B899F5E400627F83F4F331A74638976401D9D924935B5F5D897AE08E984C9DFDCF457DB4DC5DBAE3D6CC1BF7004ECABFE6326105B9A98CAF4661614052ABB206D6F6C7C51FA0CD5EC2036F367095D0DBEA54F5CE718D1E21EF2DD251D4F1FC6A70D2F8D7F7AB7E3DA847ADC478789E89AE2740270B3B16648A59B40A0A865D9E8C2DF90681F3DA7460EC03C48278C19117FCAA575FF9896A4D467950C84F8794331A44475B1BF6A426CF64BA0C03BA6C862A8855963B99D94CF8062E9F19831D135DC3E1A98D4954D6FB4EC4C2663B6EF0CFCEB628B8FA43E3FDE18B34F3C0FCB63BD1E9CCA9F71007858DFC58AA4D6775C3E7F77746D1420956B9FC21408DFA4DC6A108905D443F9BB0A3D1A30B737787DFAEF96C2F0507799DAE84BBC030B7F423FBBB85D109DFC337BDD0D403A3C6859520F17FE35A39ABF6516A390616DD86ACAF554BC40203F269665A14D1CD40D65852206BE49C7778CEA3D46BEC1A9CD6DA70C36B32E616E41ED54B71DAF6DF38CB937D022EFD61B55A81431809132ECA1B28DFC40703B7E05DD46B77C6E147A596A6CCD1B5BB3E9A24B24BF7C36D2CE8170CB2B59B8558EDBEE28F1CEF80F56B5417E6F9F4776CB8DA0DDD13275BFB8860C63FF5D1EE8E3C9DFB30EFAB30C06C805F7492D5D7D3E9AD6C08560B1F39A09848CC9C165B59D380A3F7F4A8350F9E292486DB513BD32A9D69DFE4C0D8B42D31D623F0D7757DEC1456AD7459FBD4F1370775E79B008623969FB0D4967988A0ABCBFECC86A81F6F331196ED85CD88E7452014BE1B1FDCD6E745D97441CB15030E0FB0C4DFCFABB466FF405024273BA29D896DD17E37E40F795E49B573C3AFD978EC78AB83BB1ACB6E4803C3C12AF5B08ABCA664F352511EF0CC3D9C8F5C4C3E7A420B77E52479C77CE3487F12260633FB53F2FB73615E2C75D6C3B47CE34A6A3047EB437D93C51CD27E66B03E30F78D9EE36C51851115BBE90BB94AAF075FFBA93093928AF492EE832A4869FF5D0715523933E7F9ABFF3A1EC08A39D2FBF53A43A7C4D7FFD69AA907EFFF9B72CD9E285128BF916BC9715A61CB32B2C4E11E38E1621A8ECA1CD20CB2A3AA68E73CE573E38A97B97B7759F18FAC271D8AD7690FC8550091585E555E68833AA88FB4EE95004D4760428820855EF13F4FB0475B353BD9CA3FB6C9CE8A0B4AE63EF5DA7E9B98B9FBD3B1C7EF7B45A7014EB79939921848CC9BBF71287B145FBB55D207F5F0919111542E5352F2B2D00B8A32A0F40EC65810F23C92BF164F104552D3E9CDE975A696954942B435F3840469A4D4A321DE82C4AB109AA276CD777796A1C4186A47786E6DAE4B066D0060F7560B1A5ABD545ABDF70654F01C52EB870620E2C5D34CFA167FEBDC04DF13FE24AA2901F745B8D83613DC459E227903BF97EE0E4107B6B94860B3220CE3DCD04CF73EBDDF4617AB087FA9AB015F2563F786A4AE4F19B5386D68C525802E95CDE7E4469135A566ACAB0E1D4ADB99401A7712179593EAE5BAB70A9116A4AE999304538341B51E6038515D73FABCAD826A87106B3ABD18A95DC0E69B39C26703D5592B30F4C42A87CDBF94DD4681447A7ADD39231EB5E08261AEC134D4670988D59E847883AD1C4C0182D5F87436DF4710A1044613323C2617BB7DAE197CD01D015EDEB979A5760BCD39BEB4A3168A591B8421C578D060F6061AC0E3618C25804784B0431570CF59025DAD46651C392E38A620C588E004E80D4E14A0EFF7D237E6598BE8B0644855118456CFDFA507C6C660B9EBDCCB330CADE0DB4E1229F1DD8512A5921EC1759B4B37433A0E8CAB03BF65FA6FFB7AAD203E3D7410F0CFB0235B37B6C627EC266C68D9CF912AA0BB3E873ABBB1110C7F17CFE86352315E2E172725057BA78DA74C9AD6C1E06C1CE76941CD081027BC932CF296C17BFAE8B32B3D8B77BB6544FD75BA6A0E5E90614DB60000EFF2255600CAA598B8B11F5980FD0F70524BB4982857E1BA8E39A36BB08B2F18BB903CE3708258EB80998FB768FFB7A489959F610043FF2B5DA914A5AE479DAEC2BCFF0F055D1B40F2E7BCFFF14E753E5443420825A2442A362E1277F1D14BAEF6F591873578055DB53EA469F221FDBFA6FFC8F00403B503B1BAB2E9E62ED81BB06E6AF746136BE3500EE4089ACF56898A2333B03300407E841C7F3E6A17BC30E8DB340EF6F840CF64CAA04D86A5AFAC9EBE34A7201EB45B3DE177CB2AB56408CFBF33BC5DED12EB63E3F831993C978065A649417E5625B840709CB6A14610D60485C1DA48CFC8C3E867D5785D32F4E827D0B546B0D473E49CF358CF4F4CDF02A4BDA41938DA8E1E1184DDC76202305CC360F4E9F524B2A00A327C3F18217E4D64260C972D849DDCC375EACAD4B4976929E26C7CB798E34B70F87A73981452F257C8E45826F8A60323624313DAF37177F329D3939649FA9FCAC4D076E163DCBD313C43AEB67D207B5201F7D87AA91B39D9627C0C582BAEE8145387CF3C2827B426FDAB3930A68CE97BB45961F4DA22333CDF4525D8996A51F500456F41EA1486FD22048310AB7593C8D35DFA25CD15BA4D586574FACF98BA6B17CFFBE6B65A68FD3442910093F620AF83BC37C4E8BCDBCDE3D3F7837769D7602B68A1FF08E878198EF73E2A5EA512A4A2AC404B7E3863E36F91FD4E9A54F267164D5E05DAFAEE6037AE815A50B53F2D288185FC9C4C1D01A7EA2A53EFD2EC2B44B616FFCC6A98AEC9A2A36DA7C82B1400C07B6C73A809764E266978A972C71F485562280BB71375A61FF92620DB9A0B1ABEF6956A7BA0B703DFEAF755F0BBA79D11ED191AC25150456ECFB3D9B4CDAEE3C8D010C7EF7348FC44BDF656209361E439F6033A8692941488B5EC0B446B33D777D7A2434D169FD9237EA8963C766E198325A6B52054ABCE94AD928DAF76094397EB216FA8B780A619D93819D34DF2F2AB418FC3F7F2A344EC01F972CD8942509E076BB9A33C36ECA76B6005F14839429B217CAC37D462F58A371F248E635A010CF6108B7189405443A809D56B9959112680AA581A1E75B8B17270AD4A3CFE970E45ADC0779B4E3F6506758853A74782D49BBFF9D6091E1A556AEF45DC87451BBDE54C8174A28797913E3BEB9DB4D339CAC763D074300E03B2BE2CF7B1567D2C950A6169B5AE72C157D2F8F612F3012307E57A6EB1295F601A4496DBC4075A190FCD1876530B4EF87B744191A73BACBE2A0E773E404A70E3E1CAA3221C9DA573BC5F08825939C2078F73FFD566342D23FC1A30F45235CE4F4E6C8B632B26B666F53023D77A091F96AEF17472CE0C7E67A76D71A192A6C8E55F04832A3E1425A0E11FEFA281EB969C7FC27527130A3E7C9DFE7248177829C02CCDE592FBF4EE4D10B6623DA825C64647C0F576E0A65461EBA24D460184529FE288DBB1FCB810AE02879ED11810FD104D0F6BA7419BB803DDC7785661D87CF2CF7835D74951F5C6D8BB4A07692A742C667B93E268A13AFD09471FFA5240873A27962E07E2BE074D6FF0CC0A5BA51EB047F63A4DC51867377143773015F76E0D54EDB1CF91D1D0A2AD4B926788C210708053F49E9417E6C0827735D008C4BACE7FA902E019F696D765C1A7D94F922B0A1831305354F8477583A1C503B296F1467032332BF7EF994D64B876EF9AB6F2737C2E487F9C562BB09B4BC121461A80C46A459B2E455D0CB0C0DE84EDA61C4A41760239CC53202144C25841E8BAC38A8D73A621B1F273B0093593E3D7B5B533B583AD219077510043D086275F57278E4D0C833233077E03E4893F68969A244639F5FCA56E01DB205EDE8BA5A556CFF30E60FD4099CF2223A5743F1C05D1E67D793C82E8652E92C9407A5253AEF9092A5EA2AC4700FDB80323E5EC7440C6D051E33A6EDF44511532388E28F0867E4240ADCD61E75B202A7405E2E661973335D811A9EB71CD0F6730DA8275354B8E26386CE5F996772B00C1A6401B6B44D653A20552514AAE891967ACD3C4E7947BCCE78F845B6019E7CA47672A27A6B41E9B4744926F0FBFB5BC70F7E016F5BDF634397E3123B5B01AADE031B6A478EEED481EAB1FC7BEBBC824094F9A2B5E3341C4B2316384B265D864B2471289B839DC3337378B01FE9F66EFAF9C0A3E829D9CFC3F49F9ACDFCED72701B756C5524EB739CA2227D1592CAA74E476DD7DCD0C7BE8E7F6EF8C8A6935EA50ADF975E3D81AADCCD22B4D7AE60AC515E1971B6E009751CAACD14608B64CF764CE2452B708EC63AE9EF0BE2A3D6A180B2F45353C011C0C29DBDD1D144291F1E3D0719F909B49970664B53000122ABD011C4BE7BB33FF06CD694C5CFD60BDD321F45458C186964223465E0A25007AB28F3B843EE53BB60A65409F1DE6860B7B45A49EDE835F860A4054382A1486A4BFDC0963434BA913D8D891943E3779A3F9A3BEE50844443F7863652F0C2525F654C45A2B4BA9128E98D23A291B94BC52AF419B64BA3A845F7F066F4D98B8FD3765EC94F97676B08D071475EF8C109F15107455E86D8947341B5A089A47858CBBA802BA5F8B08C68C366D7DC14EFC2ACE1E4A3A09553351B9DE051690D88D09F9C9431C73A4FF5F488F29D3D19C98312844421663A31CBC513962B75E9EEFDFA4BF03FC7C9460E3CDA09215E0D55F66A4043676463F0D680D0BBF3C81348E67064E356DE16CE74C04B001DD6D7F6B32547466835F5B2B2C2790292F37CF1E24EE4689A816DC088FA6B923CBC355D829C337663840B89BEB6E4BD95402E81D152B88C5194FD45DEE2AE52970B9205F33E21A3C60BF8FB7AE5C6AD95E1C6C5D7BC2E7C69A86DC3002939DAC5D98A46DC97AEC834F6AAFF3838F06D757FF536422C1E8DBA283D4DDC954041333980C7F73D7E651EA0501253E667F520B553DA3039A7612A7053107ACC64FA7639D74E1AC0033476483C62DD340FDEC823ADAC5979433270F7CE55E66E86297D19A3370D95C653BC9E204338D4A50AD1F77CA8A21EFFDB9A596F625C9708B0C42FAF9A39ABB5E0B003C169854F5E52C0506BA25527876CF6AC5D220C4CA4047FE5891F762C8D02331A7730C9657FD1612232AA6EFEA532531774922394A10117AF4E1C4E93C834D9B9DB36A282E33B8F9AC6CA03D6684FC185DFD3BD5540B3FE98E7ABE26DE57C65A90E0341E92AC700E7C7863E9D9BD0CFB477F1832DA9C18DFABB0D8DA2214D5FB895F42E358A27A9907B40035A292A2BD0EFBC2F82EFAAA04D5D2FF34A3C09D3A449318C7EB326BB57BE88A52AE0B75E9DFD6E504C8512188350107A7CFFB9E9F8109C9CD131CE8419B53C3836E7806B7E24910D8A8F3C13649F497A0BE2CFB711294F8DE601FBE36913529B65E78997580AC9182353452BC742DAC6FA86A5598E6F8AF6BF215A49ADDE14151E57EFC39893A73FE531DE2C038B136D0801DF66135B1EAB463795E21758D55F096318DFC14AC020E58BD7FD47CC90D9D664C32620E63A6EFFF9C6463F8CC52E1DC5D69DC403F0708B02D212FB39CE7DB1443D76CA9F962BB15F28B8C9B6D1F3F28BF9308D84B782085C4A0389D4C725F3B08188C27D3EC81FFF152F15E59E1428D3363FE71718F4B64F7A7F3BABDB87DBF6233B8D5A3A62C5F99CFEFA0FD713EE1D112E066B93280D6A0A98DF95D0E471FFEE44FB832808B23022BFCDE7709D19F2456909DFDE6D9189CFD4868BAC1AE9F4EDB6F0DA3BB8A56FB7060E1C6B86770DD1089DD41BE093AE2887C5892C3B6AAA04671E77909099B8A9CBA8E0D45305954CEC7A76D38A5BE0368ACCE3FF52121705A7996FB0475B1ED152BE5B469E10A91D8B08B4D7B365EB56F40E5381BAD0E4E6A2FA2557653C4B1F0A5C19A06965CA9BA68DD3C16748E9BBB9112C37E1B3966D42CF04E136CC29AFCB124B919CF32DE8ECBCE2E4986448D9BC544E6BA30FCFE1EB1DE332F1ED4D9D11B862B7FE4FA23330461CF5A0E3364F420B3E062C895EA9D4B9A1782B48AEEF023C4034BC1164739406488BCB27BFE44E08A9F19254934DE309637A0A4F429087DE71D30D40E99EE92F3EEA666DD000CEB6A62335A3B1806C812B0584ECD764B5A39931D1F1D35B2C73436548FE7604F666868ECA7E87DA735FEADA16E8671ABC0A0374ABC8BACF3B5818A32F5CD304E5B08F0AB5F0578EE26E6A4651C54545B215C404CE15F13387EBAD29EB52C804555E8045BCA43D0025518C614A7409D608D0B91F8D6B5C678E64AF01BE1D4EB2B765CA248AE2896EC3A2E58045CBD31EFBA4F4D3DE6FB6DD3E649245043349476367C4B422151F4C2BC9BD4CC1CFBCE0155C99115E463B603450C2622A3AC209BD082145717C028AEAAA3F40E180E1CFF740280C6CFEC53D3438253DC3F90301226769077A0E47E3F4F9EA4CEE093860593C5CA3D2A2C9C34E948DF635CDA5D743732A0AEB6F5ADD5B77EEDFB6D5A5A96AF56D383556A796BCAA826205205785332CF4223536FB56FBA32BF3AFD4A76008F433AF2BB5C443CAA751980B49463C4451A2B822F4AA03FA4FEC320B70C1DEBD80873666AF8CFED6BFD622F5C99D9584EFAAA2AEFCBD1B77DEBD977BEE07ED760F722854F329A83C79A2D7474CD8A78099892BE889C437D1A2E1382987D137E8D5A51256A2D561B668F6295687020C095B8FAF3ED2B61703F89FAE4F3F8FAB92B1A8EC58D0ECAFC3517E4797FCDF1241397B49C23DE6EB1BFC42A150DAFF4BB43C936D8ECF25E2B9F7F646374EC2A6DDBF5C55EDC5055EB98E0F2BC7D9240111492DD2895D2367EEFEF6EBC4F217E564706103F257C3CBCC52292081530218D82338ADB0110641504E2086A07F3C74B03961ADC5FE94B0299FAE17F6F09FEE85F7D67B0B066088AF8A41E40CC79986B01DEE4F73AF386EEB0554A1FF6478EC0447BA64895BAA0F238AF9CB8C2EE5F7C3294F4FC5FC4B2E6808B29DCA7C768CA37949B4E9B42A31F1754175801DD92D205A35E77B5C6DF26B15E20B104108DEE7F5742CEBE1D886E68FFF894F4F77DB167DABDD5679018679036CB5FC91D764157DE04EE9EAF4F11F529D96FEAA486DBBE6850F1DF1504A8D65B20441088DDA0C9EE3F851FB134B9AD567411053D55BB50D964727BF14B7F540DAE69F95FC24BCE0769408516C1861B95CC7DB137AFE13715D2DDF72C240F04E607ADCFEBDC52612A12A954B5DD436660BC49C74E521B55B8FB62E99EA6F27E2AEDBA37DAECA2A9B98099004C278759AFF14D9C6BB7D30CC56E0E7DD1F458A2D64748657BACC59A1DED3FEE9CA308884DF5A69F5EF738948DCAAE04EDE0C7811813B92AF605CB631291998A54C00C1B880889AFA90D15DA0960C859AA1C0E050AF5C6A021685D95BCAF85AD37FB7DD1CECAB684BC3DB11DFA815B3E5760402A12EA512AC1E6010AB87C98D23E5D660454356AFBCD8ABE65E023AE1777D5AA187FA7B3E4A7D7480CF3472E876783BE57BA7CC1167A323B444CC9346619AB8B3DACDA8AD3A3054FECDFA98C338A4219EF79D3A7284987C6E664964259F7C960FBDB08F5EC1DAB2C0CBAD93DFB5D2098C2CF2009CCC213F640A506320A53253EFFCC780D881B1DF427C84E90F6460BD89708A7E4075F47F51725214BC4931E3D8940BB32B9E73D1D846CF142BAABA703BC2FEE6718478C2FBF334EA902677C6345F90BA9AD3BBCA778BB54C0B5CA4121DA3B6357771D918154E78B5E3FA921933C26F596B96660EFE988C64EE1672C22F3DC0A88E909EDEF10D5F31E544C96F61C31B483AD3942DD11903613BB496ED7490E9C95E6ED67C3B0CD88D18EF3C6913F722C10E6846DF1162D87A226C6F91835E6E215B1A1167A464CDBF9565382787110CFFE5665E80CF19EC907D0800CC86EE4622074AE171E7B717B440B26F832997960D96695C92D5226084EFA6E0ABCCB31424C69107798909B4CFFBACE608920ECAB318FE65252771C07B2CAB5846B5108D9FE8585391ECF43C6656425AA83EEC0A046A527364267E1DC57F4881E494304948479BB63EE2EFDDF5E9AD9487B454BED7ABEAAAEC16714F4EAF6EFDBB836B32F8DC9D7F81FFAAFF251BD41AAED70BF7313035E5DEB8CCE4BEB9A3AF9C7196A638474313D3FB7CA9635434A15AC344B51486FF11C8C857AC2746D57BF6CD722DB7838EAA5048D786679866A4C4873EEDA01B6C3DBC5E8D9971385F64B4FF675971F37399BAC3D3A78E06051F4A46BA0733D22C4B88BF1331FFDAF6DA706827F0B3E25FDD5447808CF498D6D19E20E8118ABBE0C753B42630C71E1D95DA2A2FAB6191302E86BA53F56B472723A8451A16930243ADA76A2309DA4AB4D257451B237A1407D2B1555BE13DD8519F3DCF4101BE161EE3A4C7820DA60EF2664B4C21B7F83BD5A2C9C73E7BDC5CDA8F7754853200B603C97D0950AEFC147123BAA6139C62EDC56263314BA1640DABE28F7D1AA86C38BC69823E242383B72C1C97F12D78AA6638BCB5E4296E19F2F68D665B36B988718347445F66563FEAFE88639BF7F53C70B3A754C5AA1095660EE40A29D2154031489A207B83976D0AA0117E122A4A879F05D2BF2A3C8629FB845F5C14722954539324F325321B9C46563D5FA5927B9BB0A00921602E77AC6152AA026C421E8B7233077321ABF69FC176E53DB210D802A9DC588F2CAB253BC78041EF75CF0D1479FE381D360BAAA4DCFC1F89F2709FAFAB152141F07617B743463B4CFA112D4E250C0AC07454FBD796C698E042BC3FFD355662C16F55BB5EE265C7DCB016D2F377AF03BB50196B40111AFA8396D20F12136F45B758697303540D6DEEE5A81E0C88502BDE805DE075C73BA21E6939D3FF4957D3C76912F931C84D2E06F8547789A6CD58F8A901AAD3207CCD1143DF7BE3193339A7903DD4178762D2D50DFE3BB57926A1BBD6B7E64F2DE2EA014EB272FAA8B5A911DE3C5E885A5E1568016799641FE5EFF7D592FEDEA1D94B0BEE49F4757556423BBBC1863AAB3085B4BBCF8206A07B56543BF073F0F6873AFBA77DC152EB147EBBD9A46EE0F728B7BD93FD7748549064070D09F05BC50E0CE5927B32959C0AD2DB673CC8B64CBEE624958047A752CAD3D1116777D90AD51276D59DF5944A41FADF3DD4A97C569FB11184F72F0AFC07505EA1BF465F03769CC75841327DD6864C091A2E2C8415EE6B7DADFB1BF8E2DC2C25A019A54084FE2BF01CF2935C548DAF0C4F8A31A5B14A89F37937EC287F3035C46D92DF48039489D3B1293E823417AA8687D2BBE41D14EAAEE2D0742D6F87C534130950F81A04A8A3B42B3B26266B30A7C0276F4739110B9D88FAC9DBC5FE85122E0BFD74653F099F000887373550FC8138F1B6D1369BADAA8861BE8958060BCF2C65788B4BB68AB11DEFBBFC543F2608F0A16D82FD97BD55B06BDE0E17F05C1009607A2734A396BB8CBD718356B3EFBEB1F1586D1606AB3B2701E4B77800C33673C54CF9DCAFE215DFABD53B13879BA663DFB443A717C610671A6F2D65A319BAA06D472472C6F71520888651E33DDB9A72242E23C81933E6CBF951C8FD61942FCA23D7E464D24DB365874AAD627A8CE684FF0B73772A542047C5A8DB9B9B077075707C602384DA8A035092877A27F16774BCF4533B8423CDC7EDDBBE7A27E926031871BD2293CD46109CC9C0CC7E18F06F802BE20FAA35A170D547B864AC931DAE50EA4FDB0C24BFBE2B3E720A66EB5F6EFF5009D69B353FBA489F18835ECC43E3FC2863103513D8986EAC34B31E8BE31CC2BAA2962905988BC0E20BB1D9BF98B82A66544B0FF175B296356BA17217A5D91EC5E38839BB7A3FB575F71290E11D9E42C28B7C63A1E3491C7651D3ECC52539BA21D824FBA6A22A548B91335CA607A630A16F234330F4FF75061B6C9FE4C2E131F4065A0E9BC8BF4967CA4C0238D3CE38291EABC4085198EDE4426AE3FEF38A3A2C70448898C800E726A9BE870263935B6C71998E83801AFA13FA2DDC9760155EF0F960C206E495B78B1411361B98992D7CCAB9623BCF6FCBFA1A5ABB8CAEAB0B25DFC2CF9CE04A0FADC24CFE1EEFB752B287B1DA6BD820C0AEB2CCD414FE618547D3DFDD58E53E6DC4A6E7A1955BD6E451B52616DB150A75EF13808C3BF9D9069FF6DBC76290AE755E97F2B7F3465719495AED6CCEBDBB2B4030010AB1BD9F74C4A216504CDDE4C97B2349822E25C25DE270BBDEF0DEB901F25C8914FBD5919CADCE790537C53749FEE474B6D099CE7AD3B36F748D336892B11AD2F4A9B9173126E805B23D6132D75E9FD4FF9E3913F74FB4C88F8133F9B20E20E239D083F90EA9DF7B599F14DBBF454A5F3A49BEC62149E50772126DBD038D5E6E52AFCF5E11313E33FEBE953500ECB77FBAA17ED2E9F1348A282F7671BC4D285C4099D46DC0CA702A2169102479EB4D291C25C47D997DBBF76DFE7C5C20DD9A4010221579CAC03E837AD9187A0D46D9BF4BF41D2FEE16F49F6F64F428817567A6311F6334A43BE921CD833FE854F901CDBFAD5A5D6908508F6E46C3F65B436A8AD3FF8931390C5BAD82CD274BBB1085064FA1C1F6CDD0EBFCC3E46AE16006A08A48F6BA27794C89B68350A8409F81402237871674695A0512D33BE49A2344B0B2A1B7833775F29E501B88DF27F4ABB2AAF39D114B158DEF012185B4793B3523E839CB24DC605A0F28F21C4C9195722AEA7EE5EADBC41A18C6295E5A3D18F357A3EBC2C5DA8770EADF723DB6166654EFCD0357BF892ED0CA10F8845F6BF8E5EA04AABA6C721187C9E360AFDB868571F9AD5EEB6E50C154EC3399F5CE2E9FF639F08785E39EE7FE92BFCA0E4D4FCEDD46F4CA5FEFD313FAF02DFDE5414E70797553A8CAB1A80FD6572C22C5F133B4FBC172F1E9721BBE70D8667AD968F31D62DBD4B8AC2A49FDA622B1E74B7EA8188093AEDE307F3FEF35507D8D72738152B26C859DD6B0D27A88929AE340471710718D635787E5A67A53AB1C6463E9A8BBA220BDA69D59F25F04A2D670BBBD95B99BB10B393043ED5BF97344E71D31086C75CC3F82F6AE373440FBB56EFFC39E07D9423F003F76BF36F8145A66F4C9FCF79CFDF5930019B26D413BC6ECA59371ED9DFEC86D92C7C364327AC934FABE4A73B361340B423729B2FE5ED24CB5F8B97B55912944FB5BF5B8308FCA7F3077DC61CDD3BDBD603AC14C837F91CFD50F95EE0F25757CB8CCC49F72897A9B90C1B93137D79EA75813440C6591F909B3796EFDDB1AC209675A7028F31404B3C4D57A23BA3C0B71C19DFBFF189083C0CF0ED48EE89DF5BA1F9D9BA39B6C813D4B6CF94835C7B17D9B7031DDF921E9FA2D8CA9D91BED4C0202805993D41DA0102650994D6D818DF2A56E983E903F29BF9423F1190CE0B181808F05A2D2975AB73D49A61A8F7757AFEBD48948766C5EEB176B917342598A5EF51AE3BA1BBB908903A308B6E138249C7C68E788D3AE44A07589D3FE4AA09F1B2166698E4FD1F213DDBE35D38306A5A72A6CE416DBB1888CD0B0C58C3B8878EF04E1B12E0969A7EB01000D51AFF1B962722EC3D0B976ECFBE2E885006622FD6D4A6F28C4DC6D69FDC0B1BA28B285DC1E3D6338F33FC41881E378D9019A894CC6F2AA13D65D4028C988E5D8E76C5A3F390FE8C943043AF1CF59238DE9D24617EA2512A018DDB523428049D63E524E9CEF36D5E57A8F94DB5214C919E70078D8AAA157CB62C571DDB73686480329A20B4A673C9D955AB7A61F376D143316B99221B8DC06F20A8D721508EB2904E45BC69B7D0C93B9923B66B0BD5C785A873901BC1BBDB5EB487381905427A99A9EEDC5627079CCAD1C0F12BE9B73B953A915D82E6962F62C8955203E3CF5B14BD6581716C61ADB4082F876B8B9BD9C8BFF942F0D9CACD9EF57A1E71F6AF24068CCA3D0A36C77AB63A284D7E80231B7E10FEB2DBD37D1B2823767F1D563093A20092AB1E8FF9697CA7564A6F3189B2FC23AF4580EF4673625217BE44668458F4FD0B021D54C6B577A1E55B2B2CABAD55B138536199E6582BF6705CDD7E424E702553E0F72DD3E3EC5D358F75F24CBADF1425BFAEEC8932226E36284E26AAD2A7086B586D19535CC8F8E7D22C2B9FAE71EFB1D6F3795F09C6FAFA3CAFA2D8E4A8621DF65165081C6A1C1544DF2E4AC9629EB9AF15EF28286F49CA95C56150657A286FAAA5CCE15BAD2869D5D0491D36B411F0A38A8D82AF231897EAC0E1B3014C2AF9D1B999F0E49E94E6884AF0030D5CF6656A9B4E7E5CABB602EB4360A1A46E7381EC5F0DE56704FCD15E873C12E67F2B77B149D37031CFEC568939B9FB299D0F1981E6341284F742400E1A936C3558FD9643D7B22121EB06484B92522E0486BCDECBFD52E1FC035413F4449A9FDF339396F80C25D0B5E6874CD8A09335EEB1C826A61DA4FF9E7F13E112B12FE82473B461F41CA8F32E35DCABBD3B5FD164820D271C891500CB8603A6BA0DF34D28422A8CE143D715B5CAECA85CA2A705E517601D577020E98893BB108B656411E14326D917D76D9831046EE8C3CC0C829DA03F3BBD6A5EF2DD66822EA76B018E00E83A8C3298901FE8972AA9850E79E62163E7CCFDFA1DC68114CD15C0F1B2CACFA35895FA2568075D8336DD1465838018D55F64148FDA6517BE0D9C3E9803F940869D7AD84F1B27DF8AE6B718C9E66ABD760A17B54DE2BEF5A25DA993A7AADFA10BD5ED7D5FE7806D8E6F7FF5CFFF226238884A87B7851E2EBE3C454A8D46342BE1CADEA0A3B05E5C07046DF6F7261ED831D673C9BA941E3BD6AC47FA7F05B158291B39C4B1DC782D98738A4D03AF3E4284CCDF904B5A32CFC0381E54F46D6D4E860EDFF1479985D3B2A66843F1BB07CF6F646AC7675E7E2A0D9961562AE99F9251AD66937F18B669871524B72473FA5368770F2AD811485AABADADCD205CF80B526543A82540C3E7570105C49DD130C9B8BB7C4F10949430F1E19FDC957D8205A989249CE3201BC916959DE01D2C27523C64C0886D20FC5A0E97C141DD1A44A76BF8D2FC92AD25C916FD91322610D59F29BFAF8DC8144A984EBA131DF584F149069E5178548631EAE2F4C6643AFB9E21DD0E5E6DF44937CA667EC916037EE358F7D0FD9787D1CA87EA3DB17C883AEA9812BBE7CEE8FD76A6AE14DEDFC608F45FA191701716AEC26432B9C260B3F897275E1BC997D9726AAA24F5337E8BD6864618C02BDAC3A33A90F821F7D360759418D03386697655CD9958BF4173929C0D2A81B656869B374C65703445B0F891BA6446A62D902B4F248FA3A4F3B9155A1F46CD45AB32B3F6FED88B41202EF948CF8B28DB9050E7238519A1A42654E1A9C700CBAA49311DCBD44E11FC23C81615871C7973E083F4BB206C033030813E467A0B7CB309081F32DD1C83E9E078E3A5CF06C7B5253A08E38F9B94B10F79C95BB64A9402BDF21EAAF8624976170B9D0422B55C6FEDA5FC0193F2E94B470035C2C9EC95BB306922FE9ABADFBC3F87A5DB49FFA4384ABAC6530D47CAADA896FED3FBB91402810EE018E62BA1A831986CDE59394BA6BE9EF6A1414B068A7772D5C425FAE3233BB5478FB41505ECA49672E94F25E59E8D3CE16DB2C835D2A8FA3735AA4BE4C018AD1FD63CF161ECD37E0870152CEFA3FD19D81A1E70E86706BAD04F35338DF2C3135B8AA8EE7586DDB11CCABB1CCFAAAD5E89D7B5119A1CEECE29ADEEF89B5B5BE498E6A22B1C22C1B8CF3F8CAC0CE7DFB8A675CE7B529E2BDDDD11632CC0ED6ACEFB82198B64B36B05CE0AD7C2EF3C501C6F2C3C2E41068543F14ACD6577F850EC22ADCFFDB8CAB9130E5A107263798B7B62BF1C1DE66530FB999289E26521F4887EF6A6D0DF560F7371E9E49C24CF7A3001B24856F4259A1D0774C5D202A2EC92F46661FC017B7DC0F8577BC1F417FD8058F78639BAB4DB52E5A9378202FB5748F258D8E0F0C3602E9038A28DABEFB252917C184B9B451B417C30F1639142387886C38799D232BFD1838763E28E996FC1A60319117E2671E50447B280D258C3521CE7C1E0A581D8B346CA2B0886994B8824F044AD1075FDE7BD90E772794BD687C720E7DD52FADC89B322691AB6ECDE3C4B5E57727B9B11BC655D45C8CE945736F0AC132627209BB8BE5CC895E792334CD2B976BAC912FC021203DEE7DDF9922E42E2823BBEF92B1D35BA88CD67558A6E28D348FAE24F698A35FA0FFC382463994D8C74767B93F24DD318C54DE01F7FFAC68F4BD0F6654F75467AA6E737A794AE3EE3FF5E0F1BF328FCAED275CF6AA05AF17C5D7FF0EDA5BB00634416A693C963832714EB4A6DF1277ECCA23C8E988114F31EA166417188BEE48815DE3CD19C9702611A3781F00DBC59D3C9F14467A0F1F24C2D4F3EF8E00F54D4E347CC9D918C392D72075DEF691EEEEE1792A3B047C159D986890E02B8213604FCB558A1EC19C250AB4AF887972B6034DFDD4D80FA97B57B12F5332A19AB7ABBBE245DFDE7B349FBF36BABA0B1E016D5202EB1EF125794A668E6DFDD3DC04D952D5473EC4B7000B584AF71426E1C6CB264DE0DF1E75873A315ECCF94264F56534A567CF15A2A38554A83BAD842ACC735901E15B75B51E851FA6A4B7992084F7790DDD3DEEDB4818DF80C6CEC1DCBAA3AD77E5ED336F5996E881F07B4BD68FD5D027F6A7D62D0D24E7D91796D15590096855F9DD7F3B08278A56416625BF14BF149105CFCD40244B114742F7B24CC15A50423DA48B72B33939F8C39E0B43D566FAE15EE39D1A45BCEE69146ED442F45AE76E4CF0D59A6D167A7646FB8FFE57DAFD0AFBB0DF34F6D8C0D8385F6EAAFBFBB90857D2D231E3131F298162FAAD423A830E2790D15314A529618D3D84BBF3CB35E461D1978053A81247BA5CDBD1A06DBA16E2540E63D83880A2B57D1696A45B95C78BB876688560E0F1E97D9DAF88C25B95808B0E616D605B22AEB7568DEB14B83BB0180D8C4A2DE642A63917A5EE6E08851E732AB538E1A738EC66A271F7188F349743EF6DCA9F2271218C1A08E2C0988BB5AB72DCA7D795B941C4BF1D61F6EB6155FFDC6113900F6AEFFC03A0E800169F8BE687ACCB31510E44172A67EE5A682322429244DAD69BA2920522C54661B59996281F6C6D574CA65CB36623F1AFE834ADDC957519708AE2EEA8D44E761A3320C5EDACF594C122E6E494AB97E964FF4279D23342030DE99BC3E7BA415341855AD09932C00C28F20CA1E2BB9DBCFA107BEE3A6BB7FA374530D673A03FAC6A231CC752526FFFF25282CA8CF439CE627D73655B54702215B0B6190E7F78026A831FD10B79C2712600902055B8D04724E7243EE7DC6FAC0B6E37B7F5BF0FD39C7AFEFAA6C23D2E0FB91D0C92FE49D3421F72E4658CA068AAF60782E4CE6315616E54E899810DBDEBBE970466E99D59B5D7609AB90F5088177964B899F60775149147650D7A4A2D100A8169C3F99955DA760E3414D6424A7BA3ADEF7EA56FE080B8C193840D1C870B943B268046D2DFFDB6F59AB9F9A091B77DC9C645F0B1BD4DEC4044460D964A593F2E369E12CB267E7F6660EE7FD8039014F6376D2B5AF820AD34541E4FA3F31BDA8056ADDF596D67F10CC46FA48DE013079620CEEB6A030A36F23CF845081C00C7D8E40FE13ED870C1A0D39D4946621F3F38F9528732891BB9D2D8ECB2B605FD90AACECBB14135AA83DC04BF76B04183A8B98DDB8D70E48A2C43F7B8C1D34CB8F28C8B473B804A6BF1BD0019A3231A7DA12D4E1541EB582562D943B2C48997D95EB37EF817C8AC336421C1263AA45BB95E18ADA3225B63FEE678963B94C228E283C1F367ACAF4DBF4FDA56515C22DA61D5E9DE620F1B9BC0B2B1F0F94EB7EEF60D1BB3F1BEAB79E638004FBDF21FF77115ECE7EA0DEC68944FCE74A7F7D87B12C5D830F51512102CEEBE336DAD9C730C22A7504E7683CC2A3BAD9F45AC759EAD47A8AF00A7D45222EE6B6713F7B0A6873A4A05ED7F6870B37EC87273A98D9D5332FFBCEE8EEFF5679FA36D2565BA97EA4D85E5692925415CE5C8F230593ED5BF37B79F9FE3482EA411CF272BA3783853576DB6525EEA16951A600C40E972C0C1037023938F8DDC972BE280FE494E0198BA0AB5C779D8147E9FE858B64AC52C6D0C54B9356EA97099CEDDDA0155FEF930BCC7B194C87ACBFBDEE57CBD23379DB73259C8F0106EEE62237510A790C1807CC1A0C6A618A632CCAC931CE696926BA9FD81C52EFDBCC4CB9D4FAC1D607837A52E2F38096473558F5F693A80B54111F611D88A7C754826218F86CB04D2BF3BF207BEDC415AF2A78F5706E42540B134B7353AD08F65A20C498547A3853145045429A06EC7AC65B68E579166020C059612EA973A992A934E6DE672C18B20BC0A49D7A001C1F1A53967A4B264B3B8CB16E42D072317047942DD7BBEB64BD45A2A64E7EF9F6D9CD0814D86A635F80736D4E10C12260C9B9E842666802A5149BDF7E607719A20008F08684EA85529EC640F075CE927E84F2FFA50896E8713BED7835D0C5DCC50D7920447306B827BF654B1FD56BC0B55767971C0F65DDF6E230367FCCFC1DC642162E958B397AC19B93ADD3A87132EB41B5F4713BFB2F076D471E00DB2A877F800AEB27AC9D8693759C27567AE240A856B5A76585CED3019BF8D6E94AC75395E56F27AE1C89C655DF677CED7AA535F6E7C8667221CE040E03CF4BACDD747F83D7E8230C4F0FEF1B726AF300374B00A3C8F8B12984289EC2E68CC007FC8CF6803688315285D80BC4F745E62D3B81D3578D7E55B71696D9F90DA19039BE662A5D7ACC0779BFC1B0EA561A79BBBD90A8BA8FF3059440259EB781C75471E653AA3987E1D75FB80EDEC67911563C37A853CBEF039071538D7ED74F643F4B4268E71BA37456D98041F0557268000CB82192FD046CE4316941A5FF7444A5E58AF67B2F088AC113AC66B5BE09A7E7D2387624BEA28CC77F30003B1A24CD27B44A7E8C8031BC579A83CDC485AAEACF71DEB536ADC388C03F4B443D6828CB9D26E5C1ECDA81F6B505F6791A594522EB9A6CE457846965CD8CBA309CE1F45A229CCAFFB67D2B0AAA948404B18703E1ED8E56E9B61102667ED53FDAD4CB75566D874E8AD7B2A7B1D5B701551DB717589CA0A16749E9674214F84BA9E2CFEBCA2570F5B558B7239EC22B6C5763C4E074A8F46E00A3341700C79538F6E2695E1610E2452DE07F9F6D49CB34167B069675CA30B92DB6C3C576FCED30245D271CF6DDA75F2A69B5D1BECC4AB1607B6779B08B4A5C8E0355C93FB28E9980B4EC5730CBE152CAFB5A098156D616E9F4A051E1E84FCA4794D0B85E760F6E146C1383CBA715BA3888BAF0FB542AAA54165D9CF9D0A40E22185962C533A4B0617DD2C4801C790EF46BD9F739E36D83EB1501566DD7467AB23CA0B9A031B6AD48611084166393BAB44071EC74CE3F6124B3895210178FEA852D499570D024B7AA28C319B3835F208F83AC1951748544DAF7E2D801F5878B323AE3EECFBCBCDAF73370959E17F0C8A728D8AC900C6835B72F524652F558B95A19226618711A39925B33FA2E23ABFF9B691B0BCACFE86B75613084A1A96CE6D8927C9919242DEDEA970DD74595D709C3FA504CF8A3A8BF6A2594CC261A68C06CA084480EC20D9771C273A4F8F1949031AFFAB22FBE12818ADDF8EBB57F452D710D8D8DDD441193ADFB9C6E9298617D227F7235AB6FB80FC74C436E63AD715195B68B716C058E0F7F59F2AFB4F7E0B195D49895A2E0D311EB83D40E199EFC8C895B5A439C9C5A019F1ED1F37E1DA9C3CCE7611B7DDACA5BCCC2413B51DF94FC251E7AD3D9A74696142B7889BB1F14D10006A8B291E36483856AF8A80252FF1B5BED5479BC8AA7A658AD60D7F4643EC651232AFEC7A7CE94259EC513A1CEE9538BE7E1280867D8BEB61B34DB8930475ED47F39B9638906BECDB2E82553A048AFF1DEAA5E4D955D6D0D40FEDCC9FFF580842B00FB823B82F15E57409011610814AF2BF4CF69D5527F99AC1435CA28EFB79D1A1039396E45B46EB507690D889A42F165121CFB9457BAA175D7DA853DF6032596279BB92DAAD07E97241A514FBE1382756727AA99C648C77E4089231B3EA36CD8C469BD35DB4914466408CE9F21BDE34EC23E6768F36572370CDE29F86740BD45B9233703732986ABA686156610B1D539E1A28FC42F894A2075925481DC8971000C53C4A7DECB79FA27DB85820AF9D27FC50BEA10E7261B828567B325872B961CA940BC8A9577718B17846137385F5451BB151E06FBED139A5AEDC94A6E39E6AEC4554C10473DCA75FE5DACB31FA75D750AF5D316798120DF7C122ED357FD51F6956BE7FE14323B1AC5F993C98C2D67002B472B393A73CFF29673B4A8507E145A4F25276B71E4EE252D76FFE428580F03FB4E8C6FCD9EE0D59C6B2A1D0A033EFC19300EDA5E86A34666A25A3BBC5CE09C11A15008BBC402620EE69FD6B6185BB3923CDEFA79B5EE839BD3A303C89F69078BF9B375E9B29585F7E9E93B28DE53D066335DE12E4F9549FEF6212110F88B5D97544090A7F2A673EA22AC6DBDACA589DC00916780838790EE91FBCE17A2D25649E39E15FE5F31FFFDF75B6C477EE133DB575146E610777331179A9F65D7844BEBE30286C3550DE93857A9E45D57789B92307197E361DF3F8C532856E24B2EDFFDE552E78CF80FD5FE0C431D9BF22EB531137C390A374742E9CC701986FFAA29CB291D03F631F813C6A68176FF315FFD80CFF0C399D1B441FEC8950FF3A11BDEE0BE28B7C2367FB4CC768B4BDC74ACFB23441B7F0680A292A73B8DABF69733EC9BD9BE7DF25B7E55BAECE406467A55E3F57533D1BEE093CE4717E4D6094DA4190A2AC2C19B45F7FFB081A61BEFCCEBF0B22C0BC50D42C92D87A9B1EDA17A943AE811DDEFA4E74EB1A21DE73E90A75B53F1BFE8A4B1F2BAC73F60DF799A9265D6AFE35EB8E12C34DC5FDFA0C441FD9AAB610E57C1815DDE15A9493AB76160C29579D69A72D85FC3DA3FA1E48A60E6B33035BE27C73C190B000EC953C56DD9BD173E3939AC84ED17F1264B7E25AF5BDB42B25926F3D196197A6225E924A32B282E7DC2CA89B3774774D9DC4F2A4EE138D1E1281FACCAB63DA5BB8C034D0B96FC7F4CD640303EB7963DA464449A7489E2672EF64359C40FF1A6FA897CE72CFEA37DB0B178E0675CE034460269E9CEA69D2660C41125AC19DFC76CA1E607B5130782A860A4662E0D3748A2AA02B9210FCC91EB74FD55574193B9F270C52F6B5360BBC2AE48DC0631972938ADC0580B2612129E61E00FF7CB325CFE4C3D704FB93DAD7F21CD40841E01CCFF9D26255286479E6E98E93944AE002240D4D33635B7234ACC13AA2C5DDC30676328D16774DA5DFF2A0BE49F3B1E4BA69610E1BD7ED1E1A49E91B06F7063A7D349F2F76A8363DAE51BC3FA1BE9AAADD0BEE83307333FCE09033FFE7FFEA542005AD7229C0EBB1BE5557CCAA19CA548640CCC350C2806B8C6924FF9FA398A5BC7C66396635B7D89165ECCD5238271574F0C9E0BFFC623B6B7B67D53AEB934037F08C1B38345062B48ACE53A97D55E50E9D0A617559477629AE09F510C20F11E0932D1989F2C7E06394988042CD7EA01C0F7749A509C3C370741677CCEAFC6EDE68814BE4E0301AF3C8383CAB65DA3DC17E6794ABC4EA67DD481EAC0D320375D2087B18417078A9DA184FA960E6E38A6FE6EFB11A4516EF33EF2A5260F5EF2CBEB171AF902F6648560ACF32A038F03C4D6D1DE235630B606614E0A1320F35A1D30CCE6EAF7AAA21CAD4FA5FA381CC7CE290DE695EC38B1F8EA9240CDA10F4EB1BCFCAF7F268626718D905896104D16415758E3B33085F02E20CEF9DAF1DB697473E6AA56C3E93683C287F00FE6A4806F20554547611CD54CDF96AF702565E4856BC7923FF9036C836CC07876793F707BF51847BFDD22D46E5AD5F7854E37B0994F7981150468008A078C25173BF35ACFE5D89BF11657C15FCA03D53C56CF35BB49B9FACD39AD4012E06E9EA9C02F5F5D9B215BC29A1F66001F2093B3C2180C0F5A44BB8FC1E0D96C5F6C0B10BFDCB7115F19ED233B5C4828D9294F6FEA1A507237C5B153198E3139A9CD0F6B7851A366C1BBC7C070D1A449803D0418A0D86752A1FD25D79A6FF0B2D6A7CEC6E92143322B64FF442E5F1B49FEB2B257EA406BD06AC33AAD89ACF4DA8A76E3B29D1D9D16B9F571524FB7CCE608170B07B2C641B3DD17B6FE3104840D8E6057A4E6E4F0503593880E284BDB02C808681B347F91EC14AE075768F917AEBB5BBFED5AEF7F3B2027447C831F0D839C6B7598E9C38E951C95C90588F31C18807B07D3298D66549EFA3E555A89CC1558F0EEFC065211834B11CDBB9F8894AF15BCC041190F3992819BE74BD02CA9C6A4E5F40E3DF7D74B4A3CEE3FF86538F754A24B962E368AE492437419E37944B422280048AEE750E70311708426001F9288D0BD70C36EF2B14A28C6FA701E6410A7C20D5FDD65ED1B18EE26A5E2C3317E0A47D1B4FC47006B7449C58510D7EBAEF16733D501AB86645BCBEA5BB2D966519503CAFEF9C1E40F91BBF1B39F78AE0FCA8D73CF78E94764F759122B4DD04C5FE9DA3D6E049D76D67145F60D6D845ACA2EFC8D25166C69D6C6CDA61D8020D3C2E66A6BD31EAC0F51212566705D66FBB3116AE6AE19B5247FF41D33D3027EB29B86E3A201951BFC3E61D501BF6C4FCE727E20FCF8A378060961DCD18587E566A315633A52580A3556129CC801F07FE7AF06E5B2FD0D4894F2F316BFF0408F48A255C08CCB42C7D569433E0029112D8551338522EB6AA5AE970C73E258F31D79CEDA8706121C2AA7264F57C026F624EF6A5C983195017793D7E71B4C7A9A714CE863E5D766F0C81AB3446A4CAC3D534958B5208F84B2F8B683B472043A217942DA2989B89F54BD11B5967CE7014A8943BA20D7796B6BF1CD18660978ADB50B563AB9472735045BCC477E015F85C0230A4635C974A58BEEA799B82518575AED6B20EA35D0F56B55BFFB908E099C37B037EF4732963B861DFA2DFB83CAC54C744777A450C13B65F14EDBD3AA54D01857C68CB8F01EBF0EAE09382CD42E4E4040031156A873C341DB204D24294957673E05762463D87E293FFBC35E624FA1E0347DFE2C1C4F2EC0C8E975FB1347794E59E6CF2DC3E7B25D6A62D5FA6C53854684241B5DBF6EDCC10833ADBEFAC1276B0887D79C4CF0097BAE990A7698C8AA4DE4DFC6F00574E3811D8F358A34E8DE83EC474C6E801DA61FA5DA180FEFA7739FB3408DFDBE71FEC39FD13E002878FDBC60200FB5EA3AFEDDD58CF4DFBDC7B35C4B5FF527D5466E7CDD6D81C8A72B7C628D5480832616A87877205C6C24A82FE6D7580C9F52DE72676035A6675BC20C04381E100C3347871A70CA2938B7D027B8D4A7614985A6964A99D631EF0228E89FCEBE0188108BC6D6DA67CED038E8F658009F185E5F63D0F8AE7F15B34A93858F03485DDE2EA8D31A339F215E830CDB136CD6DE3DCE726C31AFDEBDD7BB6D0BDF6F858E8AF0724C252C06639346C7999E12301573233C361CF4E590EB947AF8AC195D79C0AE8F2DF3A4CA806DBD18FD33277FFA920111E42D1D3F5EE0568306D0D7A7DB01D49C8F723EAB74A2E58D0475F7B110B24E0831914A2DD5E0B521A015368B86294995B9EE9CA772817C5839DF23B16042D04336B0168101CB4F3F9B36F8CC99AD74A4ED5114DA481DE51720C7E35A1DE51AE125C4BBC8A13EBB98A28306C5D1B0D3DFDF1A7696C0DCF5D4A9FB556A9C8EC618E74224DF6AF5C36AA1B9E4429923091735AE68D19794C1154252CF06C2A437C5BBB54DB7CCFEA3BAD44B49054B87539AC005CFDAFB762BC74DAB1CAA7244AAF920B6C6BB42860DC7CA68F590C37C2A678FC65B40496DDCDA61CB49DD636DC338509028E6DA60A530C3E24EEE8F09D34A517CA6E15522F8A885E68888C4312E0E7B0E17046AF2527432882CB30B6DD537550586A0B168164C3B8F241D7333BC6FF29E235AAC7C505EC1DEAE24C3823BA2BF07B8BE5CD67730F4FC98443E32FE6B205850953BA59231FBC9408271DB3CF47857196FEDD3336A975FD094E1C6D2D51ABE5F0E5783807E01B1D32F004CAB4BEBEEF2EA35D3FB772452EC01E6C5BD8A684A17B33BA00D47BB36949F13EC822CCFCE167CF99848ABE1760187D3838BFFEC835901ECDFC905E8EC3427FE9A24513E0BCD2560FDB7C32412CD97EF65A667329A50B0011A2CF0AB5FAD5E2679B28231999D2E29F57197B6D32FC74DEBAD09E365B3A2CE78A9E3A9BEBF9044C29D5DE4E727D0190E83208AB1D9ADAAE0815D2194FDC08EB39788BB0A8E7EA5F778C5391FD368B7CC0AF554704025CDD59764D7622E4C8356AE477E0088488A5C44D1B5075662BB1F85A2684B49808A3099F457313CD03344FBF3B92861A22CC52C5073BB13A12D4E0740C60BB941B738E977EABEBF94C30AD8552833037926EC9662D4CFAB0256B9F7893B0E898D3513967200656EA6688B772031DC86C9CC4FA3B3627226AFD4130C8FFF98CA52E617155A4B93D4E860DEEEF416522D08B2F789906F4DD317B570A83EDF10C4B74B03393409476A29B2FD38DB9203F6FCF2CA2F8B3DD6795D57F7EFFC6B3FF7B4A9CF3576524EACAF951C53B518B2BF1357286C22A88FE6CA47DB4612B29D937515FD2B408A4236E9CC7F393F85070E28C4D9DF4D75313C1BF8D598A562D521E771ABEAEBAEAB29106B2FACA90DA05CACE59A13771B8F25D8D6633C28B5688A622E7149AEB7F84F3553AB45901E6033E005120468E981D1517491EE8FD4505B96A6160BE6827B960AF32E2351FC2DF5B013F2829768AA68538D51201ABDE34539D5B260131121F91EB2B98ABD9FF17BBEA0695AFB6AB1A8F52B51BC0173AEAF9E5770D40443852C737587B8673829EB2196BCC304984B66417AE0567C16250D7BD4214B42221CD11EE9ABDF6BFA7F67F2BAEE9FB8F662347D7EB3917E7C8A0FF1069F0190914E4208907CEC2706A6543ACF77D23AFC529115D46302CB313C44E1E5AE27197E988B2E3E291DE0210F55B60A9ECD6A1587386FA257B94346AF7D718A8A63F684B7B1BAA34BE3DF4D5486DE7099238584EF31056B765607A6C1152E688B16D9591D8107ECF25DAE071E83753DB4106E2D39DE3E3BABD3831CB71705218D67FF8F34932D64A55FD4C73490C57F295744502EB1B318D9104BBEBA34269395D86013953F03ABD89A0094C32B68720649671BF470465DA5EE56A4407DDEB23391EFC395FE5DBD5D759ECEC505834F57FF93F2664458354487EBEBA662E3EF485C28AED2D12AF75659E1926E6F31527E5DDEFCB3DAF78907229295F3F0855ACA0EFA88758317B883C2BBDE247461557BE2DF5C56A91F8AC34FE21FA17A4D6B22ECEE501DCE522681D4143AD4A86D916F9FDA8156A560EC1AB61974FF38C8D46DEC1DCCA4861E6E8BAAE92B0AC27F96765223C2A32AFEAA0BD073011166D44C5FFC7AD04F2D50890786877A19B88748086180FE1633C2D2E95CC12EB665B73C1639EB261818B3F0C06A76B5E51B18DAC5A5CE656120F2DF88F47D47C426ABC4746F70ABAE9597D0A504EAB12BADD7FF65DF01F3936C26448EE6457A66A6E73872973CC139CF673DD2A8A60EF4821724A9F6C91AB2504DC096AC368326D1DE07602153A00515C9D3052FE1AD5D91850B952969E16E9575A134F83C2B52B652E614D7F77765EB6B8E903D50DABE22FF223E4F0605639589E9C1D796FA94E39CE8D53AD1CB2356D9D1A1391371DCE1F6F80636B41A4256755730702337D018AB268C2C9F8AB5E864676954753E833325B5529E95ED016EE2A05DDC128A9B5030DAF373C7DCDE5E1538BA6C6D236AE59CD59D31B3534AA6DBFFDE21AF8B9602FD3F2FEBA31550EA9F4BFFE98DC1AC2D120830C88CB2F893005DD7E446CFF7B5EAC8B696366A94D50D8190C4EDD44AC94B5AA5ABCF4E8F6FB21D24D7611664C42D92988405C99D1D553115C2746BEAE71896D1E2625CEF840DEE64DB3A5B0D199569B0A3841CC8BBB7F3478FFB4C6683483C9EDEAD2A250066571DCE46446C6B1C53385A92D473EDD3D8C8938087EF6D07FDB7340AC3B6C9E45CDED17A882896E8E42D12E1E9324E90CC801E197391FE6AA7921DF62A1D74B7A00EF09BFCF7E1DA607EFDAE3297F0F9DDA22D618177636F2E61CE11C206577B5E97AA301EF3E9188FD24C83A5EBF0D774BC2DE770FE4A1BF00AD17B4498B4B53F754CFB4D78DCAE942AD92FA84D36036EA089E10CED758A4C48447B3773FE1077E18D302C44C9502B7A61817BE55AEA1043BF230A357F4FA3B9C0D9A8B13670F4020EBCA387EB77E3DBB42352F061BC05E218E34FC49F64710C88378441F8FC63BF2F62EEB9F28F5994370F54B2D4835583237A32AE477CFD2459A6CD2440F3000E84E8434878E9F580880FDBECDBFB1F75794B187F0B3D5832851CE012CA2024E34F69E5F320056D935EBF5F0C5597A9B621E3FD7B57EAA88C15051EFD6687D45D0762B067DE8F359270321774A9521C55DAC74C1057D010DA9C2298832257132343953D1527A8722253967668D2F6D3D2D6E0467588152042207C791FCF314AFA09E656B51CD5DEA72E2AE92837875C148822026F9A9050616DFD47C768C029C5FD4AC84B55F7CF1EBDE770DB234BD72EF8C81087D3CF560EEED9D4D4AE14AA9EA3757DA5932B5913C51EC3229B22A9A4E76D4F14968E3A2640433928C5A8B771B89666AF0D370AEEBEDA470CBF3F1A3D90573AB576728058F91BD1C0719A3CEC3B8CC1C230489CAC6737B4B26CA70080A1D5D58F56FE72D364E716D2DD129A624C8F9708BB987F25BCAA8AAAA37389BE1BCCCF5C238C677023C2717E3979B94FBCCF2387598B4AE4759D0917FA8BD1D024F50D93446C8EE8321EDA7AA22DECD6C0E435CBA7BEA00B12B2FF933535C06566D1A77436BF73B8D4E541B0C16526F8480FEFB36421E6E8166CDD329051AE2B17687BB0282003971B3A6ED6F25E36795473DAA4D2F5436942889AA25C9F78914F79279F6F7DAE2E23186A9403E44A19D55540A2852BCF0A4D8B3892530903D5FA0C7D02F70C0FC101162BA01636C629A9C7EA6D019846D71E9C7BE2901109BEC9182F6C5FDAA15AF0F9D7248FF4C93B8E3B7B26C22DC3952AEBF5E9A6445C9278E9D6133CDAB5F73D68681B9464AF05CE1127E0731668666F494C7E42D17724E6FA78217B4C54CE3D37B0062350D714F712D4D300695AD3361A1BE14AC753F131B6F35ED60C341DBCE731F6BD57730FE9D6AF6FD47AC614647BE9201903F35FDE5D674831C263B0DEC59A5545316EC5C4BF0659389B3DD6588B559B3A864B591BB4C4A82C5E4870EF72D6BC767D8273244069ED047B479A51BDA24D1E64886D232CA6130680040E4591FBE4150A2225C6F7BD5FB4E17F18339ACABDF30201C9FA2E59BD095CBA000CEF206520B0303F713EC944FA952E4DB3E30A399A41FD16061772100CCCEF357237B2BC034EBE4FD7E25A2E09F210BB3BF82CEC16A567AEF61789CC64B10D266AEAD04B2A67E59EC5C3BDC176E3B702E69C852AE6CDB3362D0D040024E99A471446DC81039515231F2BCED51F092EC3A5013E02A8B50C4B2B82C86EB3EC8B5C980E88FB83E1F1DDCB3DD2EEF2198E2D391A665187CE882F1DCA248F1AD2EC7D62D4F930D12E798E10C998EC5769532E7A13EB56CC13327C9C4981C165D8420545B932585548617998BFB16D3EB1D9F760871709641778409A6CFC4D7DDA8F92414B49DED04C6E0E6EC91904454C51BD89EEDD05A4B545316EBAC7DEA61930563D1ECCF40586A2F1AE797FCE8BDFF21AC373E88965E181391F005D0CC1A77EA15603891C6792C498D8D1ABA5E0F9B081CB7E024163669E03678BCB60B492BB8E5C8580696D7A8FF9803B1F341FA6DD93A7187731079FFDE8D032D0853D1EBB39B43AB5859F713FDB863FAFE3138C901F6BCCCAC2A2E6100CB3DBFB03FB5DE6FFC5C631029D4E2B991C7CBA2876A5597384C23090E5B2158F83C484A11F33F8086194FA93F81D744BD50DDF9AED457FEDC312180CBA061ED8040AD5A6AB82B6EB97688CDD85E4364034C22DB1DB9C21FD59CEB24F5EA6950BEC272040432178DEFCA3B1C48BBCBEC0B8B18E3F73175B5CCD58E4928C0698C846AA6D5FCFD7492B10064C234C88E1CDBB060D06BC3D130BD1107D19F3DC44DABD19F6AC31378E349806666CE2E1E44B74C5409A6E48112CA45AD6827F11E94D7A1BCC53878D91BA753487FCBC21E01A65E5FC50CC7A94C0A1EB038F04FFCE765A5EF15510318223D1D6C826F8ABCAAF074B4A0D61846212CE16AFB3E6464F862632FA65B39F0F41043335C1B80D7201E17591E37F4EFF2198072E1FD03F6273B7322F8C660B6418851C2909BAA401346A7DE3DC2EA144C9511FC380330547CBE95AB577BA92E6179FD3AD1A59C5014C0FE0CB7E8CD25EE288B6FEEB20C09EA99B37F03FAD4529F650A010CD46B97C0F29F99B0127B15FD673088CA1FB8FF491552D226F9BD2A3510482F36E6B6C4123F2891E387DD9537D69EF2711368F2C654C0F785F5DEE2CC95EC412CDEE48A413D4E384055A17808806FEFFC6528260E9C40B1916E3D7BEBF8A22209421D7FD961731FD71BC1E3ED56A4E4E81F0DF9123A309C8D7942AD43FA126E64764F16484BA56812EB49A8B912664027BDB8DDB9679380090039A07704A25C49F7D6B9962069D811FCBBF16E759DD30BC4CDD426999342E12EA2E81FEE51E56E67D696A4EAD4478B14ADF1CDECC83649B28B22C954B094EAC6ABA9DA36654DCE233F4BDE09AEA129D78CF695028661E9ABEEB5944FF01C40BE945D811EB73C6BF00693228F23159D3A2BC907143BB5DB2FB2F5A9BEAAEAFB513B61184B16F0D58EF6F77E122AB9F16C2E0487D01FBC998745575895FE11C408099A312B406720C34F266B1C7A47A28C5D6EB3A288B99C40726146C5917FCB80CB37BD9AFE5AB16B2A23BB64C17305A864CCA34E75803284F59869F98758A4189F12110293D7CDA5E126A04C4F4827BB7F0DD9E4F35C5E1590E44CD3731AF98BD5121140974662CC9A3D39AB74336B79F5F22513106DD970DA639F4771E5291432D58F2C6A37FE3EE2BAECDF392E863FE163BD187C696A8D75DAEDF10220A4F74E0071FFA5C4BEE5C9DECA65622B9FD16E48E0FF86521B084D3E3BB55A4429CC3B7D739E51A155DAE571D7A0DC66FCEF85AD1AFDEDA41CD94A213EC2FF246310D2A0A150AA9C0A15D00748EFE30240596426DE5C973978B6C50F43FF5082B57849DEB861489E82083B0441CC7689C6E7779E9F2189DE6B1BFA30A6D6F918986F3716E98923970783F2ED75ED47EDF3C9AFF771D0237E22E3F9002A9BABAA4CC360084185FBB9F710B2ED3B7AAE929FAB1734B7654B096BC2E64DCB3C4D3346B25F84702D457F076A2F30EAB33C286D912FB4D12620E11CA7A35D83922E3980BBD97FB3A5619E6682E6E301151CAC072CF08E04ED990C843ACF8B0FB489B6795338356122AEF2CA069EE781938A5057D518A8A248087F85E5533E6882FA3452F35561324CDBD7D78A17057654B7A35189A66E96423346EF2E19141BCE7449C6D60FE52CBA1E4BD201945A7D122908429129AD6796941BA4A12A5F3B857AE47C78B0B1D0808ED6DBDD749D54291680163299F61DA4BF5B91B3015C01713124BA63250A86AD30BC3FF19C75B37D8102837BD369FC1CFBA2D80AD3E0C0E3048C3935B6840F0A0B41461ECA988DA184DF9C680DCDDD0F0346A685B188B2ED943EDE6CFAE53BAB364A1C1A2D1E778CC8C7C981E297D47D6302005BAD51F7450D3DF18912C9D6937C6C26A739C805C63FCCAD72B78448019D8AB866C531046251B6702CE87CBD65CDD5F03AFB18656E36F63E32AE9CB67C2DBF66E42A9AA15C3E861640FCDB3B9BE82961D2CCE3359892F8313A36043A1B00B538801D648CEDB02F43D3CE684A75C4A188AF1348BD5F4443306B249705A16352683E44EA5EE41B1D95E2ADC7189B6D1F2CE2BA77ACA3B6C4465AFEE1D05935B145DCF8E13DCAE92B99CBB76F4CB7FDB838D4019FC411CA21C512DE6D85D9527FE39CBC154BE8D600D06C11A26B142F07761D89CB84C9B86F378B1437E34FB71B7E06A656833EC31195ED8C65C287875C67B286C35DD8D2CFDAAFDE5DB3719ADF4E5081E45172F2E422A8D6D222EEE2782D8C684FF92086B13A1A5239ACCA77E1FB162DD0C9236AE84821F8CEC30C32C0A153CC6590D779833CDFA20A8135AFF4474CF751EC18401BC69264E3CE04F22DCEDC4C0F8A060B89503D5A4187A1E97CC7CA7661840CCAD24B1A0C506D5F43A4EA81F17ED3EA791AE8CB50909D1EC03DEFAE424DA32424E5C7C15C11A628205EBC78A66621553F2CED67028456BDACE57D86A189870398434700C12A1926A3A40825A332E0F7A0EB469CE95FE3650FD1FE31C85ECCC62190DFE894FD47C4D352DAD00DB0639C4BA16E9F93CDB2B6AC156E44C5E747F7C4B356CE938332A6F5ABBA787E2A84EC607638C24BF19D8F06FFC245C81D826A615485E2E07F7004B25F4243FDB391EDDDC11DD0B63E0DFCE6703D1BFC33CA6BC074797FC39A620BD9B1998BA3FCC148E1F2C29C33C992737DAB783ECD23413CD86DE41E78213C17C3EA93AFAC2873EC00B81FBACFEF521997A823C9E2F7933FD7151CB709C31D181F6AB9C589C3FE0392DBAF2FC663AE4534F65D4894AF9F1A7E6CDA2F0EA1761136D5E6BF6B78AD6E6BBB78519292B81029FEB6637E3CE6D2555AF4DB9CA5C94BB0E64A54B781EF2D43BA5D4AD2F938F63B8E2D0DC64FA1C96B224163E30A134B4C66C6428CB6C7EEF525D381A823A555FB4C75ABBC140C465C2B1AEE1DF8411729C57CDB3CB200BBCEE5A19A7379C42CF5D127154FE4653FD04E1EBC4C22229D6E2F05200E941ACB013D94BF899D32408B24E33FB936B4A1FE98B2C2A2944FDB9C4033C8AA35A9B77DFA89DE336F1C4038790CADE3C63B7F146DEA3D72205E55F0D3E1065353D876FDEC569C8BA18509C89C9DE6A6C14EC5C0EED7BE8409C0F92E5963F982AD45739CF5DB8C0CE11CE888888918AF02FB76382EF6E95987FA4376F01AC134A3A542D03B2A82AE0F54DCE296547A1A78F43AACEBA891F7AB51459C998F811DD5CB50D00CD9579EA414C5E4DB37242518818E328AC8B5EE409D9F19789016B23C44EE123E2F0CDE7B6F9B20B9F583D0BFFF9DA8FD3ACCE9064BDC2F370F830AA5061E335F9FE39510304F5C16196B32066913288C4F6FEBA940065AE918CACD2BB23BB36770439804E08DFDD9AC89CC91B10FF77067CC52EB40D48379C476573707C0698D0D0FBED05D68396318E4069E384F3F44CCF295EDD9729798398AD0B3B22F68F935985267A0EDE208CCEB3EDF70ED75875234B6F5560054E1E101A266625667F4EA17E715D003E7F7DA35B7E05B184EF87BFC4119557011F32B98911C602E4DE156EDB0868CA33845BC759A084A11A8C6028E1A9A114958F7347091D223F3A4F40E11429C9F582EF9B84A884CB7EAB6BED5603C26FEA19E9F133A37EF295CA9BBE1A0901C23033908A5ECAB12F449EB3F2E6E753C30B2B19F015E048271FFC9E58D1C7F47D523AD35B8CD793065DF7D04A40FC50E06F938B45D2BD85AE6ECBE15394D4645D3730B9BA590EF90025535EDB0D20939F45EB10A9F2F35279E529712790B09CDFAB681ED25BBE609E1261F8203F88CC37C4897DE56729C67DCD98318DB0C5236FC75C8EC1B171461FF27EA74C8613E669FFE1C144D169D96C14826C8018BF0599038321911CAA7DF4F354F1789CA6178D958C44644EF8266E541A457CE32736294E6E95B7C3E5FF2F713CA6A4F814B77D6EC89D1B0390C9DF49C05BE2A9F322F1D375E58EE9E4B120662E885FCAD8053BBE8DFAE914568FD48C30478F709BA4D6E62E9C5E332F61EB81807DD6B2C07AAFD5E5BD98C27B3300561769ABCF993768E8261CBD7EBC2F0A377CB619D1DBFAD64E24E4D890169FE88CA118E391B310CE892A296271DFBACF6E93940C980D6ADB4228267B9E515F69844C9F72608BB40DFB20A2D67A7ED848DBDFCD30A61ED2CC6FED10BE97F23C217D3A7B55CCF5052C62C9F5AB59D68921D603C7B71EB0B7E071D64B67D89F096DE05D6A241502989F4713FC03C09B509E4D7DF8B24E8B059BA81558371BBACA268D44A7BFC06C0320A7715C61CD8F2D7618AD721E28BD4A6914B709D2427267F18AF672741303FE988390D5DC009D876134F026ED256A8FB82BB8333206BA6C7B3D39296DCEC07ABE34CF665D93F9970171E86743397690964D61E752615341CDDCC72D3F27EA12FAB2C1CFAE77903FAFB6A87A8C5C956ABCD76851E249D522D554D06DC3C1A023493A9B12ADED48A7872D9A33A7E548783CC43C31A4798A520862F4BD2D0274CD0F907BA4F77FD500AF8FFDFA4235EB56D5CA9A3E96F5D4E6BE7D967012B59C972783CD8023FA06099EF7E9CBF04BF92925A5A1D52712D23EA93388CC6A0FDE17E34A4F130AA5128557685349AE91FCDEF7356739C67E8406055B44F6409B6F86C070A76DE40B1CB4BF6E34F9D2C0B1AC6EA91B0EB8A6C5F87872D3DEF7CF1566904550366B3622C72172B3D9D4577324AFDA08F68F0307227707BEDEA4C05D00AAAE3127C84F9233CC47B144F0329F9B3E9BDDBCAD6F2A37C9B7B0AE83E114FECDACF6C8307A072B3C5534761C3AD5330B9D275DBF629177F856802CDD430CAC4A06260B8EAB6A3762169AE18535862C72AA281067AEAF16A82407DD62B52A0FBACCA1D5852B000BA6236CB8C90C4C7E9000E2641C0D52766ABAE9312F03252FD3401A9B78066D1F9D9017A94DBFE6CD3B2C4114D03B6D3D11CCE167151E408CE5BEF02771938AE121A13E0BAF9DD13EFCE8540B90F3A54F6585FD2F5885659DD78A27830F11C21243BE1575CA1D939E3DEAC90BFD33766A1209122C70854D6D255D4A7DD789EE5710DEF2E23063F157A3892F6B292B5977F0AC39E77F8C94B3514AEA20BE3F89EBB942502E91753FA87B5C922142721E7027C0D0AC6977EEAB4128D4C074504CBD6C9F380F0139529352E37C6198601A2A0B0E83978C41162626406108255A9207EACC1719080782341DB5319A73B52D27F18EE15694FAF16666B66D7FA75980173F0DC01DA3E8D5E173D829103E40B81452235594D68359B7DAA30B7F325E191CCF489FF9E38A5399BADF634A0B8E3BCEEC60FD55CBB5D59CA5D8BB15B0AF68934B00E518BE526FC78E1739F029B8A4CC9BB2F7F5A9645AB4CDA28081572F76E02F8A55923A4B59E0773CE7574FFFC4370E90224F774BCC615F2405D78D572B77E996AA6CC37B0E1B9A2BF27C67880404D8B285D45FADDA102F2808F770E0424FEC81F5455DA9A446C8BC1597233F7CEF8E71246E6DAE5BA5289EBB49693FC5DB014531F3CD0A76A2A292DD0A6F83A1CD4F8092785CCF571F6864D041F1CBFA915F12D5F3E0C84C5317E9E19F2E9EFA2D0E2B6940E5269C724F50A9F5DA73985636037C1E3B4530884FDB466B4724AB45310E8CEE89D1A8C5F3A52B6619B8CA4060AE6C109766EE95019F96B8E7575F98DFC10880C07AFBE6B549A919B5717C50C38BA558BF92AC3A6EC3CA106AAB3D91AC6036E93A71B15D43F7F9C25C9161103AC4235615B12CCD9FD84508F19886478EFD67E53AFACBDAAB3AD09ED0E4A48A0B81C11EBD7E92EC7F2368F7F3235E6DFE1251D6761D75E9FD305184AF9559B3FFF63923024EAC69AF83345D1B631B65F486968CD67DBA901C69DFA730B15CBC84FEED119AEFB4F5CBF4F5D4F93A6FA37B61184E5B4E7576E73095B2BE520C16023204072B504ABD98FB095A58010F013213110CDB7ED6342376B1CB22381F92DE99F533249CE430BBDF481BDED8639BFF7FED4A37D9038A6797786D2CF13BE9C2E4B81F2F1DD340E8D7B610A7F3EEEF21A34AA9CF685FDD371A902CFCB4E8B367356A297399473E2D477F44640D588726E7F08D0F7BCB4E9766F182382B33F4B9F0E090D4426E503286CDF416FB9BA92B6A0BD081BD4C9CFEE843176219FF113BDD0BCA1F2515D91956F3FFF043D619ABF4595A6B2A5324F794E7B01D1E901816A412722E7C814BC67584F59DFBF599A7C90E332A1B185ACC8C7C6BD14EC68420B144F01696F816FF5B8CA7E833860404B712ACF90ABCC454FF417EBBB4AD407E5E847F98D3953F6C32829DD90516F07FCDA09A34B4A4D72F7144F5A6AF3FEE284AA13FBF2CCDEC7D12904EAEF3B60DC1EBA0F34BCAEAF643B9DD017EDA1D4E07557A9194275C2A2A4A269AA923E7E6689CF349779D548A1C469567F1E5CB0E2F13EC3F9FEBA13ABA88EC5EC9633FC65993CD9ADD01418EF9CFFC6A8145EA86164B0A3787298C667142625EEA140D5E74A404F5B9B6F277EA7F7B679F2B14549DDF9EABBEB44C5234DDBD7A08505461EB825D51A688902565D2476E3D571262DEA4163EB275D6905EC42025A7FF8A562FB1E57B47EBC4132C6E78D830D53011A6DA61678FDD55B5EC63EA41298107BB9CBDC2C2B85FD18AEAA95807D8DE259FB85431F79279B96FD7F9926BDD8C7E0B3BCD64D71A94D274A80C350C3F54A552AC9A4C352656ACAF549C4714C077AA759523BF55F9A9E8F6A6CD4E6A4B9B188E8219195A1AEA584F361CCD939C21C9D4BDC3BBC849CAF6B47D7181F16A2A0DC3D05A57500DDE753668B029FB1A8DEFD3F5DE0274FD417AC3B0F0B1716C341E4C99A0402BE5CF3AE32898A986A91EB9D24B39A37E4692D7A604BE818AE3B4BF45EF3FE8DB8F57532B0DFF382AD64182F1838692C04AE6DDBD6D37623DC0135FBDA07879E0F1D907085C30EE99E9C0391672623964C57FD12AE76858E529B8A9C67D944CCDE2D048A15A5E6E9C933DF938133DAEBBB03DAC7FF0850AE5842CEF8604EFA9B4053AE17C2F62437A10DEBE65B5FC496232FA56ABEBA287AE703EBB763BC980978327327D4D5396C03DC638562DE7043C35F86F750EA65CF17B7FE7FF7D5280FF941438BB35021269CB4478CABA9233DEF282A070C858A2436803B5918251B79041AA8D09CF635BFF0030CE2D0F30D868F13D8A9989F3EE0BCC25D648392F33F7103EDBF28B89A8D22F1099CBD0CDE3C109A90481E0A9E0C15B8919F63A0888647F70BE9AACD56DAE38FAAC38975251DAC3D5BE4158C9851DDDB740D787772770F0F5E3D7F519C4CD8035559170AD11881C201B29E33CB9DDC20C9EC534263F552A1B0220A6A33E0C6BEBF25A647D9BEB1A172797549208ECBBC36FB19D22E9F52FEB641D3FB6A7B9BA77ACF0D04740EA849518D9B71EFECCFE34E563F98A8FB58E57A0D3E6EA0A00B154C8883E908089FAC6BBAA7C28FE6CBA5CD6E8A61774BE0E30617C257E7EAE32A00E2C06E95F91FCD1FE79DC125457D7EF3CB3FD194BA4BF82DF788676C377763FE5E5C49B817E7A264A032BFDBD58850F28F6EF35D602D2511FE3699AAFF105838BB9DC0B78719C12ECB6ADC61A54DB2E31E86B04C1A8BB95CD2D387A2518A8F82BCA16699BB6341B4BC117D7020741B4C6EF2D602124B1297A7441BF4F18582F4327262E4A2716991376A11BC6CDE1ABAEF80C90CDD2C850803811C906AA6ABEF3333EC3628AAAEA218D727DB46AEF22491063BF7D8514B22EEA2253554B8BF2A5000935742ADA369DB1542789E4357CE92344D5C7F3DEE61F312AD1735DD4C1C8081798D50E911A9FED7EA86596C2A671CB5499382F625310CE25874854B43478944E098D991F156053101F1672083A8387817982100F982067B54F7939E30D57C99066AE8C93B60DE8FD22851C91D97CAB74F82C0FA816014B338CAF511DE95268C4ED057B6E1227B846638BDDAA5119073444AD401276250D72852C6531D2F20DC53497AD6B18C004CFE37F6607F7D07955B4C46AA991ABED048C80C09050A8D65D892D0C84E6DA5E8F5DD10D329C4416CFF1B3DAD94C38F7B54885842D13ED6A4F1102BB8CAA9238A392780E9B76308860E1221EFC4A53BFD29745985AD635B3FC525EE7BBA489AA9B7A5208D2332FF3A9AE9A85203CB36099171A0FC42381A169BDD3005D8F46A851C7B5CA5915548B69087484AC13EB5F93592248C0138BF9D7415AB5ED020F09E9ADEEFF8AD59AB29E4DD4096821EF6223B9268F477B7A14C7BA5EBB1F3FB436A9C2F0394BC3CA95EC2C037CE06618BC6815EFE46FD363CAFE0B0E4EDA793D9AD903BB8943045DEF09A49D8D179B78B0FD75B4CFD3C389D2F774E720203257A5FEF44DDF6BE142257D95F7F90AF77F65789E015E78252B31A103E98193AC6BC56CBBBF7F46E99650AEE2407A82268162DD931A7F933471F946898351EF29A4792097A22B66A5ED571FABBCB2FC9ADF033F69020997D3C9A4D7E49D7CCA0F4AF33D9D8DA651AC7A5FB4075B45B9FA517EA95DBFA402A6058F806FA9A48568F0C7A1223C89CF54F93A8D412987D6344611E460A70FB06CADBB005C3B6FC28D1203C4745352EF527EBAC405007FCC33484E6CE871B1C25638F9C336A5C0CA24B01D88D1E103FBD232EFDE4FD2E7A164680F1D3F528C2EFAD90DAEC6E3D6DF5A236BE1FA8F2669F92D7111726979C000764A0F7906D35D394BC2F21C6CDB3918CDC7C93E52EC76DB3E92D2AD6ABB6AF77EE01EE18A64AA45DCF430FB84D500F8811CC32ABAF767CCB0EF22B6F62E3FC903771520E51E82FEE219125537FF8316ACD2F300FC94512CA54CE1C68061B8277E1BB4508E003DA7F8274B9C2148EA4719B2884923C2082203ED22A463F9A07C166CEFFE4625D15A2E690C3D8EBFBDFE5BB8B32B85B1DE582DF00638FBA93EB700F2B19818521EA8EEE0481739515D22298B94EFB870B6A92190146A98F5657A25724AFFAA52BEE9AF8E0CEFFA1404DB27805CCF47B9A1F8817E830ED46405E7DC7D1BE3EF3B080697E2340E47507634E561A77E9F18665729B84666BFB31D7452DD25DB98724C66497C0C3F57034827EB85F1FAA34814E787D2ED76D4CB7A04228EA0313ADDDE400B377FCB16C716BDC71E08A33635D2C0A4A2BEC0F7C8013B5849D8014C2231E020866722CAEDDDFF4228EBBE0D68E72F200CD83610A4E3CE15983B6AAE3E41BFE92632438EE2D2358358CB1CCB69C960DF09873CC9CC1C766A81CDD51ED9724FC06B6DCD708B5A4688C19976328FB762EF74027786694F08B2DDF3EF688A605E3EB41A9E59F7748C5A9B53323289DDEB888569C94DBCE7012BB97D93956C2B86844136C146AB9F983B905BE8E70DB991AE43B689AC95A7D425DC3F1BBDD456A224032895E12CF7037DC878B07A9686BF77A35D5A5C222F29D413D64F4E71F583ADF46BB6FCE0DDCA51922E1D220EEB41E2F09A0662D5C8E97E1D81FABC5AFA0CE9844AD4D4BDCE7C6016D8A1C452A1B407FFBC58D5D9E7C701BDBC8C666CF0F09E69FC345A497C822C956C235A1E43D987C630C540FFB4494CEED53159689F74D2131924487B3FF08AF6C8E14E2BA15C48D16591DBC27D1F774D8AF379E7C7319EA2323ADE2CA17B2EC53AE2D6B3F80E80937179FFFE04EB048E21D01E4DBB5F860EECE71780D706D93526285B65429A60FB8C34D9B62F9F9CB7A9EAD204375F8D8E2EC1262593D3F8812F4A3BBD15C444094378045D3EFE89A1FECF91B72A0F6FD1EE971A06F79B6B2C4F9824F7B6643221D0054F543A430CC2F18DB81BE4741D82CB97584D743FE3B7BD248350EFBB901BA4BD6BDF0185065931F20209B710F9DADBE65DB3D736963323D22A6C8874F1CA67AFCD3FB3F7AA7E2EEA71FC4BC3A3CF9107773C75F5E5D86B2F2FA331854FD4724AF4871309625D7E11BDCD2E8E3EAFCA85E98FBD6A7F44B9B85875EC4265A15A0CEFA1CD54E67C3CCDBA0BF7109D98297D8DA5A8041FF3B154ED586042AE2424CB4A9D070E8F485325F2F83EAEAE2A6A38FF3B708C7ED052F1BC1E28FF505031216816D856360542B3C38547F903EDF10133BB79E0719D1483F28670B2D51EB9411A562C7D28587CD5AB16227AA6A4429CF53BDA226E55B1F12F243BBA1837BC2C6582EF38780FE34FA331BDC1F565DE8963F087B8A46C90B2C205BDF622EF7844EDAAE6CE61771E996F2A16A5C801DFA84206599CFE5AFADE60891477C11465ADD7588C92836E1DB3987FCDACB59AFB412C3D81802F4D5A2F421CFF056264E0AF2D9697DC89CBC0DCA71DDC591FD29887F2C8141C1B6BB513E5D7E4680C90E76AC9912F01ABE511ABFE7713F336C559C00C477617F6D81B32B04C1E1A0847320DC452CD7D51FFF1E8273E0E5A64CB19D42BE409069F569A429A112A3A820EB7CE3B8A5BF47F13B624033D287F4B714745166C74BA2990127A0F975FD091248C9223EFF7680879BA6067C0765F95402EFF9547815111A25CBF4AA1D94797FCC631F06ADC1A1E35AF06F4490AA3797DA65FA6ADE3D0CE758434E5DEBC826F5413F9745CA1893FE2419BA32922BF8041971D5AFE081E2B489E5D259BD2523B9FBDCB0C6E15B0830B80608EE303F2B5476EE7D41DFE7ABFA6E5E38BC718F2519AE977BEBA9D61AEA11D7BBA6CD1B78B811291C1FB4DD9C1B434A051278B27D7D6E9AA046EAC53D2AC47B4EEB47AE72D72B84E647DA99365138C8A1E316F4C7DA1B791545E01B64AD3836FC82D5F6494AF1BAC1808218FBDFDD3B8F633F26E71AED2CF976A36D734FAC6B5E49F10F10B39EC57E92667079C9889A723AD078AD7F6990946BB478584C3E86A69889C281EC9440E43BDAABBCCA1DE1D9D3DA8D0FDA54422CD37EEC80DD17115C8635E618F65E819F9CB84E28630DAE5E53FBEA375E036FC5160F9F3E3045298C242AD57661968D7038A7D5DF3AF2D294CD3812AD747BA41A33F83FA77B098C939007565CA09F061FBD87D1D09CB5BBB1F42AA3FF08C9987EAB350A56DB13901FCCD67B8CAC4C517C2DB03FA6286C855D8AD41F487CEB5507DD2338BF94FE742558F6CF1AAF8DEB1B6EE3E9C85EFB0F515D92670F2B1C46E1DD49831D79DF8B87B30F27D78D630473D695A913AFC6C7446AA93171598D19F6DC29B10BD11484226A33C9E0912BBB1D0A297FFAC54C6F1D5EAA5B8A28F9E0810C46663A885DB70FEDF0D67E38ABBBC26B109062CB1E194B9EF09E27CFBDDA03BEF099D813DC7E79FD20E96319E5C3879D9CC8629E2A272B6FEF7BB29AB590DF2AB1FB87273314117061448965A338C95F218AC02F404F9D8FF56DA62F2D78E696B46A7120F28839022665F4092238B4B7F8AFBF8CE58C9F4477567AFBB63BA8D10B85CDD3262FD47CEA90B3779E6AFDC37A6643D499BC2562E9A98F8ACADE147B22EDBBAF687176DBA845953CE477575FD2CA7F0628EA103977F9C456D2C6E3E1286F36BCE3CBA6092E5A238B4BD46CCCB27078020974D4FBC773A206700FFBDB25623A9D12BD8DB5C7638452B73D6CC30B44F9C73FA7CCE8E26511A7A5FC4A8C17CC0BC899C6B58A7EB4F00F3E64AB33574D75A0E4C563B541B5FD6DF598B45384840F583CBF629479E8FA47F4E5773207D093D0E7588786F2485D569063AF6AECB3B019ADC525F096E05D6829E09CE351AD872D80A361A0800280AA3D965F6590F93FAC003B4672F5BA55805D8F9D91DBB9F8CADA9DC3FA2C114A42F9AE617C4DA2B7C4B759B33EDD464BD7BBD0315B671A435960F6057FA3734FA6825357F392D3D31FE20F0FFA5336D5CFB57FDC6E03E873FB3E4A3307D862FA7828C1DBA0E0532EEDFBE1A61B588C8809BD105A0E810CB48E86A0880846FFFCE56ADA16817229FCAD2FD34072D28895DFA60A729CBC76D1DBFA10D57C3084E2027C657735A9EEF88126A44D2BF10F6863B5310C43BB856E812CE1B97939129C3D3218448776568E73FE9BFC4587AC2953C093357DB013AD90A033E6A472D6383507F67F9D6273B60564D7196735F3882618B0783A9A3A3E281898D34C08AC0FA7AB489CA3FBE1A7FA3148884ADBE50E54CDA7ADED820FC27B68AEB11C80DC3DD6FB9D79942538EB590979F427BAD5DA7C7B035B907B99E86B6C31969F34E116E79EF1D5DCAD272A5E3488494BAADFE62BF366EDFFFEA0DE9CFE2F14850F1168BAFE7DC03E0346E1DD0538E361BBA9D6C3227789BE4FB354992D923C50B7B19123F907B66DB827D54F47ABB448700AE27EE906DA638E9EC205865C4924276EA8DD984CDBE073C5D05BB4A9A242ED555C1D9EFDC0627F2370E499F2C51764F98220B287649094EC45FE7A5B2766AE6E90E6E8695B3325FD7BB8AAFCF2E15D38D1D106121BBEBEE7B8EF492EFFD2D6430F5DCE5864D429326E37EA86B15463A5B9C88133ECEC158B0FFB67ED563C085821EA1210120E0DD441DB572A88D00CBD50E80980FE675E136133CA4E1370668126D2AEA98D36273F652FCFD67722B87E6AEB281B1D9BEADA4BED94145FC719A45277D8B8AC19A60E08457869F75D6BEEFFAD1CD8A2998B5F7AC049D3DB75AAEF2FFAA69AF8905EBEAB8B86E23FE0AB52017853388F4330EA6DA78DC90783E6EEF2FF86B0583BE802B30846773AF7BE59480BCB0D1526B0E631CF4B0CA5CB742E8A8B4C5999EE88E44BDA1FC6971BF7CB3206A867EF9CDEE83F3BEC5783E8877DD4CEA10A816F14D96AC5C8AD88A92334B27DD8B8A5243DFAEC9F0E2DBBBB04E1ED4568A70374E419FFB3519215C018094355F91B3E499C463C1621A9C158AAF31922C959F959EBF6E6D60351F616057C67E76B954261214897EC05A07C56CDF0CE65AA2FF04101380317F90005601C0E0C7A8561A582F6899FE65341F0CA79DF868C49BFC9B95B3B808DBF4B327F35C1263EC15C6EBA3926B142C7A7E929DBDC206971C273DDB28FA58653144EB98CCBD75A21B972F0FE3C76A1C2CA21D009E635C4D0FD3FCE14FAD4264C3D6D00E43028385FCB1E731971B9897E12552624D0C8EAC7E1ED8A16D9B65C12DFDC0480D9B2A6E4E5B53F79E6FC4E75066D75D03CAF6F699FA2669B2309879F2AD32F2611B98F9D268CA3D55235CC3A87DB93DDE8DFC6374B25EF75F0D1123B3CD3A12327860BC5B882152D367E19AA461F850866BE58488E57730BA9179BEA68F263736DA6BAF5B770D6E55BCB8A83CE905B6EBCECC74EA2B8D04BFCE4549C6C497709D2D936EE5BDE2EDCBAD7DBEF69DB131D7673459FC4D9D31BD603A7D36BA246F4F6E8F329177C1FFC4C323BD00A780F9CE5F058C9A062700A6A23CE5BBEAB679F5BEBAC10EB27664B38C10B807032D8D546DB160E11066D93A37753D114B60C6470FC15970E561E3CC48A0C0B8F60DAA375E162A65E574AF2B9D6B7C9622A757395D2C48FB371ACEF0334583EFC001B84AEC1FE2643840F9454B93598167F7391166A9476F1A17E02F830365DFCAF0D7B426DE5978440C338F58B1E05839A71CAF3E78B77AA65BA1FD46BF3457E619BDAE5D19E1DA801D33343A6DDF3727666BCFE397A4250F1C491B1A3521664C80186E4997FA51F90E690729B40A96DF2F5C50D0BC73900691BCC8B20FB14A45862DB9267AD7FF52320CEA5546D31461EBB732431DC5FC429672A5A5A21E0FEB56ED1B6287CB9BB0FA60FB5CF505686DD72F54081DEEB6CD2FD2009BD21A4B7485BA43356A38820E35453F38B3E0F1C89E5D2AC60A944709A0B3F1C337A176A2755BD8C629BF57C1803638758341D5D0DE54B9C18AB13E052E16C6268DF5451ECEA094AC2BD7DFD2D8B5E1D2AA971854E5753CCAE43F40CC8FBFB6AFA826FC515B83B879C7EF758422A3B018D221431D4F033F426CA8A2E017241B1877FA084DB473CA217FBB3D69C2A1B2CF3EE7E63854BA2FF4ACF4BFF828B8EC47D71506A39C5C6C724DC12CAFCF3C7AB4C095EBEC2ED04D53251A47368941F897B656E3B6989E2377BD75B1B2A1905D7A274176D1BAA2677158934FB9AA0F5D97A440128E2311B966E98B23D91E7E0299193D4DB743DD917A185A6132F7D5BF8D44FA8ED48DF7F7A0F90D1086371E6330B3B81D105368EA77807AB4E0689285238DE9E7ED4460CE00F81A880A3848E05E642E1F4531BEDB4FC2ED4A52AC394E4234F6E05611602EB1BE537134ED9F24D9F47BE500C1C73EF551DC2CF7E0BF8C725B17ECEAF0DAB8B3F15112D180CA0355A0DE7AABE35123544955473140C1A211D2225BB6C115A43120EA3F89306D3B3EAE706C695EDADB0380CFFA1EE27D48B594E05076CDA16F51A7FC183AD9A99DE67AE18A5FE0DB7C2AAAE2839302037BA71CD18F7675CAA14D8D6519874F2A333D7C7963FF633DA201FD58551AF7F7214D1C2BD612ABB7712AB62605629E8070A743D323EA4844C1EB7347B3693D155FC08CC274639CE68B726319D2FF4289C4926A2BC88C32EA11C95885BE99632A9261632B23429CB6240FDDF1972D7A999A480633034ED1A88F3B4C3E01A5C49950FAB6CFD52219E7AA78CBC8F0DCEBBCC25701FB1B2CE4C23C24D7C6BA48A37D08A87F99C2F3121ECA194BA105482C18CB30AE691E6F87B71C8A07143C475887880B19056755FE8B74010080D48C4A6ACC4270A903D4F08AC80E6A6340DDA4931751B4E95839DF30B16F028A201BA29BDDD21DA69E5889B625B8171C66540C9D7661582D59408A3839340B03EBF93CFFEAACB9A462CDA1285DB900088503AB969222CEB5E61366C352D2781CEFC9E3D00CDBBDD820F5FD9F5F25006D6BFDE5A16063F1302071A7E6F574E7F56C3EBDAA9E2BFED115B4CFA155A00B7CBA65777BFC546327D294EE9215852905394CB8A5CD7ECC9BC656C3B6DB01730497F662548E8776CDFD90AB002ADDB8D2767895FAA6DD571C7E7936ADA00CF6D1B4A2D49FE918DBB292C094517A8E11B1D9B821A9D9086EAEA72EEDF8F4152C26F80CEE9461EBCC33B0986897601D1A5B222A3B5A8F493D98630C0426D49C93130EB4D05D3D8CFB7ABE419B43D58E2A874780FCD256E6BF6CC8435D75F255AC798A389457725979C8EF289CE664402FC0FABA37A24E3B40BDD806B23CEF43797B4D58DC614BAE859A362D15A19B192283F4A3930730E70E6AC82A1BA316E1DA9586BF8AC1B94390D9AACFCB2063C5D161A8D8538051061E646B642B51E26C35F7E49B40CB608B88C64B6FF7C16A29A197C7D9453E7E7B3629BD8FE4C67703DED74BED46DCF23E3B6F28B2DF2FA82D4C5ADA18394E07A79E9B4ED5564F63EED83826B9B493770231CA56B988ED31621B45F6B9FD5D451C189CC5D5104F35DE4EA32FD6C623EC01344A949621851007941C92A981EE1798838F5B4CEB6578C560B05CAD78260545B2181A0AA1752768BEDA09D4C3FBDB3638DFCBFBCDE6187CFADD8EE621471E68ABC48A138EB2AFEFF5EF38350317589EB23B46D8034746E997EC77D7884DA9DD2027BCE1997AFEF32C6D4A2A1DE068F11D3B3835D28DB243CD4F2120BFDCBECF926E89C965E39B698DB2998A3443DC6E3723DCC653BD9F33E2CE09632FD05E1BD6A624ECF88C85B95C120C96C2058A39345498EB6726FD14808C48393F179EBC09F0000FA65778F7F1B70224725311EF19725A8BE50C489B7CAE26312CE24BE4600DA70A21016B65A8BFD4A6F0CD3EC73A409D48C2F697D5C42D6CA798B5EAAAB6727AD53959ABEC3562711E9661DA8B64410686761A161464BA141B2C21CA1A5BCC2D213633F2372D6B0E5F66A57720D624B3DC628938B1335E3FB10AAF889B1909E215F6CA836BC9653E924EB5556795738C38E399047FE24FB36FC2A13A79300BCF50FFA488806A54B4CCF780E2D008C688C6615041BDAAC153B06D2EDB999C07628BD7E1A418B261FB7B2CAB234F0F5682D9AF401C6120C1254C87C2E511D04A914C8BEF676B2258F8DE95B6252332E1BFC997674376F3BAA90EBCC528C6B81D992376E739D2225ED3AE78510F58BCC7E21D157ECB68B8540A818140D3DE1318504F85ED23177D9CB7459C6D8FAE0ADB4B626122C66B1D860A2EF753E0BDD9634E120590B2D4B0718E83B6F06171812F82C9DB2A4A0D981D70B347A545B87CD8DBD35AAB271D3B0723A4F237BA223395C3DCF2BCAA97282CE963312CAFB65F78C7E1151DE6101E7998DF4D58383973361F54ADD2CC8579996E66DCBAE5F00202B157C17894E1E7961691B543BC8E92BD7EC383D73218471E8A7D2B794021A5FF3A552BE689A79EBCCEE2A7DD4A9E7702A57D0408D6D8B4A92081B5A789948138D9602C5A8324B013C772CD381596635C512AC7A4EC19EBDBF48FB1F7F563410B0F52C6D716DD4020A076826246A819E830CB268DD745964D0B6036B8275E1F1344A27988D0BDD8EABED3645D5364C4B6B448AE60CCA0135FF08DB589058E0B71F99AA2DD0C5CAA82966E96FB98BBDCBE315C2799C03F94C9AB55558FD12581C292AEBD7473E28B5EC51F635B73AE6A556325F2650B59DEB44A25AAA61A33C5D94CBC1B82AB44F53BEE323D7A7A359DD8BE85B434F3A40F32AD344F7A60F0056E77DB4C5009704580358BA95435686C4926DB9699036767A957E545A49BD1AA3F7CDDE1639BA993613AF66794BAE3D07709FE6C4A7BD2D2CF978D060DEE9D8A4D48F5997A1EF5BEAF9220C8FEE5C846CDB354918A092E75AB8385BF088717DEA9881A37373074C0CB74D2D8097D219DB4EA2BE6FC6471D617F31AB92AAD18BFD48A46BF96064F434EDB418263C7EB1743D557AF78F4DF4EBEC858E0E0B06C5CED5C6A54D186E75B3BDD6EC7D564170D51002BEAE838F9F2B7D68784F3E10DC75C1D71092F0B221844F0A358104AE46AC75B24752F5141CD6782ACF121CD799A0804A316463985216BDA98B5BA3C7134AA25E5F46180A288DD3E52AD68E1EB7ABD666AB88EDACDEF3050B263A470CA7A805A3E120701E61ACE38CFB20410A7C414ACCB79D1FF72299B42F2B412AC058AD33F0743A063DC267E4317CCE6B65FD00BC06A16F23C143013CA1F09EA6D0D9BE4989E7F1421A732876B6978F119CCD7B51F7261D414964933EE23EFEC7EDB0AE7D03B513FA89291E499B49158DE5E29357EC92B55EAE2E3EF634B0919D2CEB7CD6430994ACAE132032372D987CB052D4F7A13B8D51B97B2345D9EEB8E74420EA506508C3D6815AD3EB480F589AE9449F5D2400FC39F56809951041D0C4CA1C07D68CECE46E1727B39EEDF1B5EFD6E9F1C28A10C708DED3ED63D635B0DAC75C705363FD52636D0D33DCC2606C358F11BE175D34A1A41A08E964956C48DF27DA2C3F51EEE7787CD8FA10DA26FD87B206D90486722FDB053C3E2C0F08FD90BB6CA63704BAC4615DB9314A624F5D5D16D0F2D7A7306D4C1DB969C39B2DABCD6DE41247625917BBB56D1BED6390310C20793314352CE3633EE7756F81DA1877C5D292DCD8F90F813934596377301592DC46A6F012B978A9687FACD9A255816DDE941D8FFA5FCEB63C0BC6F676BDA609779FD65DBD78F2A6AC763D846C3B63B7F40FE7FEA09703D3676527E062DE4FD692CD9CDA8901462A3C6DC315447A89099E121B97332E35594FD13E6062D93E34A0626E8957502C61ED8A78AC87978A94DB6A87024DF4A662564F1EC441653EC706541F32E5A9E502188981C51A3544FD2B6C0D9383C2DA3E9EBDC45D4739B22EFE1125BEDED6159C4BD37866EB06463D57C2119DEAA281CDE3725218D133CDF7817FE32408554CC5F48126215A4A3EAB3C58FE8E2888E73C70D0C4E8881C9DA95F06E30C37B64E10BD7E4F4BF8BFA7700E5AF03D4B8B0151971AD461DBE22D1290B3B05EC1A48FD244D1CA4E510B8E8E8A7E93C1DCCD2612779C8FE13BB28303FF6370D9DD8479EAE88649A90CD242F531D85DEB07DD627D1F8A8FE42FB2FD95716CC884641624EDB8B7284C7747E0B58657393917F898974C487C397B9F10A0B7895C7AE3A02CFA76C9368EC2BE9C0943F1A653D7305EF004916C7F69F4AF4EF948C77BC885550E8B4AC20D2947BA9E7018F643B655891DFAC68A81047F3C542F8C70A59A1127A1613DB7438E03F31255A92577EEE9A23DA045BC96421C1785BF604D2B4AA1251A8EEDBFCA1558DAD9C4803CCA63E2E4D88DC59A96F41B6D3D2E6B15FCE35731565027CA0F738FAD0AEE7035F44D5FF68DEB92D9DAD8BFAC611CD5B86A301EC5B717550DFCC6DA590945CD5B23A45F4BCF4CD5461BD8CD17601AAE2F14E3DB5E366D86295DB75A9B07A580F41BB017CA440269C34A07207145B51AECB8A4B557A40199F9BC355F913CD59809622D517CD6797818F3D603D1B1EBF2BCBBB1D3C117242FDB77237FBA06E719BFA63C2FEFF537DA469B282893CF0A37A1614B32B455282BEE47A10151C5DA32DBABCFBB1888C5A181389F2FC367DB215C7EE7AFC0DCE36A210CB008E726F962ABE80CC01C3D157EB9F045FE3EEFAED7297C797796394F536D52DE4BEEE55167B88737CAC6656570D442C4B0D9244CD869D65035B55D0B70EF5483A8D51C4C9E21B1AE5BEEF838436AF9DBD23799E9AD3D8E21D801B4AF4A1A0556A2800FD7B31940D745D5E0F13B888F4C1E707D9305A08EE2CBDAE862FE7BC3043737C718049B701A94517D37AFECAED3DCBD0D4692B1D6CF6B3B9A5322A5F39293540E7C61A627191368EE0AD5B74612CDF83EDF2E763181082937D8100672B3FF5947EB4E59217A941FD637E63F9FB7FF4D5D63CDA3B55D9D504991C4635C12EEEECEA8BB7FCE5C1A13E07DFF6D2DE0D4B8FFCF3E982C26F180F88725CCFAE0576F3C934F6E75DF9846B69EA62A947121F6AB1D066FF551C49CA7F8BBCF1AC17F7376926A9BCD12D817E7CD14859771F4E3F7E8E5A16041F68D84173FE04A5EAF490584F5E0DBB62FE1D679FCF6A6BAF3B4923A13043EAAB5EC8ED599782C4C3B9C128370B124582A609FD85093EF88247E213575BDC4707E7773FFE0410821FE06CD8CA533084CB09EC1752D7223E7505085C7A55BF1A27E4D0000B15AC6D264FC72B45D25FD3CB24FE75EB945FBB69970AC6731DB8841D16E844F4F8FCF1D7ADAB02F89603B32899ED83979B5B72BA763B22C26D7B5390732EE3EAF15B3AC23E62F573521AF8010AB45BD9F1F2B289F4BD0367176A7B7CF79CC0274AED59D1B46D32343555DD5E5CB9770633703F38A83379210D4FF663C8CEA99F9674567C4AC14F371E4CB8F19A57A1770D848751C1AD9A609E5119657317416DE54C1835FCD29830F49AD6F719FB772F6252B13912AB4579B35A3812F7BCC1B7C54708281A89F30DF491209256B03E0DB62BFE281E982ABD2224BF3C62810FDEF059FCD65483693FEB0D8845A29765728A59BE0083C576E68DFBB2D947C9987E1ECCB937229A790C862EB60A375A8F7B760FD592CB51C1996F93B1DD592A3E80BEC28ED6E0E0B20575177C18177D506CC80F9489E41A24815995F60E83695B93C64F0B831B72F7D2F798F4561C27C912316A7952CCCC3698D6E41C0B98A5318FB01EAC97F3080721B4168F5D5DABE13B3C7E14A914694353964545417EAF20272FF0A6AF87372E38F7E22222013938F566E4FD637F5D10D2303314014ACE33EF1B9C26CBEFA6931B90F7E735F21778C80C9A9A6515C2576BA220167B43023B1B7689125D80CCA51771C7A2FAD2266F091AC82B65441823065536C3B5879F08FAD8FAC3C6CBBCD43E244A22F9B5C3CD8FA4AF079A743189C12BCE489A64391F6CB6A556AB9B44D51FE72C11C936CA288C6AAB268B8DE45680A0989553C542413DE958B3DBED41E668A4A85FBF81A5C03CF05C8CCDAC7096C18F45E97EB293CEF30C9E0D673BC40614D24EB17E9BAA2758BB2EE29CE430E74EED071C6F73004817B4B0EAA20E1DCB64C846BBCDFD118DAB21F8202558678A00B80895CF91111100B35720C8385FC28791D764D77CEF71AB2C43F8268116F120881C17010A55AA3814600E7C4B84FCE4952B2E80FFDE1794D18B9209311841A4D4EA4B8C6643CFC98F75F7D03C370AF4A07FAF44C7C25BEABB484C0E42321251D61DB06838AC3FF1C9784B836AF78F9E2B352BE7AD1D0D54FCC73E154148FEE964AD9F57B10F89ACB9607B678C9B1F189F92E0D3B4C3E44487D760F7AFF49266A71D3E493271F9AE1A68935458EE611D765A977D05D415649187439829557526304F853694B9F0A299FFCFD6A1B74F2D6A99BBAA0B8F9C1C3D3125ACC63D790108E7BA24239F9C4B362507DB1DFD74BDB6ED00DD9D01D335F1AB34193851A3BCE7FE803C5483646897F8270049665685E2EC70DDB353FE1866462DFC373C8D23D0A1024008E5022356D492E1DA21E3C0ABEB9652CB63916C3219EF2B5AF7F2398F277A5F7A53F8857073BA635C19E90D0F000C3D84E2E6033D6A50561BDD493116FED165A35CA58BD7B1E40CF0660F0D351BA37DDD960780288006F25C64F688FF6C513BD2BA9105EA9FDE3CFA94243BCBB4CE8D54DE2F021D2DFE5C84016A70A980028CDDC67E2A455A8BBCE20A2B1B540FBC05FF3C989798631E7FC2056540D4C8F068BC527ED89723002AFF997AAD7B75F37C00AF45CF39D1FB5ECA8AACB13B290C0F9A587FCB39FF556244AD03E778D9076C97E439DB2C6B7607C2865FD8165C592CA5CBF6A1273B7D732987FF09D0EB1D428404C601A7774016F3AF844664563E781AD3C179507C9B3DCB535E9BA4C14B807D0DC52D0F8DCF609E89932F588F14275C2C47BEF4BB69FE0409850D1CC681E4968CDAED75DB80B0CE58E1B111F687B5B5A4731F873605D37535A48700F2668B61A4AEBA20783D1DBD14D88D7B0F27F9DE6D030135F1E50EF428F24D3374AFCF3371BE01A1039C2412D37E58A52EBD0DBC78848A17D144ED7DA7C8848C535C4335A2EF5574727E17A344332700EAC71DD64C8518DAD3F959B1174219C5EB04ABA05E0A1604AFFD2ACCA0135680BE86D07A4236E09F4897B6B93E953B3790A345FEE8D66EE49D483BE48FE4B2D3E2D99B0516417338EBE25427ACDB2A92F0F01FB54C156CF7163BB4966658C5CD6DA580D54FD4E7D40A8B498CCB2D1FCB3EF71402CF9C2679F77B10DF07C7A996CD3D2F9E4905D1C541883EBDC38C102CBC7371032087114CC9DBB73E5A59E6EC7FCEF92F5CD05F846DE503709123085C7D853573465AE258044320F52C97738C7812BF73A701DD6CF8814695FF187A674D26DB12F990C7A56D6CFB38BA475EB20E9BDEFFD44054BF13DFDF7816141C89E897C7340FB9675E3D6721D8472BB62DF3E206AF59E6B64F8F4C9B3AED72424D86D6FE808C4065AA79D00E1716E85D5205B64EED36610D61F66F76BBC1A9111968194196459C7A3769018EE34EF5DC03EB0BC9257ECE005993DB5010036CAD711C6C9C09E9465A3A1ACFA9A85E08878FD838A820BAC280FBAB50826CB69F735D0565762E0C6FFD154358105B1C1DDA0A1E4303811E4E3FF5A235B49836720E5E8323E0DF783058135CA9599C4511FB1E965782EA23159E72F6FF333923B51946417DE28C1D7B044F18707178E6C0A3151329C9A9A7AB8E4735D61294C08A859EF72F9AEEF2E6B98097E72A890AAA21281329F8D4F1208219A6C3584B6A0F86361AC6AC0C77D4092D104E0CF7053DC41298F2501AB3ABEB20F77850D4F9A5F685613E43F191B07FB10C03DFDC0D7582D8B57B1BF773D2CD8F3B3AFCA7CBBB7AD359C9B2D74D8E7883E1D9888A82EC10E24FE29E25ED7E51650DE7523729059200ED10D49C98102E1D5CC5C22D20C12C4A2D827D684D6A7EB90A37843D8E06DBA90B328108130CF1824A083F770B9F5C3B8A1A60F51382B56A6BD836AAC0467E9CF2D3567E86BCAF917E98C016F01A14CDDA3315D9B50CA02A25FDB361DB34E0F47F187CA9CE0D4F96409F431DAC363FE330E4B5F936113E6CCBAA9150661840ED6FACF11FDDA8C5C4A7E07724D40EE267E53428638C952B7FC777AA13B79DF695BBF491496B543E989934A7350C25594473A4D694008D024BA9788D0CF5C6D590BE5DEE99FFFE6FB7B1950D502BB99176FEF1A5585AA94CA228251AE1EC0DD6A561E26708272F19A97C412F8744B4F2D5C9BE742FA310374A4C6C501D35920920EA9D25F568AFD1C8975BCD80219B4C3014E936C74D5562A37899084D5095867F86FB5AAD9153D0D61CC0EBD35FE1C1CB48FAED442126677E914D0B916972293CDD034472EFBFE29F6096F0CA844DAE27F974B49A38DDA4F60D938160736017AB05975E9E34C367A142CC6F8FAB6E1FD6C35D412501806460BA34ECB98780BB9EBC5E95DF9B7ED3A80C80A7967D2AEA13929D332907FE2DE21F1EDF1EECE3249380F98D5753849EC9C8B55B4944C73D0BF7934D9B709EAB5007384C3B5759D6C16169FE4BCB0D1D99AB0BB7C31D90B1B08A767A5704608F254E131197CA3441EA53B09082B6CF62515A5DC2EDC44D0528488351F371AE159A1469DC8F11959D98AC9DCFA09C94B110B5EED08CA4BB133E79EAA62F51061DFB7C0F201060D6179F1484AE298299B8326E899F93D2A014588422020B2ADEA0DD1FEF37FEB311707555C8AE0778D9520267CB6B65A0D63C96639B0A0EE2692CF82D8175774B779BB1ABC0BCFDEC88AC7DB21F7B0AE7F536ECC36D0CA5A6BA31A22970D23FFBF4088D13BB5C700B1652E89366F4765F1AB6CF546CEEE20B900D840D0699DEDA8729DE06F4B753BFD3BD151938F3AFC5CE7CBA52B5DD802756C2468545821B946E70879D73B504395C0CA92C727F7F129CE984F6A24BAB246B606042E68E9681E63E9C07B614F86DBA76D6870D3E6DFD6EA14C81E5020BF5AF5629A5B8486579C603409B37E177004D48522D6209E183002A9A90330DEEDE7FBA5222A5C96845CE435F7770290FC62F639753FC109DDAC53D1728686507C1B55B6C397D2F82D8DC6A7DCFA0EBAD3EA1A2BA8EFF1404698467FFC37F0AD07F4FC56160EE298C31C80FB782A50C7DDB083AA807947855DBF4992F2B76FE4CB1AF04FCBF062DFB4293FA7D6AC19B1A3B8124788982CABD885DCE6215F5C3C74B706509C36A239FB42970CA7F1F7F1DA5DBF532DF36D81EDFA7CE3BAF1B8BEDD7F35065D7F303CCC7CAA80D3EFF30876D56C1B3E62188CF95EB3FAE0B1A39B2B68A9AE602E211B3414134649CF98F10FA777FB6B3B6E03814DF383E2742D3B5CEB00E70A1962710989E09D85549BE7CBFC1521FD2C559D6A10620BFF3D238B5C67BC6527EC7510C6FCEB39CD9D080C80C6968C81416BA630E035A55C5615C53A64EF04A9EEFA745044CADAEE9DF42956573F73303DF567128FBB3B405008053571E8963A067BF59F896B77F4D7DB4317FFB5997E04CEB0E07793EA06AE306F74317DC9D09EF2C47F25FD8618D3036B81E5C9F12D5E3E5F6278C163180A4CF40F559CB48A3260348EE0CE0DD5FE1A81F6CE3599665493466C0B19251659C186F1F2630C314D6EA2075612D09E820BAE06E027EB7AB361AC987E3CDCCA01365621FEE66F24BDB84F295CD7381CF15CAA767C37F722F44B8CB5BB879AC538130D1E7930636B176B395010726DA4D192BFB86F6FB0DCC2B384BC6B601682F2AB435D0DF35E8D14DA20B0979B822235E7BB2E9479FCCFD338A443F5DD52E4A317A954A76BB080482801F93182E6890E226392BD8A8872260681AA4FA1AD64DDB5977586F0570B51C052732CA743B4E3FC10DF04D5F99B4FEB21964AE907CAA914243EC817ECBF2606389ADD6E4B89D3AA42BE4FDD97E54CF88A2C940995397E49F2167A8D229232D8E40AAC99D6B2CFD898E09A245E8CFAB837CDC48196B40F746DB4E3609A10D1E3BAB1D505DBFFF81DFC1343600F6AC67C47CFB86644F4E942C540F6605A2A8533B592BE658B03B0E77B71B7CA47C615B1B8991C43DB2FBBF5868F53CE0C15DDEDA9E4A387F179C8FF71025465A7F56D88CD742439A83724F5111CD5332DB50BF9C014EE0C46351B13411E141C1D87B8428F2211B91741BE5287CFFFB17045CC73DBD1ED7ABC5B89053A6360B8860468D38685D98ADC3FCB5DBF79EC54D79F082A7C5A0F14599CA2A8A6CE7C60F3683514F7B5C7947500E51A54BAD3FC94CB591040121DED134FA77E01C32CDDE54EFDCFE189E481C96AED427485B869C381819BE6CC48D29D91163BC10D679DBC7F8FEFB12FB2187FC26B4F2E0AD995FFC29DA395E3532CB30D7E474F2CE3BFEC83B23CB784FCE7EEC427E90BAFB231037E7FFBE0569154A19175A37AC0DA60720E9D19C249B6E6BF4CA44C1B7453D09ED37E73A6BB69B4EFAD6BAEB938531470FFE7ACF07DA382BDF797D773CF23D6C40E5A4AA5F778DADBF674177419879285AF618C130025819B672E10DC6FF16638782DD80DFC00E4A1684FE3DA79C08C4DD0A267B1525414EEE6CDB64816DB56F080799993E5C8E02DDEB8AAE9A1274E457C6129C44B6641FD6D7C6617C6DECC279C02444D0ADDEC856454674F47FE3218535A674FCFBCE801DC5C94CBC8971CDD2375CA39278A5009B3965F60F22F0ADB244774B067088087BEDCC062CE62DAC57B6DA19EBC928DE33CB75D81117CABF26589D0E47E0AB42BEC26F5ED3F449879F9F4077FD67F5547106A8D4C03198A2A5EE53B5DB056AB9C9F1E2A9D5E649CFE9CBEE585188DB4E8BAE2C492B313273FECED665ABEC061C77A52297D353C718B4B104CC845AA24828E3EC939B80A5C1B14AA1B51441641C79C3427CC9D75285E36BBFD4CC7B028AB7726DF7583B7EC1969F3F961164331BC718760DACDCF5A7123DB3C2462AC611B773E60F3D9131826589B72A18F3E9A19BA7DEBA5D06BBCD4EDFB6BE918479ED6497CE84E2309E13886FC02A966F0293B8379B47A4BF01F11EDF76BE8161925550CD2F4F53C4A4A67A8D4F76DBA13C3F1A27E91DB392666FF93D3AE88AC5FE6786228BCAAE200EA1FD329297449A1C768F9D28D36BB1C79DA60DD696A3ACB65A83820C96BC61612A7CB1D85739BBB33486DB56D20FBA4A16C42AEDAAB01400AEB78EC92C148121B5ED813B12FF5997C6833259C5B1481402972DA98A3D91419BA7BC9CB2DB3FF10FBA266B9C836C7C8E215E30EBEC76D33D6715E1F79E1DCF8A5F49352934556D134EF7F4875FF19A2F01AD90735660E9D703CCD3DF9C263EEDC712390C10DA73E492C95282ADABC3992EBC112C33013F3CB25690ECBA1685D64E84B28348340FFCB1E20DBFFB671467EFE8D98BE3C3E2B97A063BCA499ABBC3AACDE57B8BCEB08F0027718A98A21F3A07EF99B41A698E723384B6AD54967754D587E3DAD55434C68C93E85C5D0E2A0D239C1B2D7E72EEB138E44E8D629D87C0BF67889331164FEB513BAA3DC2904955B4E0FE365482BE932F3540B3BDBB1DA3F50306B611DDAFBED08890999D945D179267490881F3AF3D0EF6699B62C4465B207A141DD9FBEC633066FBA60771BCD432356F2451D0ACEBCF2445E5BB3989EC54EA26A45AB692C9B646533EA3E9ED2989E268A8BAC53823A1A565A5CC1E996F20C1B27B2DCAB0A79B31CF9EC969A8DA2861C81FB20365CA3FF80E9CC7449CC36D6FDC197B6A227F4F8061AEB270624C61ED87AF17F64DFC4F54885F68203B373C10BDBC3C85FE42397B8DEC63B0C1B991B8BBEB5560B1583A6BC3DC07212A974E4C669B28A0B753889D25F5AE4A5664DE93F7DAB5C641C3621695CD47CD9B68438DCCE1ADA11BCB4695C1D50D3D7A2808D16991BFF51CF478C7A9A20E27CC4350FD2AC56DC6EAD6A60DD58417F5816D15BFDC8B4E7CD25F072C0D13CA5B968EA671582A766BB7D1E1E465BF6D9176D0E9224A6C94426663B409749B0B0BD8C1F1DFDE4BE4825810B6D2FF41384D9BE98DC7E8862E9BC2D53FA0FDEE99DEA4A25D52F2FA1D26B96571153373A9F0F900C9F185456B94EE8391572EC0D618DEA0B734E970BEDF11DB2EDE57A92E4D97B4B4DC020117527934DAF20852380C5059D8F044FAE4B445F7688FE2AE44E027364E28EC62AE6B6DF3938942B5ACA94923954FC44CA63B930703B95B61EFCA38AA521905EB954083B7DC328851F30FF734AA364EB7F4DB3A3653BD1FD5305ED041C4B94C3366D53BCD4C613250EBD99384E7E7DF2CAD649B7095A5DE27F34FF6A4F0917BEEAD403FA5F1BE8A651F562E5022D3D5100012F8F1FCAACD88224DE33661B0BBBB0A5AB19FCDFA111152C869944EEC0A8678402570E7D65CC20CA71572B9B57F88E4BCEFED603BE237E185313EA5E114F39380234E0CF0E4C49B3A81D59F31117233FFA92D45051BC04C92FA3CE23E2D37B4804BE2BA001748BFCFDD1E943F27648CE81252231433D705172B8B22AACF6BD3BEA3256585CC84289C79A1CF7AF2FE03A97AA39547F757771D6CC0388ACFE03D7E9590786335BCD0FEC1890D5712A3A62E33D887DBF23C80D47B0014FC9487D39A3324CFA92CA212BC29E9393E6FD5E6933BA2A6DB7934741BCF0F506DBC2B7F2194E386378137E0CCD8B3124B29BF47EBF89220787D778D6C2DC232B5A4C39CE9DC5743A1D80ECE67911BC6886C3F756BF7F4A59A27A3593D10D06F60AD71C8D69A69FF1CC1F17860F92877C5E0C75B9227FA13CCC86A9862B7D0BB849E0FB566E2430ACC639B8D5DD932D367A54E0101ED890C6AFB120419B8A04A4F1DE11C4030A398CF1A818F5433C8CCA0A67D52B1CFDC0B9E3643DD3D9E62147675345EDF1B9151CFDB52FD558AD99E4C3102BDDCFDB3B2FDDC7211F7827AAB7427DA19DFE86718F235D0280D3FF41AADD63F8E2628550293483E9835150ABEF10C6C98FA6EBBACEBA31BFA24A9DEF6B65F03CF1D462941DAB2F71FE09BC70C1566088C94DEBFEEE37483E76F3F5490A2CE86AA4C2D72ACA1CF7CDC2345309F1BDAB668E18DF7CA2FDCFB70E3476C086C48FB81B853894E2D238BA34540DCA2754BCF613B32B66AE60B715662648FF265341E10317A1423B7D195807476370D0527FF15CA1A255AB117357A8F6B18A502A27D154E1C84D0126026BD15F236A87C8F024DBFEC09DE837696A38FB55347AE877F46FF6F157EC6FC8D1846B7F55B1FB23DF3C97E42F48E63ABF64A992B4F77EC9DCCA1A329D84316155102E7F2F874AD369B64B3221A0BC852ABB69E1898D7364EABDFFBC94617448E257AD83112F87521857E2872E9895F2DEF3C5402DEB8F7F5450FADAFD47342907EC9642CC670FB1282BE2E1B31156F843F68BB77C29430708E91BF3988F9F4B9CE27F707828A67C2EDBF3B395500CCF71F31299C54601858C442EBD59185439C18F7EFDB83252BFBE193D65BEE7D150501832CF3E20AFAE4E936EBF635057670CE9FE5601A50BF518457DB36125ECF3FB77588E509A8A7D7A6F438AFC9AA7D103E2F2AF575EED551B1739A57CBE5AF4FD286AA870AA50B4E7457C11B2FA39F6F18BFBCD99188D0D06117197578DD2B7BE13016165B4CD7FA26D72CD6BF1B9C48D2BAD48802F26FBBE8AEE0F9E25E5D3309E03F72BD07E40C5F5788D46E62F29A4013104265BC855AD7809A2C800350FB140935EF3059B1B2AD54DD5FDB92DA429BA8AEB1D9A806D67DC7B6ED187DDD2B3F1084422D75B2C02BC242EDF4ACE0D478FCADCEC64523AC277E88F3823E050915190FC48EF6FE0897BD087B6BB2757A16AE27BCEE562A3C3955B88F82117428C73DF31862E9EDD8C8183F22DBA5A74A904AF45EDAB4AC057B8A470E5D48E277FC433B8E28851B51276728D6B0F06BC6C9E32BF06EAFC45704D7395A1F70AE27F160C7C7626047D030F8CB252D8B848CEA0D22E765B85A9431CAB3FA41C2BF939B56AC8E48D04AACBB6A62E2303E09A05AA6791F8E723B4BA8B021397C9918127E65EDC2A4EEC6B7CC5679B1BB08414FC4F2E49C2AA0F82750D07E3440A633F36BB107737DE269064725B5563DD7E49FF26508B14F29B1695F9E918B893B5D4FA04602A1688CA6BEADEE3F6BE2C0EA512624AE585396C930CDCF9E1D24F961241A421E035AE0034D4711641536F80BA8D8DBD1846216E8CE8702B794BBE1681A01C3AC79ACECE24B82DE63D60D48FBE9455359D397F0A6FEA1762920C6B976A83D4062CC19545201CD0D5A2F58312C01CAB6633521395358FA1044B6B5874DC913DC9A1CE930CE9B5EB39A87BD0DA73F5D7B237472C50C0979FD8E349752E1093CB658CFFD84592F90E0DC2CB3B957D81D80AE4C31A4906FB8DCA58835FCE16F6B3E3B6307FE4EA88BDCC466508E40F0439A3D84D1879281D460C35FA38C44D8856F684E5CFA5BACD411BF50DDBCB0F92D6133BA190627426B61694F3CC296C752E8CF0A916A1DAA336AF6DBF20BE34745DE3405AE15B2AF7D05A13DB27AB0549E3765DB2002DBB2432CA69DDCF90901B42C563DD33FBDB85D483EDF2A98931FB51274258323F5EE623B7E98954BC9AD4198CF3EEA950B2F3670A518B6C14404D9BC608B22C51F20E71FF22A13B870F11BB5FF80A9A32DD497565FFDDECBC45785EE65A14239E02A9C85D2AC0C41005BC932E137DE905FFD841268FC6E9093F911E5802EC1DF5EC68AF9277D85F90BBFDD470561AFBCF11552B52CE1ED64D281F073ACD51564367FE624870CB51B45066E98C305EA7BC6F9814F6487C3EA0C6EBB2912023E14D0C0D6223AB57F724135FBF553E2086E512CCDF095A0981F73BDAC5B27E68528758B15E5DC7F0B9C87946C1849D9861DA175FFEB27BB9080E6BDDD0820BF7077FA44E737D446E00F9645F82AB87625312D9BA244C15C9951DED33836182C892A54458DD090652613A3E1F53EB718E27EA344AA5930A4219EA1746D69E3BBE936652CFB0B94F5336B887E401A16496EB2312E5616FAB9CACA5B409FC5F41828FE2ADF32D6EBF6BCE8ABC1A3057B8E3EFA886C97630102587EF316D740A9D55E7BE8ECD4890D7F1B66A421DA4004A42EBFB9B98BE0FE01D409F319CE066EE2521063D9AD0136906B2D3039418F2334D10A85E217EB07CB5F6CFAEE42F7D59E7896DB6476A9F250279F5F7AAAB0A92198D795172B0541BBCB6F6EC8CB7E70D130F43BB2596E7CC50A9CF06FAEFD08DB1D8443D0C9918C17F3A577063EAC3A628C48FFE6CE48E484056187B6B7275FE62AB168BC60AA8AAA39CB47DA5E8E489083B5C90CF63005093B7E4C822E4AAEB03D8BD477C02876FBBA9C5CDF8F0805AFC962F43F342EEF53D531E964C4E9AAF08A0917FC8E2D2E896345583A48B556D3586877F3B7241E5F28648744BE752A029E4868B3D0BE4149C0E9A9C59B469664813513F99B1FA552B271B5251F1F91FC53B5C5982586C41D8F201C8FB187ED60332797D2BBAF27003E09EFB2A3A6053094F29175E709D4B445E3D6A65F1DE85789D1DA9E84DA5548A678D37A9C48C85F9E2B1C652ABA789B9BA004D7AF8D59BC61CE996F48227DE35914D7A44348C2F33EE039FFD855BE89FC08298CD77B77A35BEFB81AFEBCEF5BFC136263AD34027F679AC2CB2973EADE129CD5151C082944D9B795C107773248751231574E34E48976F7DE2736D11571D7A6BBFC263DABF8F9C230B26602F7489A920E12149ADE320E48E2961E9925708DD638FEC9B3EED0102188F608136E266863AECD63792732B1921B635C322BC26E2B779239D9583BEA245F62314299791E162A54751FC319FEFC2D96CD514A9472B4BE5828ED1C054126A3119EF75AA3ED1AD3F7A43E9C0920F82D1AE7344C8F31989EA355330BF8DD6C494962FE48635C2A8E8B94BD6CF5EC260E24BC838090A1DDCF33CC6DCE23D6F4075FD9607A59ABEF12FDE27818E19D91347F3A07C825B64D9FE609E1D5E4CABF5CBF59EF536C9DFE23766688572ABB728308A81AF112EDE97D1BDDBA446CBB5F66D503250E9579CE0CCE7B8F81BBD3C4A517F20DA10B4CCD8767DBEE2D7329904EEEAA8B885B012BDEB288584C41ECC9643EC2DEB7BE58D99BA093862A3CA973275264C5FA7E9FCCE66E34A87C9687CD398256BE95001C8BF18748CD64094DFB89317CC1750098E84AACB23AEA6EF8FA882296EEFD6982DD86C37E5707356FE0E6264EBA15480D15245EBA707684A47124D8837BB998B04341183B126222D4BFD23BF8BF1154C74BD9AE9AC4F1A2F6349EDDDE331043F2D8E524AB7A31C72BC5358215274AD529134901FE1FE105981E5ECA8009106DADFB35F7B7283FB9D9B43053E7030B04E31AF4AC1AC3289FC38905F3667A2E088E0558B08FD0D35688308C8DBEBC604B1D91EF8FC30333E21EB32AD3C0B8F159D4999535F117A0C77E9A8E15111F40CA9BC36B87725C18DEB78672F022C9C7D1589BD1392B39210B899F9435DF28B354380C9716C4E78938C99DE079625E39416776556C957109E89C81BE8439C37B2A33032F89DC505C7451F6865896F61CEAD50E64B7493131CA63E2AA4D3AC4BA1A7DFAB900C8EB7AAFC8D192D35CAD83A8E0A00322A0496BC1AC609FC030286CD20BBF1B2B62E7A98A10BB49A7AF2B98825F2B2A30C4361010CFC342E99E905ACF9E23D51275AC5655CFF53372D386ACBE4D43001B6BB46729663D6ADF641B00BEB312A85F0EFDBF4C2C86967FBEA0518CCC9CE9C063312E183BEABFD35497346297F5CDD8E289EA2859D0FB1AB4E54F41C38F1BE95E8177FF8D9276C00AD3CFD6BBC587B1EDB59FEA80EB5F513CFC315459E953B7DFF7F0424C86D29A6108CE0836216E15BB8659FD6D84FE2B55F01A4966F7119379A29110BDE2BC880DD70DF26B4270944C0FFACD1A048FB4E4516AA8129E049A745B6B34619794606F7555DDA876B5BAD91457D4694FC3CEBC3AE24945A52346EDF39C4D3126C652B819F6E85973B3C77ACD1D0AF1C61124556601F16E6A989136843D5C914FCC6EE481EE33ED2D79F7C5625309DED0A6A6C615EA4DC2A01F6E2039BE88361913EB0DD1E2CFFFBE3BC4ED6DDA93D1AD89D82232B314B144C2014B6C689816AB1511445AC0F50EE7D445F3054E35A8120536E86E5E130E85772D98012B69861A5BF739077383F5B7AA6A1AC7563C2C47E7833837C3449B0B6E6FCC0BAB2CBADB6EE8673591FE7343DF1974B174A9839036F9568F5F99F7B86965AE4B81A2DF277BB0598D5CE459C0727A23A4271F0EB83A7D4F6C055CA85C3D1F78F4D692C3688F5B618F779A24C03C6869BD2D5B9611526B12E1CF202325DCF316EC225B48A3353AB0D3DE412C4C486C1E3816BAE2AC9BBEF4206C3C3F976B8E10AFC72ABB6EE6591F3EED911AFC4275C3789486D67E46E33145574AAC0FD789E16EF7D88D385950309A8387973F608B6D948ADEB51B46281AFABEA8B8301281C6B0AA3653F7374380AA6984D77231F0D34B43158BA581109858E4344EA36ED73D16DD01E1B4FFECE15ADF96AC0C67EA8A2FAE36E57979C0C6A32923A5DD067618817E5A160DA7D5BB3C039D7775E060181176B73895065B051727F32E86AFE951EAB4B4949DA5B2E417D8DF2B8084564AE2C236A6E1DE5664BB1112A0CC9F6AF10F553F31B7C034E142B1E8C185DBD11038B79340926F4BA8D19C8F06F4D03232660DC978B2332EB45C1D17C89B7AF821CFE5462F4E7231354C0B0D6D64BD58D1837A31C8CF720CBE563CA12FC58925CEE387B06BED84E0BB062CF1DB2C87A37AA8F48B9D930AE4F7593BA1AFAF7F12C9A395B75170CE54979E0E19C89704D501D11F93911A8BDFD54A0ECF81402A0419FDDDED13D509537A59E02AF373A26AD0D3A0E110D0DEEA1B86DFBB9B545FDA6459798277949F17AD3E2A6509A78C778853828ED7B31EA6A0BE20AB3034879AE6CC8305DEA9E8B67796089A33E3B19806DCFCF7B8ACB76513D4FD38F3F6AFF4DB07E2701F6E5624C91C32CCFD626A6BA31DC166EE6D755FE699373EC68B19AB6F285F12FAB4C4F1CE2F8C7A2DBAC4E4D723185A4F64E18DC9B2651C52B843B4D96DFE8CF822A95820EA5CA271E2D427B70FB599167B9D8CBBFB5BF1162B4610E916EDD792B31314C7A777E4E7089F29E506B9A22988929D272F289D1CFBEEDEEDFEC28FEB379A67F43EC0BBD3BAE4EE2F8399B8147FC58AAF42A80F760B5105871AD5B941393BB5E71EB5333B8A7A708263F0D9A6042C5975E8C94A9DEB587A5343DCFCBBE36F7DF70E14D1F04C5124CD40B7B20BB0ACAF008626EC65F8F473D61EA2B336B512343C52941A6F98DAC0A543697E6122D09D833D8E3C5F2D7690BF7587166759579D5F3B0C26EBF4608CC846BCEF2B7366ABE3C1BFE28610FA94949D4F5512175180AEE782045C9BEE2C168A5CE23BE2FBA0AA47156F21F77FD11C135141DB40BE87028CACC12FCA3BC19CF83D17DF6E14DF931ADE786AB70137BD60F9A12CECA9F009115D3D429084500B5B1A82B31FADA1648557BAFF81FA4AB322C554D4EC38422917D31AE5225BAAB5D0A8053587E1A2C4778BEEF9178248BFA3E6DAC8E4748D9EB9A448D8ACC4979C77B5FAC477150DD8835A6E7D882BCDA0BB10095E0F1747439354B5C17476F6F7156F85981BE703529A3AE55881A2E99831A4379FC3F1CAB5AB00DB3B340722C5128021EFFD76C9CA7480384AFE80E720F8B0B53B8A127791B39E195F8427E8576182F67F794AEA65FA16F61F86E3C493A45FCE18DF03F8286CF1487CD9C4D792A2EE4AE9BDBB834B943CA042212289F59221340C2D85AAD6C71FC0F66FF2B6C1B60957D8410007657F085C9E442342B8A25B9E7F608085FAA744C9B37B4799BBB5892A3CFA40AC8B63A89E0CDA120BE8D9DF40E1F074A3053D8448514DD4C71C58A8FAF66B2A576E3A3EDA77DB4271B3ABBCE7B8B4BE12EB58EE9FBE6F676DFFA640EE40D01551348A412DBE0506935345347B471794B549361953550C70CC5373E3249D6D6D7BD8758D80ABEA6DAD9662DA44B09BA1326057CB2099330320725A8BA690906546609C6998469E122797E35399EA2CC1936D467D30FC55E6E24DAC353AE2F461C928B1D7EBDE9B489BFF98EC3E13136693586448A554DED33F3E9BC9AE091534C634659A97E5ABDB8B49E9E23BBBFD75E577910350F33C7901C67FC19E6ADC30C02104C17234369D3EC5A4021BDBFE331E19C2C1B6E9F2DA334FF06EFBD9E382352FF0822814AAA437D75BAD4C9E83E50BCA3053DFDAD299D13B0383BD80448189E909F30D95B3D9783DE643C4D4829B40C52234915B36DEC34E369FCCFB9AE6F6DFD2B8FB846BF82F6CD624CEA7F0CBC95B10D8FA91B9E288F635D3AE874C2D664B167E9D06AED4D618DEFE7A3F9902BBFCA86992A1ED9BCC408085704F039026405C29EC9371578F09DEDAEE3ECE92A5ADEBEE2A895BA7989F0D2E075AE9765C81E21B7FBDC8300B6D50A934D313448ECFA0AD73470038E6C1EC0D80A7A15C21096A1BC1F08A6ACE3B7200C3E8F8846B28848ABC36E8C0D03CB2E3F791C4FFA311EAD9809F1BB3B4D0894E3F4E446EAD18659DFFE69FC7F0C7DE9CC5DCE2C7D41E4A7BBA529B325E8F5857130AD8717C4DFA86279E959B0916D4E66A70DD98FC23F5DF15CB7DD6B8B550B060BFB23E0822D33FBFCB10B35EFE07C104D8A2D5C19D5D55A036761C83C78E509A4758A567FDB0720FF17CDDCB07BB607D726701418C0C8E6753EA8407A03E4E1DFBE0FBCDA3E06DFF57F1308019CC73BE4225B17A245782A93E029A8552E88CAF83FF45FC15F62DBF001E444F37500416229815BE02A9D069FD91DAC3
exponent:-352674
) < (LongFloat readFrom:'1q-500')
4.0 asLargeFloat < 4.5 asLargeFloat
4.1 asLargeFloat < 4.2 asLargeFloat
4.1 asLargeFloat < 4.0 asLargeFloat
4.0 asLargeFloat < 8.0 asLargeFloat
1.0 asLargeFloat < 2.0 asLargeFloat
1.0 asLargeFloat < 1.0 asLargeFloat
1.0 asLargeFloat > 1.0 asLargeFloat
1.0 asLargeFloat = 1.0 asLargeFloat
2.0 asLargeFloat < 1.0 asLargeFloatfalse
3.0 asLargeFloat < 1.0 asLargeFloat
3.0 asLargeFloat < 2.0 asLargeFloat
5.0 asLargeFloat < 500.0 asLargeFloat
499.0 asLargeFloat < 500.0 asLargeFloat
5.0 asLargeFloat < 7.0 asLargeFloat
5.0 asLargeFloat < 17.0 asLargeFloat
"
"Modified (comment): / 17-07-2017 / 16:38:59 / cg"
"Modified: / 27-05-2019 / 16:39:49 / Claus Gittinger"
!
productFromLargeFloat:aLargeFloat
|otherMantissa otherExponent|
otherMantissa := aLargeFloat mantissa.
otherExponent := aLargeFloat biasedExponent.
otherMantissa == 0 ifTrue:[
otherExponent ~= 0 ifTrue:[
"/ INF or NaN
aLargeFloat isNaN ifTrue:[^ NaN].
self negative ifTrue:[^ aLargeFloat negated].
^ aLargeFloat
].
].
mantissa == 0 ifTrue:[
biasedExponent = 0 ifTrue:[^ self].
"/ INF or NaN
self isNaN ifTrue:[^ NaN].
aLargeFloat negative ifTrue:[^ self negated].
^ self
].
^ self class
mantissa:(mantissa * otherMantissa)
exponent:(biasedExponent + otherExponent)
precision:(self precision min:aLargeFloat precision)
"
5.0 asLargeFloat * 4
(5.0 asLargeFloat precision:20) * 4
"
"Modified (comment): / 17-07-2017 / 14:50:42 / cg"
"Modified: / 27-05-2019 / 16:48:58 / Claus Gittinger"
!
quotientFromLargeFloat:aLargeFloat
"Return the quotient of the argument, aLargeFloat and the receiver.
(i.e. divide aLargeFloat by self)
Sent when aLargeFloat does not know how to divide by the receiver."
|otherMantissa otherExponent otherPrecision q e pMin limit prec n|
otherMantissa := aLargeFloat mantissa.
otherExponent := aLargeFloat biasedExponent.
otherPrecision := aLargeFloat precision.
otherMantissa == 0 ifTrue:[
otherExponent = 0 ifTrue:[^ aLargeFloat].
"/ INF or NaN
aLargeFloat isNaN ifTrue:[^ NaN].
self negative ifTrue:[^ aLargeFloat negated].
^ aLargeFloat
].
mantissa == 0 ifTrue:[
biasedExponent = 0 ifTrue:[^ self].
"/ INF or NaN
self isNaN ifTrue:[^ NaN].
aLargeFloat negative ifTrue:[^ self negated].
^ self
].
pMin := (otherPrecision min:precision).
pMin isFinite ifFalse:[
pMin := DefaultPrecision.
].
"/ (m1 * (2^e1))
"/ -------------
"/ (m2 * (2^e2))
"/ (m1/m2) * (2^(e1-e2))
e := (otherExponent - biasedExponent).
q := (otherMantissa / mantissa).
q isInteger ifFalse:[
"/ now q must be made an integer with at least pMin bits
q := (otherMantissa bitShift:pMin) / mantissa.
e := e - pMin.
q := q asInteger.
(n := q lowBit - 1) > 0 ifTrue:[
e > 0 ifTrue:[
q := q rightShift:n.
e := e - n.
] ifFalse:[
q := q rightShift:n.
e := e + n.
].
].
"/ limit := pMin.
"/ prec := 0.
"/ [ q isInteger or:[ limit >= 0 ]] whileTrue:[
"/ q := q * 2. e := e - 1.
"/ prec := prec + 1.
"/ limit := limit - 1.
"/ ].
"/ q isInteger ifFalse:[
"/ pMin := prec.
"/ q := q asInteger.
"/ ].
].
^ self class
mantissa:q
exponent:e
precision:pMin
"Modified: / 10-10-2017 / 15:57:06 / cg"
"Modified: / 27-05-2019 / 16:40:09 / Claus Gittinger"
!
sumFromLargeFloat:aLargeFloat
|otherExponent otherMantissa e m|
otherExponent := aLargeFloat biasedExponent.
otherMantissa := aLargeFloat mantissa.
otherMantissa == 0 ifTrue:[
otherExponent = 0 ifTrue:[^ self].
"/ INF or NaN
aLargeFloat isNaN ifTrue:[^ NaN].
self isFinite ifTrue:[^ aLargeFloat].
aLargeFloat sign == self sign ifTrue:[^ aLargeFloat].
^ NaN
].
mantissa == 0 ifTrue:[
biasedExponent = 0 ifTrue:[^ aLargeFloat].
"/ INF or NaN
self isNaN ifTrue:[^ NaN].
^ self
].
otherExponent = biasedExponent ifTrue:[
m := otherMantissa + mantissa.
e := biasedExponent
] ifFalse:[
otherExponent> biasedExponent ifTrue:[
m := (otherMantissa bitShift:(otherExponent-biasedExponent)) + mantissa.
e := biasedExponent
] ifFalse:[
m := otherMantissa + (mantissa bitShift:(biasedExponent-otherExponent)).
e := otherExponent
]
].
^ self class
mantissa:m
exponent:e
precision:(self precision min:aLargeFloat precision)
"Modified: / 27-05-2019 / 16:40:13 / Claus Gittinger"
! !
!LargeFloat methodsFor:'mathematical functions'!
ln
"Answer the neperian logarithm of the receiver."
| x4 one two p res selfHighRes prec e |
self <= self zero ifTrue: [DomainError signal: 'ln is only defined for x > 0.0'].
one _ self one.
self = one ifTrue: [^self zero].
two _ one timesTwoPower: 1.
"Use Salamin algorithm (approximation is good if x is big enough)
x ln = Pi / (2 * (1 agm: 4/x) ).
If x not big enough, compute (x timesTwoPower: p) ln - (2 ln * p)
if x is close to 1, better use a power expansion"
prec _ precision + 16.
e _ self biasedExponent. "/ exponent.
e < 0 ifTrue: [e _ -1 - e].
e > prec
ifTrue: [p _ 0]
ifFalse:
[p _ prec - e.
prec _ prec + p highBit].
selfHighRes _ self asLargeFloatPrecision: prec.
(selfHighRes - one) exponent * -4 >= precision ifTrue: [^(selfHighRes powerExpansionLnPrecision: prec) asLargeFloatPrecision: precision].
self < one ifTrue: [selfHighRes inPlaceReciprocal]. "Use ln(1/x) => - ln(x)"
x4 _ (4 asLargeFloatPrecision: prec)
inPlaceDivideBy: selfHighRes;
inPlaceTimesTwoPower: p negated.
res _ selfHighRes pi / (one agm: x4) timesTwoPower: -1.
res _ selfHighRes = two
ifTrue: [res / (p + 1)]
ifFalse: [p = 0 ifTrue: [res] ifFalse: [res - ((two asLargeFloatPrecision: prec) ln * p)]].
self < one ifTrue: [res inPlaceNegated].
^res asLargeFloatPrecision: precision
"Modified: / 27-05-2019 / 16:40:46 / Claus Gittinger"
! !
!LargeFloat methodsFor:'printing'!
printOn:aStream
biasedExponent == 0 ifTrue:[
mantissa printOn:aStream.
aStream nextPutAll:'.0'.
^ self
].
mantissa == 0 ifTrue:[
"/ a zero mantissa is impossible - except for zero and a few others
biasedExponent == 0 ifTrue:[ aStream nextPutAll:'0.0'. ^ self].
self == NaN ifTrue:[ aStream nextPutAll:'NAN'. ^ self ].
self == NegativeInfinity ifTrue:[ aStream nextPutAll:'-INF'. ^ self].
self == PositiveInfinity ifTrue:[ aStream nextPutAll:'INF'. ^ self].
self error:'invalid largeFloat' mayProceed:true.
aStream nextPutAll:'Invalid'. ^ self.
].
biasedExponent >= 0 ifTrue:[
(mantissa bitShift:biasedExponent) printOn:aStream.
aStream nextPutAll:'.0'.
^ self
].
((mantissa / (1 bitShift:biasedExponent negated)) asFixedPoint:6) printOn:aStream.
"Modified: / 10-10-2017 / 14:16:04 / cg"
! !
!LargeFloat methodsFor:'private'!
inPlaceAdd: b
| delta |
b isZero ifTrue: [^self roundToPrecision].
self isZero ifTrue:[
mantissa _ b mantissa.
biasedExponent _ b biasedExponent
] ifFalse:[
biasedExponent = b biasedExponent ifTrue: [
mantissa _ mantissa + b mantissa
] ifFalse:[
"check for early truncation. beware, keep 2 bits for rounding"
delta _ biasedExponent - b biasedExponent.
delta - 2 > (precision max: self precisionInMantissa) ifFalse:[
delta negated - 2 > (precision max: b precisionInMantissa) ifTrue:[
mantissa _ b mantissa.
biasedExponent _ b exponent
] ifFalse:[
delta _ biasedExponent - b exponent.
delta > 0 ifTrue:[
mantissa _ (self shift: mantissa by: delta) + b mantissa.
biasedExponent _ biasedExponent - delta
] ifFalse: [
mantissa _ mantissa + (self shift: b mantissa by: delta negated)
]
]
]
]
].
self roundToPrecision
"Created: / 26-05-2019 / 03:44:50 / Claus Gittinger"
"Modified: / 28-05-2019 / 08:49:15 / Claus Gittinger"
!
inPlaceAddNoRound: b
| delta |
b isZero ifTrue: [^self].
self isZero ifTrue:[
mantissa := b mantissa.
biasedExponent := b biasedExponent.
^ self.
].
delta := biasedExponent - b biasedExponent.
delta isZero ifTrue: [
mantissa := mantissa + b mantissa
] ifFalse:[
delta > 0 ifTrue: [
mantissa := (self shift: mantissa by: delta) + b mantissa.
biasedExponent := biasedExponent - delta
] ifFalse: [
mantissa := mantissa + (self shift: b mantissa by: delta negated)
]
]
"Created: / 26-05-2019 / 03:41:29 / Claus Gittinger"
"Modified: / 27-05-2019 / 16:39:21 / Claus Gittinger"
!
inPlaceCopy: b
"copy another arbitrary precision float into self"
mantissa := b mantissa.
biasedExponent := b biasedExponent.
precision := b precision
"Created: / 26-05-2019 / 03:39:04 / Claus Gittinger"
"Modified: / 27-05-2019 / 16:39:24 / Claus Gittinger"
!
inPlaceDivideBy: y
"Reference: Accelerating Correctly Rounded Floating-Point Division when the Divisor
Is Known in Advance - Nicolas Brisebarre,
Jean-Michel Muller, Member, IEEE, and
Saurabh Kumar Raina -
http://perso.ens-lyon.fr/jean-michel.muller/DivIEEETC-aug04.pdf"
| zh x q |
zh := y reciprocal normalize.
x := self copy.
self inPlaceMultiplyBy: zh.
q := self copy.
"r := "self inPlaceMultiplyBy: y negated andAccumulate: x.
"q' := "self inPlaceMultiplyBy: zh andAccumulate: q.
"ALGO 4
| zh r zl |
zh := b reciprocal.
r := b negated inPlaceMultiplyBy: zh andAccumulate: (1 asLargeFloatPrecision: precision).
zl := (b asLargeFloatPrecision: precision + 1) reciprocal inPlaceMultiplyBy: r.
self inPlaceMultiplyBy: zh andAccumulate: (zl inPlaceMultiplyBy: self)"
"Created: / 26-05-2019 / 03:38:41 / Claus Gittinger"
"Modified: / 27-05-2019 / 10:12:13 / Claus Gittinger"
!
inPlaceMultiplyBy:b
self inPlaceMultiplyNoRoundBy:b.
self roundToPrecision
"
2.4 asLargeFloat inPlaceMultiplyBy:2.0
"
"Created: / 26-05-2019 / 03:37:36 / Claus Gittinger"
"Modified: / 28-05-2019 / 08:49:04 / Claus Gittinger"
!
inPlaceMultiplyBy:b andAccumulate:c
"only do rounding after the two operations.
This is the traditional muladd operation in aritmetic units"
self inPlaceMultiplyNoRoundBy: b.
self inPlaceAdd:c
"
2.4 asLargeFloat inPlaceMultiplyBy:2.0 asLargeFloat andAccumulate:10.0 asLargeFloat
"
"Created: / 26-05-2019 / 03:37:16 / Claus Gittinger"
"Modified (comment): / 27-05-2019 / 16:35:43 / Claus Gittinger"
!
inPlaceMultiplyNoRoundBy:b
mantissa := mantissa * b mantissa.
biasedExponent := biasedExponent + b biasedExponent.
"
2.4 asLargeFloat inPlaceMultiplyNoRoundBy:2.0
"
"Created: / 26-05-2019 / 03:36:00 / Claus Gittinger"
"Modified: / 27-05-2019 / 16:39:27 / Claus Gittinger"
!
inPlaceNegated
"destructive"
mantissa := mantissa negated
"Created: / 26-05-2019 / 03:34:34 / Claus Gittinger"
!
inPlaceReciprocal
| ma h |
self isZero ifTrue: [(ZeroDivide dividend: self) signal].
ma := mantissa abs.
h := ma highBit.
mantissa := (1 bitShift: h + precision) + ma quo: (self shift: mantissa by: 1).
biasedExponent := biasedExponent negated - h - precision + 1.
self roundToPrecision
"Implementation notes: if m is a power of 2, reciprocal is trivial.
Else, we have 2^h > m >2^(h-1)
thus 1 < 2^h/m < 2.
thus 2^(n-1) < 2^(h+n-1)/m < 2^n
We thus have to evaluate (2^(h+n-1)/m) rounded
Tie is away from zero because there are always trailing bits (inexact op)
(num/den) rounded is also ((num/den)+(sign/2)) truncated
or (num*2)+(sign*den) quo: den*2
That's finally what we evaluate"
"Modified: / 28-05-2019 / 08:48:59 / Claus Gittinger"
!
inPlaceSqrt
"Replace the receiver by its square root."
| guess guessSquared delta shift |
self negative
ifTrue:
[^ DomainError signal: 'sqrt undefined for number less than zero.'].
self isZero ifTrue: [^self].
shift _ 2 * precision - mantissa highBit.
biasedExponent _ biasedExponent - shift.
biasedExponent odd
ifTrue:
[shift _ shift + 1.
biasedExponent _ biasedExponent - 1].
mantissa _ mantissa bitShift: shift.
guess _ mantissa bitShift: mantissa highBit + 1 // 2.
[
guessSquared _ guess * guess.
delta _ guessSquared - mantissa quo: (guess bitShift: 1).
delta = 0 ] whileFalse:
[ guess _ guess - delta ].
guessSquared = mantissa
ifFalse:
[(guessSquared - guess - mantissa) negative ifFalse: [guess _ guess - 1]].
mantissa _ guess.
biasedExponent _ biasedExponent quo: 2.
self roundToPrecision
"Modified: / 28-05-2019 / 08:48:55 / Claus Gittinger"
!
inPlaceSubtract: b
| delta |
b isZero ifTrue: [^self roundToPrecision].
self isZero
ifTrue:
[mantissa _ b mantissa negated.
biasedExponent _ b biasedExponent]
ifFalse:
[biasedExponent = b biasedExponent
ifTrue: [mantissa _ mantissa - b mantissa]
ifFalse:
["check for early truncation. beware, keep 2 bits for rounding"
delta _ biasedExponent - b biasedExponent.
delta - 2 > (precision max: self precisionInMantissa)
ifFalse:
[delta negated - 2 > (precision max: b precisionInMantissa)
ifTrue:
[mantissa _ b mantissa negated.
biasedExponent _ b biasedExponent]
ifFalse:
[delta _ biasedExponent - b biasedExponent.
delta >= 0
ifTrue:
[mantissa _ (self shift: mantissa by: delta) - b mantissa.
biasedExponent _ biasedExponent - delta]
ifFalse: [mantissa _ mantissa - (self shift: b mantissa by: delta negated)]]]]].
self roundToPrecision
"Modified: / 28-05-2019 / 08:48:46 / Claus Gittinger"
!
inPlaceSubtractNoRound: b
| delta |
b isZero ifTrue: [^self].
self isZero
ifTrue:
[mantissa _ b mantissa negated.
biasedExponent _ b biasedExponent]
ifFalse:
[delta _ biasedExponent - b biasedExponent.
delta isZero
ifTrue: [mantissa _ mantissa - b mantissa]
ifFalse:
[delta >= 0
ifTrue:
[mantissa _ (self shift: mantissa by: delta) - b mantissa.
biasedExponent _ biasedExponent - delta]
ifFalse: [mantissa _ mantissa - (self shift: b mantissa by: delta negated)]]]
!
inPlaceTimesTwoPower: n
self isZero
ifFalse: [biasedExponent _ biasedExponent + n]
!
mantissa:mantissaArg exponent:exponentArg
"set instance variables.
Notice, that the float's value is m * 2^e"
biasedExponent := exponentArg.
mantissa := mantissaArg.
precision := self class defaultPrecision.
self normalize.
"Modified (comment): / 17-07-2017 / 14:50:14 / cg"
"Modified: / 28-05-2019 / 09:20:11 / Claus Gittinger"
!
mantissa:mantissaArg exponent:exponentArg precision:precisionArg
"set instance variables.
Notice, that the float's value is m * 2^e"
biasedExponent := exponentArg.
mantissa := mantissaArg.
precision := precisionArg.
"/ self round "/ normalize
"Modified (comment): / 17-07-2017 / 14:50:10 / cg"
"Modified: / 27-05-2019 / 16:33:31 / Claus Gittinger"
!
moduloNegPiToPi
"answer a copy of the receiver modulo 2*pi, with doubled precision"
| x pi twoPi quo |
x _ (self asLargeFloatPrecision: precision * 2).
self negative ifTrue: [x inPlaceNegated].
pi _ x pi.
twoPi _ pi timesTwoPower: 1.
x > pi ifTrue:
[quo _ x + pi quo: twoPi.
quo highBitOfMagnitude > precision ifTrue:
[x _ (self abs asLargeFloatPrecision: precision + quo highBitOfMagnitude).
pi _ x pi.
twoPi _ pi timesTwoPower: 1.
quo _ x + pi quo: twoPi].
x inPlaceSubtract: twoPi * quo.
self negative ifTrue: [x inPlaceNegated]].
^x asLargeFloatPrecision: precision * 2
!
normalize
"adjust m & e such that m is the smallest possible
(i.e. has no least significant zero bit).
Notice, that the float's value is m * 2^e"
|shift|
shift := mantissa lowBit - 1.
shift > 0 ifTrue:[
mantissa := mantissa bitShift:shift negated.
biasedExponent := biasedExponent + shift
].
"
self mantissa:1 exponent:0
self mantissa:2 exponent:0
self mantissa:4 exponent:0
self mantissa:8 exponent:0
self mantissa:10 exponent:-1
self mantissa:10 exponent:0
self mantissa:10 exponent:1
self mantissa:-10 exponent:1
"
"Modified (comment): / 26-05-2019 / 03:34:00 / Claus Gittinger"
!
precision:precisionArg
"set instance variables.
Notice, that the float's value is m * 2^e"
precision := precisionArg.
self normalize
"Created: / 17-07-2017 / 14:50:04 / cg"
!
precisionInMantissa
"this is equal to precision only if we are normalized.
If we are reduced (low bits being zero are removed), then it will be less.
If we haven't been rounded/truncated then it will be more"
^ mantissa highBitOfMagnitude
"Created: / 26-05-2019 / 03:45:02 / Claus Gittinger"
!
roundToPrecision
"destructive inplace round
apply algorithm round to nearest even used by IEEE arithmetic"
"inexact := ma lowBit <= excess."
| excess ma carry |
mantissa isZero ifTrue: [
biasedExponent := 0.
^ self
].
ma := mantissa abs.
excess := ma highBit - precision.
excess > 0 ifFalse: [ ^ self ].
carry := ma bitAt: excess.
mantissa := self shift: mantissa by: excess negated.
biasedExponent := biasedExponent + excess.
(carry = 1 and: [ mantissa odd or: [ ma lowBit < excess ] ]) ifFalse: [ ^ self ].
mantissa := mantissa + mantissa sign.
self truncate
"Created: / 28-05-2019 / 08:49:25 / Claus Gittinger"
!
shift:m by:d
"shift mantissa m absolute value by some d bits, then restore sign"
^m negative
ifTrue: [(m negated bitShift:d) negated]
ifFalse: [m bitShift:d]
"Created: / 26-05-2019 / 03:22:12 / Claus Gittinger"
! !
!LargeFloat methodsFor:'queries'!
decimalPrecision
"return the number of valid decimal digits"
^ ((self precision + 1) / (10.0 log:2)) ceiling "use ceiling, since the last decimal digit contains some precision"
"
1 asShortFloat decimalPrecision
1 asFloat decimalPrecision
1 asLongFloat decimalPrecision
1 asLargeFloat decimalPrecision
"
"Created: / 10-10-2017 / 15:48:30 / cg"
!
epsilon
"return the maximum relative spacing of instances of mySelf
(i.e. the value-delta of the least significant bit)"
|p|
p := precision.
p isFinite ifTrue:[
^ self class radix asFloat raisedTo:(1 - p)
].
"/ mhmh - what should we use here for an infinite precision ???
^ 1e-300
"/ ^ LongFloat epsilon
"Modified: / 10-10-2017 / 15:55:12 / cg"
!
numBitsInMantissa
^ precision
"Created: / 28-05-2019 / 09:14:36 / Claus Gittinger"
! !
!LargeFloat methodsFor:'testing'!
isAnExactFloat
|myExponent|
myExponent := self biasedExponent.
^ myExponent <= Float emax
and: [Float emin - Float precision < myExponent
and: [precision <= Float precision or: [mantissa isAnExactFloat]]]
"Modified: / 27-05-2019 / 16:39:46 / Claus Gittinger"
!
isFinite
^ mantissa ~= 0 or:[biasedExponent = 0]
!
isInfinite
^ mantissa = 0 and:[biasedExponent ~= 0]
!
isNaN
^ self == NaN
!
isZero
^mantissa isZero
!
negative
"return true if the receiver is negative"
mantissa == 0 ifTrue:[ ^ biasedExponent negative].
^ mantissa negative
!
sign
"return the sign of the receiver"
mantissa == 0 ifTrue:[
"special value for infinites"
^ biasedExponent sign
].
^ mantissa sign
! !
!LargeFloat methodsFor:'truncation & rounding'!
truncate
"remove trailing bits if they exceed our allocated number of bits"
| excess |
excess := precision - precision.
excess > 0 ifFalse: [ ^ self ].
mantissa := self shift:mantissa by:excess negated.
biasedExponent := biasedExponent + excess
"Created: / 26-05-2019 / 03:24:10 / Claus Gittinger"
!
truncated
"answer the integer that is nearest to self in the interval between zero and self"
^ biasedExponent negated > precision
ifTrue: [0]
ifFalse: [self shift: mantissa by: biasedExponent]
"
2.4 asLargeFloat truncated
2e34 asLargeFloat truncated
"
"Created: / 26-05-2019 / 03:21:52 / Claus Gittinger"
! !
!LargeFloat class methodsFor:'documentation'!
version
^ '$Header$'
!
version_CVS
^ '$Header$'
! !
LargeFloat initialize!