From 51bf1a0eeaddf2adb2a2f6df3e56f0efff23d30e Mon Sep 17 00:00:00 2001 From: John Jiang Date: Mon, 30 Dec 2024 16:19:07 +0800 Subject: [PATCH] TKSS-1020: Not re-create NativeSM4 instance after doFinal --- .../crypto/perf/SM4DecrypterPerfTest.java | 15 ++--- .../crypto/perf/SM4EncrypterPerfTest.java | 43 ++++++++------ .../provider/nativeImpl/NativeCrypto.java | 3 +- .../crypto/provider/nativeImpl/NativeSM4.java | 55 ++++++++++-------- .../crypto/provider/nativeImpl/SM4Crypt.java | 15 +++-- .../src/main/jni/include/kona/kona_jni.h | 12 +++- kona-crypto/src/main/jni/kona_sm4.c | 39 ++++++++++++- .../resources/libKonaCrypto-linux-aarch64.so | Bin 82512 -> 82608 bytes .../resources/libKonaCrypto-linux-x86_64.so | Bin 61128 -> 61224 bytes .../tencent/kona/crypto/provider/SM4Test.java | 39 ++++++++++++- 10 files changed, 155 insertions(+), 66 deletions(-) diff --git a/kona-crypto/src/jmh/java/com/tencent/kona/crypto/perf/SM4DecrypterPerfTest.java b/kona-crypto/src/jmh/java/com/tencent/kona/crypto/perf/SM4DecrypterPerfTest.java index 5b9e897a..40f2c0ce 100644 --- a/kona-crypto/src/jmh/java/com/tencent/kona/crypto/perf/SM4DecrypterPerfTest.java +++ b/kona-crypto/src/jmh/java/com/tencent/kona/crypto/perf/SM4DecrypterPerfTest.java @@ -64,7 +64,7 @@ public class SM4DecrypterPerfTest { @State(Scope.Benchmark) public static class DecrypterHolder { - @Param({"KonaCrypto", "KonaCrypto-Native"}) + @Param({"KonaCrypto-Native"}) String provider; @Param({"Small", "Mid", "Big"}) @@ -84,7 +84,7 @@ public static class DecrypterHolder { Cipher decrypterCTRNoPadding; Cipher decrypterGCMNoPadding; - @Setup(Level.Invocation) + @Setup(Level.Trial) public void setup() throws Exception { setupCiphertexts(); setupDecrypters(); @@ -138,8 +138,6 @@ private void setupDecrypters() throws Exception { decrypterGCMNoPadding = Cipher.getInstance( "SM4/GCM/NoPadding", provider); - decrypterGCMNoPadding.init( - Cipher.DECRYPT_MODE, SECRET_KEY, GCM_PARAM_SPEC); } } @@ -154,12 +152,7 @@ private static byte[] data(String dataType) { } @Benchmark - public byte[] cbcPadding(DecrypterHolder holder) throws Exception { - return holder.decrypterCBCPadding.doFinal(holder.ciphertextCBCPadding); - } - - @Benchmark - public byte[] cbcNoPadding(DecrypterHolder holder) throws Exception { + public byte[] cbc(DecrypterHolder holder) throws Exception { return holder.decrypterCBCNoPadding.doFinal(holder.ciphertextCBCNoPadding); } @@ -175,6 +168,8 @@ public byte[] ctr(DecrypterHolder holder) throws Exception { @Benchmark public byte[] gcm(DecrypterHolder holder) throws Exception { + holder.decrypterGCMNoPadding.init( + Cipher.DECRYPT_MODE, SECRET_KEY, GCM_PARAM_SPEC); return holder.decrypterGCMNoPadding.doFinal(holder.ciphertextGCMNoPadding); } } diff --git a/kona-crypto/src/jmh/java/com/tencent/kona/crypto/perf/SM4EncrypterPerfTest.java b/kona-crypto/src/jmh/java/com/tencent/kona/crypto/perf/SM4EncrypterPerfTest.java index a758edfa..77bf3fd5 100644 --- a/kona-crypto/src/jmh/java/com/tencent/kona/crypto/perf/SM4EncrypterPerfTest.java +++ b/kona-crypto/src/jmh/java/com/tencent/kona/crypto/perf/SM4EncrypterPerfTest.java @@ -29,6 +29,7 @@ import javax.crypto.spec.IvParameterSpec; import javax.crypto.spec.SecretKeySpec; +import java.math.BigInteger; import java.util.concurrent.TimeUnit; import static com.tencent.kona.crypto.CryptoUtils.toBytes; @@ -45,13 +46,10 @@ public class SM4EncrypterPerfTest { private static final byte[] KEY = toBytes("0123456789abcdef0123456789abcdef"); - private static final byte[] IV = toBytes("00000000000000000000000000000000"); - private static final byte[] GCM_IV = toBytes("000000000000000000000000"); + private static final byte[] IV = toBytes("10000000000000000000000000000000"); private static final SecretKey SECRET_KEY = new SecretKeySpec(KEY, "SM4"); private static final IvParameterSpec IV_PARAM_SPEC = new IvParameterSpec(IV); - private static final GCMParameterSpec GCM_PARAM_SPEC - = new GCMParameterSpec(Constants.SM4_GCM_TAG_LEN * 8, GCM_IV); private final static byte[] SMALL_DATA = TestUtils.data(128); private final static byte[] MEDIUM_DATA = TestUtils.dataKB(1); @@ -64,6 +62,8 @@ public class SM4EncrypterPerfTest { @State(Scope.Benchmark) public static class EncrypterHolder { + private BigInteger gcmIvValue = BigInteger.ZERO; + @Param({"KonaCrypto", "KonaCrypto-Native"}) String provider; @@ -72,21 +72,15 @@ public static class EncrypterHolder { byte[] data; - Cipher encrypterCBCPadding; Cipher encrypterCBCNoPadding; Cipher encrypterECBNoPadding; Cipher encrypterCTRNoPadding; Cipher encrypterGCMNoPadding; - @Setup(Level.Invocation) + @Setup(Level.Trial) public void setup() throws Exception { data = data(dataType); - encrypterCBCPadding = Cipher.getInstance( - "SM4/CBC/PKCS7Padding", provider); - encrypterCBCPadding.init( - Cipher.ENCRYPT_MODE, SECRET_KEY, IV_PARAM_SPEC); - encrypterCBCNoPadding = Cipher.getInstance( "SM4/CBC/NoPadding", provider); encrypterCBCNoPadding.init( @@ -104,8 +98,6 @@ public void setup() throws Exception { encrypterGCMNoPadding = Cipher.getInstance( "SM4/GCM/NoPadding", provider); - encrypterGCMNoPadding.init( - Cipher.ENCRYPT_MODE, SECRET_KEY, GCM_PARAM_SPEC); } } @@ -120,12 +112,7 @@ private static byte[] data(String dataType) { } @Benchmark - public byte[] cbcPadding(EncrypterHolder holder) throws Exception { - return holder.encrypterCBCPadding.doFinal(holder.data); - } - - @Benchmark - public byte[] cbcNoPadding(EncrypterHolder holder) throws Exception { + public byte[] cbc(EncrypterHolder holder) throws Exception { return holder.encrypterCBCNoPadding.doFinal(holder.data); } @@ -141,6 +128,24 @@ public byte[] ecb(EncrypterHolder holder) throws Exception { @Benchmark public byte[] gcm(EncrypterHolder holder) throws Exception { + holder.gcmIvValue = holder.gcmIvValue.add(BigInteger.ONE); + GCMParameterSpec GCM_PARAM_SPEC = new GCMParameterSpec( + Constants.SM4_GCM_TAG_LEN * 8, toByte12(holder.gcmIvValue)); + holder.encrypterGCMNoPadding.init( + Cipher.ENCRYPT_MODE, SECRET_KEY, GCM_PARAM_SPEC); return holder.encrypterGCMNoPadding.doFinal(holder.data); } + + private static byte[] toByte12(BigInteger ivValue) { + byte[] result = new byte[12]; + + byte[] iv = ivValue.toByteArray(); + if (iv.length >= 12) { + System.arraycopy(iv, iv.length - 12, result, 0, 12); + } else { + System.arraycopy(iv, 0, result, 12 - iv.length, iv.length); + } + + return result; + } } diff --git a/kona-crypto/src/main/java/com/tencent/kona/crypto/provider/nativeImpl/NativeCrypto.java b/kona-crypto/src/main/java/com/tencent/kona/crypto/provider/nativeImpl/NativeCrypto.java index b8070952..5018c2d7 100644 --- a/kona-crypto/src/main/java/com/tencent/kona/crypto/provider/nativeImpl/NativeCrypto.java +++ b/kona-crypto/src/main/java/com/tencent/kona/crypto/provider/nativeImpl/NativeCrypto.java @@ -184,7 +184,8 @@ private static void copyNativeLib(String libName, Path libPath) native long sm4CreateCtx(boolean encrypt, String mode, boolean padding, byte[] key, byte[] iv); native void sm4FreeCtx(long pointer); native byte[] sm4Update(long pointer, byte[] in); - native byte[] sm4Final(long pointer); + native byte[] sm4Final(long pointer, byte[] key, byte[] iv); + native int sm4GCMSetIV(long pointer, byte[] iv); native int sm4GCMUpdateAAD(long pointer, byte[] aad); native int sm4GCMProcTag(long pointer, byte[] tag); diff --git a/kona-crypto/src/main/java/com/tencent/kona/crypto/provider/nativeImpl/NativeSM4.java b/kona-crypto/src/main/java/com/tencent/kona/crypto/provider/nativeImpl/NativeSM4.java index 7f77c32c..ba2c1cd1 100644 --- a/kona-crypto/src/main/java/com/tencent/kona/crypto/provider/nativeImpl/NativeSM4.java +++ b/kona-crypto/src/main/java/com/tencent/kona/crypto/provider/nativeImpl/NativeSM4.java @@ -32,8 +32,20 @@ */ abstract class NativeSM4 extends NativeRef { + final boolean encrypt; + final Mode mode; + final boolean padding; + final byte[] key; + byte[] iv; + NativeSM4(boolean encrypt, Mode mode, boolean padding, byte[] key, byte[] iv) { super(createCtx(encrypt, mode, padding, key, iv)); + + this.encrypt = encrypt; + this.mode = mode; + this.padding = padding; + this.key = key; + this.iv = iv; } private static long createCtx(boolean encrypt, Mode mode, boolean padding, @@ -69,10 +81,6 @@ private static long createCtx(boolean encrypt, Mode mode, boolean padding, return nativeCrypto().sm4CreateCtx(encrypt, mode.name, padding, key, iv); } - NativeSM4(long pointer) { - super(pointer); - } - byte[] update(byte[] data) { Objects.requireNonNull(data); @@ -88,7 +96,7 @@ byte[] update(byte[] data) { byte[] doFinal() { byte[] result = pointer == 0 ? null - : nativeCrypto().sm4Final(pointer); + : nativeCrypto().sm4Final(pointer, key, iv); if (result == null) { throw new IllegalStateException("SM4 final operation failed"); } @@ -119,10 +127,6 @@ final static class SM4CBC extends NativeSM4 { SM4CBC(boolean encrypt, boolean padding, byte[] key, byte[] iv) { super(encrypt, Mode.CBC, padding, key, iv); } - - SM4CBC(long pointer) { - super(pointer); - } } final static class SM4CTR extends NativeSM4 { @@ -130,10 +134,6 @@ final static class SM4CTR extends NativeSM4 { SM4CTR(boolean encrypt, byte[] key, byte[] iv) { super(encrypt, Mode.CTR, false, key, iv); } - - SM4CTR(long pointer) { - super(pointer); - } } final static class SM4ECB extends NativeSM4 { @@ -142,10 +142,6 @@ final static class SM4ECB extends NativeSM4 { super(encrypt, Mode.ECB, padding, key, null); } - SM4ECB(long pointer) { - super(pointer); - } - void processBlock(byte[] in, int inOff, byte[] out, int outOff) { byte[] inBlock = new byte[SM4_BLOCK_SIZE]; System.arraycopy(in, inOff, inBlock, 0, SM4_BLOCK_SIZE); @@ -167,21 +163,32 @@ static class SM4GCM extends NativeSM4 { void updateAAD(byte[] aad) { Objects.requireNonNull(aad); - if (pointer != 0) { - nativeCrypto().sm4GCMUpdateAAD(pointer, aad); - } else { + if (pointer == 0 + || nativeCrypto().sm4GCMUpdateAAD(pointer, aad) != OPENSSL_SUCCESS){ throw new IllegalStateException("SM4 updateAAD operation failed"); } } - @Override byte[] doFinal() { - try { - return super.doFinal(); - } catch (IllegalStateException e) { + byte[] result = pointer == 0 + ? null + : nativeCrypto().sm4Final(pointer, null, null); + if (result == null) { throw new IllegalStateException( new AEADBadTagException("Tag is incorrect")); } + return result; + } + + void setIV(byte[] iv) { + Objects.requireNonNull(iv); + + if (pointer == 0 + || nativeCrypto().sm4GCMSetIV(pointer, iv) != OPENSSL_SUCCESS) { + throw new IllegalStateException("SM4 re-init context operation failed"); + } + + this.iv = iv; } byte[] getTag() { diff --git a/kona-crypto/src/main/java/com/tencent/kona/crypto/provider/nativeImpl/SM4Crypt.java b/kona-crypto/src/main/java/com/tencent/kona/crypto/provider/nativeImpl/SM4Crypt.java index 13a12cd1..b6ebc142 100644 --- a/kona-crypto/src/main/java/com/tencent/kona/crypto/provider/nativeImpl/SM4Crypt.java +++ b/kona-crypto/src/main/java/com/tencent/kona/crypto/provider/nativeImpl/SM4Crypt.java @@ -77,22 +77,28 @@ private void init() { switch (mode) { case ECB: sm4 = new NativeSM4.SM4ECB(!decrypting, padding, key); + SWEEPER.register(this, new SweepNativeRef(sm4)); break; case CBC: sm4 = new NativeSM4.SM4CBC(!decrypting, padding, key, iv); + SWEEPER.register(this, new SweepNativeRef(sm4)); break; case GCM: gcmLastCipherBlock = new DataWindow(SM4_GCM_TAG_LEN); - sm4 = new NativeSM4.SM4GCM(!decrypting, key, iv); + if (sm4 == null) { + sm4 = new NativeSM4.SM4GCM(!decrypting, key, iv); + SWEEPER.register(this, new SweepNativeRef(sm4)); + } else { + ((NativeSM4.SM4GCM) sm4).setIV (iv); + } break; case CTR: sm4 = new NativeSM4.SM4CTR(!decrypting, key, iv); + SWEEPER.register(this, new SweepNativeRef(sm4)); break; default: throw new IllegalStateException("Unexpected mode: " + mode); } - - SWEEPER.register(this, new SweepNativeRef(sm4)); } @Override @@ -207,9 +213,6 @@ private byte[] doFinal(byte[] input, int offset, int length) { "Unexpected SM4: " + sm4.getClass()); } - // re-init - init(); - return CryptoUtils.concat(updateOut, finalOut); } diff --git a/kona-crypto/src/main/jni/include/kona/kona_jni.h b/kona-crypto/src/main/jni/include/kona/kona_jni.h index 52ddc2ac..c7a4b924 100644 --- a/kona-crypto/src/main/jni/include/kona/kona_jni.h +++ b/kona-crypto/src/main/jni/include/kona/kona_jni.h @@ -134,10 +134,18 @@ JNIEXPORT jbyteArray JNICALL Java_com_tencent_kona_crypto_provider_nativeImpl_Na /* * Class: com_tencent_kona_crypto_provider_nativeImpl_NativeCrypto * Method: sm4Final - * Signature: (J)[B + * Signature: (J[B[B)[B */ JNIEXPORT jbyteArray JNICALL Java_com_tencent_kona_crypto_provider_nativeImpl_NativeCrypto_sm4Final - (JNIEnv *, jobject, jlong); + (JNIEnv *, jobject, jlong, jbyteArray, jbyteArray); + +/* + * Class: com_tencent_kona_crypto_provider_nativeImpl_NativeCrypto + * Method: sm4GCMSetIV + * Signature: (J[B)I + */ +JNIEXPORT jint JNICALL Java_com_tencent_kona_crypto_provider_nativeImpl_NativeCrypto_sm4GCMSetIV + (JNIEnv *, jobject, jlong, jbyteArray); /* * Class: com_tencent_kona_crypto_provider_nativeImpl_NativeCrypto diff --git a/kona-crypto/src/main/jni/kona_sm4.c b/kona-crypto/src/main/jni/kona_sm4.c index 2495680c..7b3af664 100644 --- a/kona-crypto/src/main/jni/kona_sm4.c +++ b/kona-crypto/src/main/jni/kona_sm4.c @@ -139,7 +139,7 @@ JNIEXPORT jbyteArray JNICALL Java_com_tencent_kona_crypto_provider_nativeImpl_Na } JNIEXPORT jbyteArray JNICALL Java_com_tencent_kona_crypto_provider_nativeImpl_NativeCrypto_sm4Final - (JNIEnv* env, jobject thisObj, jlong pointer) { + (JNIEnv* env, jobject thisObj, jlong pointer, jbyteArray key, jbyteArray iv) { EVP_CIPHER_CTX* ctx = (EVP_CIPHER_CTX*)pointer; if (ctx == NULL) { return NULL; @@ -164,9 +164,46 @@ JNIEXPORT jbyteArray JNICALL Java_com_tencent_kona_crypto_provider_nativeImpl_Na OPENSSL_free(out_buf); + // Re-init with the original parameters for the next operations. + jbyte* key_bytes = key ? (*env)->GetByteArrayElements(env, key, NULL) : NULL; + jbyte* iv_bytes = iv ? (*env)->GetByteArrayElements(env, iv, NULL) : NULL; + if (!EVP_CipherInit_ex(ctx, NULL, NULL, (uint8_t*)key_bytes, (uint8_t*)iv_bytes, EVP_CIPHER_CTX_encrypting(ctx))) { + OPENSSL_print_err(); + } + if (key != NULL) { + (*env)->ReleaseByteArrayElements(env, key, key_bytes, JNI_ABORT); + } + if (iv_bytes != NULL) { + (*env)->ReleaseByteArrayElements(env, iv, iv_bytes, JNI_ABORT); + } + return out_bytes; } +JNIEXPORT jint JNICALL Java_com_tencent_kona_crypto_provider_nativeImpl_NativeCrypto_sm4GCMSetIV + (JNIEnv* env, jobject thisObj, jlong pointer, jbyteArray iv) { + EVP_CIPHER_CTX* ctx = (EVP_CIPHER_CTX*)pointer; + if (ctx == NULL) { + return OPENSSL_FAILURE; + } + + if (iv == NULL) { + return OPENSSL_FAILURE; + } + + jbyte* iv_bytes = (*env)->GetByteArrayElements(env, iv, NULL); + + jlong result = OPENSSL_SUCCESS; + if (!EVP_CipherInit_ex(ctx, NULL, NULL, NULL, (uint8_t*)iv_bytes, EVP_CIPHER_CTX_encrypting(ctx))) { + OPENSSL_print_err(); + result = OPENSSL_FAILURE; + } + + (*env)->ReleaseByteArrayElements(env, iv, iv_bytes, JNI_ABORT); + + return (jint)result; +} + JNIEXPORT jint JNICALL Java_com_tencent_kona_crypto_provider_nativeImpl_NativeCrypto_sm4GCMUpdateAAD (JNIEnv* env, jobject thisObj, jlong pointer, jbyteArray aad) { EVP_CIPHER_CTX* ctx = (EVP_CIPHER_CTX*)pointer; diff --git a/kona-crypto/src/main/resources/libKonaCrypto-linux-aarch64.so b/kona-crypto/src/main/resources/libKonaCrypto-linux-aarch64.so index 8238ca842159e846ad529c0fe786c9edf62b08ac..3d558237adfdb51bf357e742f12ed6cbab408b98 100755 GIT binary patch delta 8798 zcmc&(dw3K@w(sgm!sJ0RGfCzFVkYP!32YvSkVP&e0SOU>2&j?8Bs}B}$hQWU59bPd zXLuTUdT5>gzg4Jn5V~jzKG6t*Xyp`IqUZcWszO3=* z(?U|2wDi-0<0I1s->3=xUb*p2ZNVRQJ^m=YLh=lwz2j(>?Di}bJuC;lg8HhUR|;GO zTqEu)fz_xKbpxsowR_nph)vy?TX4S(wHCDwbqA^+HGsNTlKM(~Q2S6rs0UFGp*Es6 zp&mg!Mhguu7~`&m5*D6+vnh1cU?Qw2fylsKZ{VY9|B=Ho&+Aow2K^Y&SzRkl>Dfix>YR70 zf7BR{3I6v$v(!_n;u(PARIifc5xzMeR~hM&OLQ;*&U3d~3bdBGyKd1z2hB6t@`A#g zNtokkk>aF9HG(1FI*@l?6xRJ^nrF7rpvfp_QF_GG?+?4gc(G%`{fvQdmxAJiq0D}GvS zMka~KA_>%z7A*orkDG0U?PD~qPe_ld{>4f;%QS{aC8-(4d3eu?Y;a>9c*zpE)k0G( zwnA@M@b`$mj4rLU?)hOcixm?zzCKy0qW5OH*kUtFf~|Z0K25dSXtTvw=n|rP*68BD5(+<2Um~hcaISsWDFD`=~k5=BS;jvF8h|aUy;}nwMxZ+l3d)M4~m( z*@-Ehrax&qn}tqW56z;hRO8PT{DmR{t+O=#{etfhtKG$)hA8^n*+mAllxzGV4Wt_3 zagjEXbVX(>_jXt}oNWAl1eFh{j(h zti2~D#!IV{@JJAY5pk2KaQZYoo|H+N=+z|KGcNI9&=>SVVWDWLX0lya9;gRSq-l=u zus{shEvEWojE9#?bXsysc6r#kd`NiEf1cK=Rh{9?g(Ykc~~z|`ax@hEgFnhgRQ$3m9}rVz)Qnicih z+D&|b_Q|l3L-e7HV`L5e8P_IyFte02(&VgC2Y==2Pysnew+yn8we;YiO7c2=N4#^}zx@O2OQcWKkT0mBW{xWnZAsgwzoJ_JSbU9~l)U+z|_`ELD z^q6X=oN}QKLxt38$AW|iEeZW=r6m`(?QFzx9o+kja*_NF`<`6JwQkd z-8Q-uS7kKAl|9l(66l06r6eKr#+YwqVxp|DAlX!X<)*^EG}r=d25Z16VW;9Xg?=hb zh(QCxBOoR`ML~S^REQ7@WyKHT`hIaKv4jRZ)5uw0P5Cp3r~mjG ziLq46cJIXaPKD8;XOpPu*|m^wd-i$AV@v8uEateQ6&DEPvA1k}QL z7b5_Z7EAy|x4$$XI;pz&s=^j8NeW$jslWhP%EC{1%YQ7g$t0O3dY04Rk_ftbO zBlR~8QuTG4)YZ4AbRaZ|)L%2mfyNnz`kxF^pwkc$_{Crdw1RgqQR+H;pVXyXQJ4d< zud{e3rf#=ZON(;pH$N!sXSDamNC)bclIk|xw;GZHrDsx_{v9$rJO)pfbGup%iGkNk za}Vb?=Xd2wBQIRXJ|$2_qyyW*#3OrNPa;iz4h^}1uMNooS@KTgN;`8$b=5+lE=lXO z6|$dU_~~frzznoUyARtiKfLXX*8HwAwC#coyRp06eutbp?BQO1ixKh8E*qruuM7^} z>4yZB%No#$(;yAD!O5BEXcQd!5^eO(mPwNyu zzH!E=`os6}NLT~cZMmMVn+xCeHycVX@F~QutV@z|yLNMjFs&(0!+Bka8{mpo)iG81 zmM(9{^|?&9u?aQ~!bUQ9?*JXZH-UHB^W=7YAv(Ib@Mt~W%2#LFb8qN50fQ5BBc#bZ zFWQg?KcO1nAkPIgPkKvg=y@oIpsgPIUqJKdRjZM;sgX6nf$oug3XyHaOJwj4gjHMA ziBL)o{L8TQRzsGKkYUs(Z$*qdsE@b=o&89+ta(NL=zH34?Q=0_bx8_czjhT?S8C-@ zdFu~!O644~l%A@bU_AyOKF0VFyjzWr{18g7T50g`&o;h$?rcz$)wu7!M^S2lF5m%R z5cnCe3D^P5-K!}54fqBF4hOaai-1y4QCc}4Xvg!s6F3%FwNFvpz;<8*Fn2%N0h@sL zL`oj1DWoXNuy>UXpaHNyrc=WEE2~jaDuBMj=m6V-4xk(8I|>Kz_N~P3LDauKp z9oPcw54-{lHe*28Z%HR$58EQ=DYOHY1FrzxKq(fhG59tdz}vn5X+<$&pW%KNioo{w z6s42XXB4Fjo4|^*a0L67cAy*B0bC8Ve+Wa^z%_jY8aNiA{tVcD9(s6ZyDuopX5eYy zNscXw5`mq8>yn~)J-BJd%{pMtr;2hE*wTj3S)ll(qLc%@z-7P+pbuE~oucI6eSa2M z4jlVE_&`7KG%yJK4A>0p0G|FqQ6^(A&~!ynnt*44XMkltDvBpA83z8YC@x?XunOq@ zUxWx)0hFwuI}~Lqu>7i`Gy^Mu9|K!~oxtLs5qcX&1iS)t{-P*z?TBcXqFe)Z0CVv$ zmHvU;;)sGk@IoKhkeog1|npTS_b2~2(>vt z>oyEYH|=+>0*Cx+RjX}zk%Lh z8M0{)E%8}tuJ0asFuxrn7w@4pzG3pZJ@mhQv*dw$>5z^6wk~Q!pfKmEh(Rl*l4BBI-}JEmhN0R zBzENg)Dv_>-HWp6Z*+g%O8Neibj0@Y^30QT?e-7S$Q> zxK&=tP#1xB`U0)nH9d0fMWih?2W-^oA8YLdg`8E(a9oSA;{JJ&{-=M0{8$Tp%RfbK zX`#L9`^lXxG{1g|b=fDk4fE7njTPtpgzm4OA}3v<@qy`9Ki0Qy(TNsiSbGhZ=!!sJ zx%Cna1irAkKfi5*hs=$|H~(|Gb@zgq%RqL5Y`_al{VvOkFWVBgH8!tjpS%q{^4CSv zn0#L(i+W_eF>hmpJpO#%#~dWKiuY+4wJwrIjb0y-&*WmY zw~M?h`afHf@sO0JqMm`Szm>k&FeP#z9tXvta}6In?$JLx!ag%3?ZX0J00`*BFQ-QG}dj`=a2j-k*5DN+VPS{HA7Y5X*~d*o`QXL3XI5d0AL*t5|gu zNx_)r^?@+mBuDUlLcwb^k2ynB;%$#`7g40vBb&DF~pYEf8Cuj z%_hRa&yc#66D_GP@V z39=|6$TmSPcdTdc#gPRh$ntt3m;LOSo|sfuDXZ&=r17$IoLkGj1D7jw&`R0S*Kyn*&5PZv@++?*nwN zpTNss{m;wV5|GW#$Jq_E?iGGwcS$sJEob>AH5*?wky3{%?9cRZ@yFWFh#BK*Vh%IL zRl%l#>J@(WR)W1X@7gt;)tKQaChCNltR*e%2@5F&?6W}G$GR*Sj(r?UPb3+G!q2b{ zVY9-Gg#X<>CHOhZ*vdq5fwZz|Nf=)dWiKbee>XdxL^89(kB3UIed5-_kLY#^el1H) z=F{h9bCR({TiCnFq*S&~X6aTkMt03*FIq`Pc8*tzZkY)3MQqx*)$rra6l~r&zk{8# z!i;ML!w=mO(#)!DYEsnO$T3I7M9qqR0%^8rN^Z8;4p*`$d(V#P?O$!-hy7O zneOZNNm{R`S#>YWVHIU3(Ap7xgja+eJ$J5^Mfc_-7Ed+4dFG`C+f*)YVr{+2O9;<1 z_mIq9;m0=rfxR_9MlexUcMmB^3qN(t!AA$T5`NzH3N!aXw0CK6QU%A?Xl%mAzEMB? z(L9lUP{q@33R~d^Fk`X1=6!^pK^Fooi@bE7IIhqP8-sIBnU5_<*Vf%LU1PL1uY83{i}ohtY(jcxamZ-_kf z!Nzx;i-*<7lNbvhnvr$+QSo^)M+TC)w49Nv1{L2k0nS*r4Gg!>oUJ z=s26r8%{FK`o2I%FWU!pw11%Hte<^1oD7X_7i2q2`!|sK=ZTNaR!K2FAFJo2zB383 z??77gce#!Y6WE{;BqK(DD&l26X9O7%qwg82YFGfYS>G$@IGlzq(a-2tD8YP4!pz zch6F%PF0;+x~_LwaOcwC+C*zvj-n^00Hwe)bac3Lk7Vxg%sDj3O9d5(b5+5gOY_N^ zxc&=PlSAI7+V2*OyF96P*5IO7%Utvd$u>FN6R1OVRaMIxmI9X}*GPJW#FfBR@_jY1 z7P$`jRb+f=HQIr@Z zLTPvfMvx+jz=Kx7@8&H-YLWaZymS4I2|8OT7NE?E7JTzE!MGy%NfyEH;k|~GC_qu8 zbbgZJa0?Ff^u&9CS5QGO^|R$CP88h71t@uNL$5wpFkF&<$SnB&a>0lU5?BD_`iV3< z+GekuBDhU*@Sl{Z>ew9h+d!=H9^zB~R(hAX1I@)5L=6*~R8h|o9eTvL&R!W;j zA99RQB9*bVT~0HqlhXx$Z8wv zm*ad*N-eTGx}Oz{#ge~C~?K7oi+~NoeQEQXMePL!j&rg5i>#=a3;&L9=6Q`4$;aMY7Z$ zSy%m2f?;@mP!3n33?)Nt*m2$nbhzh?Ukz(V8JNGuCEz$a(R+EcKtV|D3cu)@I!yy;v$k>KVEsHn}SA z8DVOpEORMTSoD_&{#?mlBzvH8mf#PTe7l_K{-uI%j9sFPfC?Ef1wyRUNsqgh=!`T) z%9UlZi4{)^&01ODZaIS-bZVR}Kg$?LS^Z~d3?I%NlZ1MZY#d(%Ip6(|;IEa|PRfC? z(EV{XyID5ISWl>Qx|m*y%OH8w8gHBCm;M+tcagNvRV_?*OUuKIj+0@UB|XfQ4K~Zg z=``BIQ!RZlJ~`77F!%109<<4BX^`6IV2!sYi=K+N*|X#XGWv+`EnJ#NNrG+YjwkdA zlmh8Nue7O14~#JUFN9$-$)e>6w&9)9REj97R9c0_b1MbIBKZnz@-@R->uXM^kD;c) zPWsi**^#rKD}C~r-_8Gh<@2+j@nxr#st8nq-^^G=;bl{hnP(kZV^WTQ#}k)7D&?F` zxwjH>Rr#}&SKJT{Fv;2Bn839Zr80ouog?_JzI=MmFZ;*W%T~EGVTr)fA>X6FOeXer zQAU4u^%48%E9o}!7TubDn5?2tW*jE1^d3hkIY5^=O6}f0rH;c@o>Um!L~l59NgaJC zGnZ_kuVk(vjdbAfT+&3J99~Mc(|7USLZe35$Sd@o5o<^TeQQK6X{I;uzJ|UsvXpG3 z-;B&4dwm1%+eb(n{qv{{I^e!YY976j)Y7e^bICH_H={=rQcv&sRR-DSd-PX(L(09@ zhqHSvGr~P7YVw&L90{z2psV}PzX9FYhn^1lNFTZc^xyl?GeD~m|Fq|u>8v&p;`?&K zF9;zt`k_)hpM8ko89K3*gwVqiOG$_?IrmGIgwoJSx$&W%D>pRucayF8k}07%g&$Mg zp}yZuiVlaub463|e5dGs66({64igZEe?vh$@|cg1Fd8~-1fKU#Dyh6+ z2jbXoH<0i!kDBN%?B~}Q?RX-Nx}R7Ld34FskS{9PNg@VeQgxx?K}s0SD0>6Kzm{z$ z;l3Bj*Qg|%hR*y6gf{aS0dZ{Bvmi!4g*w9NcNJSe(Am$aB!Y&{-9jRKyXHP`B3@rg zv?B`0PifA0*c1E?hT9Z6o0R=7po(DxvpFjWNQ{(;F?eWw@oFH^rfn013KVN ztm6JqIhWh3D9+x8do=c=rr9{(H`u+<6dZ}kALZNfk`_b&H5lC}dSS)Ocs{lAeLP3J z{05#My-Yc0)vl`coi|L1=W2w~i$$@eo-1anN?jU7kwd(BcGQ~A-9`8Ju(~;Bb zRK}mV3cWI-v}^$nvw2=r2~mocL6IBy+!WueD(*sFXsdHVZvzVO3cJ8>jB^+E!f=-< z7S1_)Th3!*&~ndcHRcLk@0mk>qQP}j5=KD#G`h4wQ96xoPQT)tQ@7Go#gFuS%|52i60#_G#K~pc{A^SOe?^TD+Q;g6+HlI1< zPtz)aZNMg=r3HGx8em+oQl-?qrD=mwtb*!J)HiFrWNCeQ2Zer!LHT@tORxdmjb&#f+1kd$DpyzC!Rr% z0o%@^92WJwbDFjmSPyLHcwW?KGdbxg7S~o<+LZVwbj`v}EG_64LRsk;}SL~saUR$m9?4jph8x>rD=zg4@ zXzouP>n*B#FU?t>9^4IP5%p}3r8VmZ1VyO7-V=>GG`)t7G4zXSPnQ8s*~TR2ez+N%TCdp9jR&OPTd+! z-f{~bAAo1{4DW@(;B}m$bvrf%`_E#Y>BEw@GevcrqjPqqs_t{NZfAO$7jwx73~s6d z)20bL{?1bw@?!8B&e6*|XQ&T;LLY9Pk5k z=jn`HscPqWx^ma_gvT%3vdCj?6(&>h1$uqg^x!KHU87T*ZM1TCUVW(6O3J#{=3o*+ zNEzE70(Xu2u%qZ{oc`q3)R!Pu$JVmzAtarQ)Jf}u0kyr%JRu|*jhYuqY)P&hX+%Oj zQ02EmIjk|1q_dh(VqsmOq<}bBrkUibBiFHoW-^gvvA4}6BPp;gyL3CzO8q((9!AoW zjC*IJ79r=iAgnNqEEwwc7!rX-`3`nFe?Hr6hS!zM8cu9OyZ=q8lnu9+S|&=l**ugY zPWHW-;5P5|+m)D5s$i#}#Cpsm(b~{(yUK1uB{Kqcx`Z8b)9p$}+4o^2g)Cup5oF>} z2fbZtG^}ge?fmn?bQv2IiQ&lmH>DbySz#o)bL^hmOaBkHXMzwJyN9iZT=i0RGLkGn zQ?sMsX%?Fng)#G&u*N7vgoT~rTnGCKT$0B!`;lC`SH?$*v|Nl$m*0rFn5Q2+3cP+_ zAjLh)*^z#T1BHb}lML0nnvIEu1C<^&2Z&I84Q#uy%Nt%##n!H0x3Npn2vzT7b{*PD zfgerIOEv#emSfR_ZH0xD+Wpgo9pi%VZ5#pgt35`nXjdMyThXpWRt_quBUdQ9WZfk= zQ*vd0Ijgh6)2=1#h?T4+6>Mq@DFy70LE#~+HwMkwF^Q$clJw#7qk&Q+jU2#Hgc}LG zWPDfhkH5rL#*#CL)ABg9&*EVV>i)&f6?Y?XWm8x+rn?*%p| zo|M4F6Y-=}-SG%ZOCS?f|I=)K0!hyd{BUv>M>1|T@QYJ2j%J+iW~UNh#=ndWx4~)w z^VsyD*l8n&?TLk=rDl2Vv*J9=3z^xAiEyQ-mYqz*@VZ$qCwDx-a_l6%Jn%;MF&zH% zs`7<3<4X|#Ys&e7*ZO~w{HzH=zeaZVQOQqXr|fXKV*(qVq{nf264pVdTc{bnUdDpR ztrs&-62`E=!;V1P9{44t00(QXR>{Kp^A=AOR`~gtr#c)$xj2tq>Q7!k_e>jrbuRGs z{P*}z%Wrc#Ygyv}QeqAKyzv0b9*ACjLcl@+>)AZc+^kdOKKwo46$M^z-<14{2Zcj% zawtM@RMz#E3H}uUN}=QjUN~=Hw3H-aJn&P|6y|{uGFJ!t zT3rh}jojd+2g-U~Jm_s{B=9R$On+g#qP6!f@&!>xjcUD=LLNMLG0W6$qdrL zrj8{UF~&}9V7HakjV0+; zjXw}W*a@AKjTyqi#zAVF9h@v5WQ?)d8hG*7tZp1h4>wje?6xPzkx}8sMp#hG!pDgZU&&ATl#;P$30wR$jBm`LDJ2p5k)<$Ir|<-``&Qz4qP*=QMrk z_0Csb_J|J7G=*O#VH8(Y&lLajn+2WUTvc!|`tHku+S@5i=u;qDeL3XH%5Pe`Z~x9Q z;nC)2Ms|(xytkpPz)vN9?D(m| zPur_n0<;ld!TTEgtjEu*_}Pe`I{dtWpSKm|K4mN3Y=cCvj(+uc*MOf7AlqxUZ@^EE zpcgJ2*bBS7euF~Q`;B_<`_yvBPX8UMPg$^{1Vg^s(XlX~RPFyAq4I#@qz2-3Rv5+6 zLFl@dgfL7M_IWhq-vWt&;gOc5LZw#G6{3@+K|ZDyE)i;kFuX66w-l-Z!?T++glv|n z=~x4$=4J}PBK5t#LT{cTgrDUk<#>DQx`lPM3>T@FWILzHmb5^0P`I@vOQhbCW$y78 zd37^|&{LKfFGs^7r)`TY?Kh9V?2)WYIeMQc$39M!lP1f*infFDpi)ZHtteJS&#j_7 z?g2T7aX&>_D+kpMMY`}v9Yr->?+c^&V*{y`g;1vp&sLrga$nhp{yrjA zmn(G7w4Z-a=&djQxBi*zTMMWi!mUP&NX6Oa*G2rMy7WT@W5DxkPoU5(rGf_vqcqA1 zH_BDG$1|leeDsrr<969vMUHs0C?D2!=n!ej7e0ffk3-Iu9S&m)b#lEI%NnoBu~KAz zu>t&g!!t_H2)VHp?>*4X`!1tJO4HbA>)a`mdIqFp18^E2CwCRrcC6LkJ6{-bqG9D-?AMkF1yL;i^pi9GgvD zZ-F{Y&CL+99605ejE!12i>b}iL~5SQTPd691U1BvXp+(BiS0LJdz`X8X)@QdvP?VV zhlEGA%7yMNhbc{V&kj`~;n|i-kx4J}8f1;80wI*h;68`BsTZ|bLifb*9XaTwa4RG{ z%``-$4wj|8Bd1C?Q3#i%{-dm=RK}ZU1?_|E(5^Y9>B3FUuR;?^JBQM)tp#$!Z!H)8 zo{7CD{aaQ$8bYgs;j6gLP#u@yGkRu8_Bg1D8wxAqW;*%q^ zl@K~{HCGk;4n4oYoOu5E^!`EJ4L|obsP92+9|LqU1c0T_E_DTjCcLfI!-0fpusd7dSeaD4vA7FFE|OZpkq zt?+)ox77+5o1CRCb!<#dQPpa=kYZ449X_eas`b{hdc|DsEMZ!+dHFHlqr4W+m)0+R zfnL#KGw?g8s|oLj=TNe{MZ+t005L_YyP0zmF)e<#lXE;V?sJN}o^v;1Z{k|c)+iEi zYggQME(8_rkVU=_EHJDelNRjIfY&ZmiSTTb zJO+qO#4Vf$5T_A0b50_r4c6`C98XLqj=P?7H)1?rtr!Gch$4X=mfUvE!Ni%wrJVhV zvxo~hGh#Ebh4Z~)i z&N-NP7I7(Of8yE1g`62Nokng8=X=G-bBS{~-zF{~HgUdA{3NlF^Oa(~Rhcu71U(ln zlEYKPI?m^apC(o~pC+D9+NUP7$nJc{^5Vg=b;IVcYWbEQuXnf`Z6Ld_LEpFAZVA^fzKpsuCps~nXU{iC^m zzbL3k>%`VR1zXcP$A4L*SCnUajWsVHRE&8Qv+Y_*0QzP=saIU5FxFf%aCA@j>@I@V zv0~*i!!L7XzZWoz>z{Y9YZalJ3efYU$(JYDbY`1R zXUa=YML}K5&>wSD_^AI=9xahW7TU|Oz+P0~OQOIPvOqoM!~!cqD}@pvlw6W>gcK(w zJxWkL?& zHK=nzomoT)*q$iPnlx z>`0!0-Fh6#^G33|$KgU=pKj@RZc+w@87eYj0{DYwn+}EMLCh!{TQ>l9j9S402SDm* zJ-g8#CXGJGR`-XfF#}j`e;7ArDr-%JJ!5j%mQ-M4d$H$I!7z4KSP&lLX4`Ss{C{g& z;}~oY4*stx@b1_?>`V$=9NUkrO@R*M2D7m#kT-52yOazcjWelpAz*w;Vj|8yja8M4 z2J(l*?;F>N63qDU;ClBePSwk8n(CuM$@tT3RzEOJc#|FK3*Sx{n3p$BuZZc|flZif zwz>EkN}I|TOodM(rt>;5Rn&1s)`3qju6M6s9dEa*W8y#9op&}!!eZ2gk>-bP+wq?ZNV*S*0jht#l`dI_?o7$bdXMjmlhp^cO*fg~&?0f=w zf9g8_FLVUq=uCjjY2(@K1lTmKlwIos(Uv5NXNw`})=1IHysu^KH(nBX=uy%2Z(x;rL4x!$XDQCH6}O*^A$e83tX!^p;A8rKzc^Ov%JbOD%Os1|{D;qjiYcE;8Z z{s{Y2u{g%qm@hobNsU9bak>ynI>YV4o}m*5i$U1;39iC#@$Ug#p+mt~l*#@W1PhA{ z?BhYOwJ3?L9|T_(J*G~8&c%z^#}C2!;=W<)9>OvQoZ_R`SS*TN{*dFF;s;c=APQQa z31OBf$9*OBUTk|9?0wG27Kb^mKj-%9e=7xR#lK2Dn|4IvIqXfxj*60~xjG%j5-~9d zcjzW^Tz)J<#A+z6ipAr*b$A3L`Vz(L{G(L)=aY}N4KJTtNl?BR*LMJe>UJA{%zxq6}z*@i*aB64m0|}ALUEfFLAKsrCzMe7q-2W zWgVY3E^Tbun6abr2#qtBp9?C>qY1VBYPNkg!gf5{cE)VG;M%l9L%RozPivjcCv`O824k3a^S1^7vY_m*W2nWZO=f z%dO6mP8GvrI+dS#F$5h(*jf|M4Y&OvobFSU#y3T!YwxFl`j6`=tkjIfV;dA@METW{ zFw8|+{>`&Ev0U0We1|698BzXy36)8yH~&nf7UQNr7CU6dimkqh=MwLv*$!jPq>pq^ zgG&}s(UF*WAEWv!#>Dt~s=yymu;M!<;hxmtw%eWxC=H`FZn*94WVzX0T z-8b~8f>Zf0oupWQs>}NH2RK;~VzSDpQ{-@~haOF;D~}S3DealAU&W!DNd7!hzbO0v@ ztMeLeyAF9PLy~-LF41~ie5Jfa_^6cl{bYH79HqlNO}4OZ53ZP9uympxF0Yu(3hQC; z%CY|Wv7-Hlcf-b&)0lHN{ISx=ZaTnd8_8aGK&kD~g#Iyl1!pS2Trt447H5?o!6DdJ z@i-6~*(UwjUEsDo?9i|J&C5!^w&h@}nzm}%LcCvz9jQg@LQDV8YsMM8K{{IeKSN~# zmTf`%IocYual19Go)~QtT3_rz3)%^2L%bDbFIo%QcW}_0XkBPq$YR8F^1+9}rbbPp z_^sKmX=l*7(7Mnz;pUNw0Z?;D)5_5L;yVh?aPx8s8U98ZPc$bO0~#{D9-S<@Dy zHKVnYJ&PlPcI7!uGvY?%`wvYkL2EvbJww}s_9wIv7c@;rJK1NNHU;g%FEs5K+Pi2! zC;g(P1w4rU_((9tiZ=`KcwdNiCEC?!YtYuBHQ&&*Ri#7na=7=9OO^>z)?HIIkS~YD8+IP?%LuW?^NXz${qW?%e2yofuv0MO3)kEX35#=rVn&^Dnp24e;Ix5-MF zYk!!T--c>?57x2+8tut_eCsuh{t~APi{n4RjzMiOR}^Im+Aa7gMeQi0y&eJms)n%E zdRSDIoRhi}D<#JFLR-!h1AN;YVfYp8o1#2_eoc++Sc6z@xxB}A1D>G2HoIQOM%ix9Vm#YJjUl#ms zM(r5-d&B#$bcR{4q_e_9u4N*)v1@Rkl*wxdpV8g7i_i$y=AIo&nG|;Mw_!w?)NV>1@#~5f zI&boaVXyYgoPq17j$Cu7+iW%Uo5rpaj{99q!?n#X(r6w2gqo+pG%p#bwO)Y6S4Xnk zufYGcD7NM+=%&UEhQGfa zRlPAL>}nfd>JhE))~{i}MhvVLczWYVw!Z}qZtTMT)dF8_%n37I{_nDza9Iz$41-@E z$zHpRg$^DNfV+XGb~^0m;X;l;Z5ZBT$m{bk@`hp0=rZGHH7$5d-^1YGtI_cArr5~+ z_;-w_2y(fBE={NngR1qhuxeA(gQTY7%0F`rcLG#n;w)a7s()Z=MxZe*FfKh%pB@;I z9;i#FD5o(fLucc+I3G~7F)GQ(X88xk4GGkzdA!UIWC&%5M@gqP(%)z2F{>SJZ5r*< z8)quQkzK3#TRlG}8Pm}NubTJu+~T_A*Lr+(rOU(gGZtOg6Mh|+jAiqSuXen{;pbOP ze_?TW`E|8I*hpdE{_T0uEujMN?BG`|u0OgkDEVc9=ePeYxW11dPqZn$;o|lL{OQVX zM^|Qwhxi>g9l7;RuL0xu5>=F0(k_tpC23!g_AP1mNIP*g1nm?H&%@bW5BYl%ukyt9xLpo~LzHwwj>N4BeC?zglt>FK!aH#c62 zH~y@9c6WHBDZZ^P?!EAdtRB=o;gL%3|1Z@SQxo@ut2L0nC)CSdaiR^M?rC+~99}qO zp7#H@j#Ia~ts?HdFa$g=3bjr3Qi7BT)sBmMx~LGhSLa88!juP;R_L%doZ)Yj@q07X zLPycw*(z(^3>Wt$M71yGd6lwIbD&$}f=JH{cxs`?IsP*->}qC4(BBw$~`!I`{UW8R2W+t}Ce(0ssXLw+cQ~Q@GE=%1G>i%%m36cA=)KbXbZ(y~n zpn87-tF441XpGC@_Wp#(_P8F}T>MLQ5$$IRDN}7Dzvwz)Y1;d^l5WhJA+( zN$p=?c?&ldo@Iq-$rhX!y1tjXG6ABF;9Nugk!egn8IBy8%8a?t?Pz9B`?m=~FiNN> zojjC=i;|Qs9{nXDcwV=fCH344XgE5R>6St8v8j>m-$eNYHzhHMwqu7Pog+mVCuG?Z z@cD>RTOj{<7SmV4w&Mv*83Py5=q7^yiG)ZyK8(_JSQzDXe3TMd@=oB2%M~&mdvtl@ zR!FI(u=GSYPS*Mp({RjxIbn#DFViRn;i$N!rybHxQhZH3X<((5uFZwlytKYa#lS0r$VWQ{hahgo0BGdbWRW3BpD0_HXc9fy1Z5 zRR)(&hpS!b+xi%uQ#vI~iP)u=jT9ymb*kU~jNl#eV6T#T=@6kGmATeS-Lg~&byB}3 z_4e;kB;Y}S?_C5d?Ozh<3uzyPt6BWJh`u`my7HkIC(4v9QLa!C^y;2^hx~jx;%~_O zRX(3bJ$K!v(;arB{mWSnsT(bhZ68fk)l`S~$AiNB`eqFoA>QOj?34}$y`N*)H!pZY z)3+9UeWIt!(804)d#nlOqUt%wJk|nRQT6QG9$N@*m%*>Tm*_=3M7vY`|J=QM!*qAD zpXaQrhdOtPpJxNCfy+ovd5kzA`g%&RXDj#Em>ej$p3wH_*?c|O|IZD4HC(x#+`+Tq vdh8VF`JJJ|glf?uk6rAT``sa?&VimcQ~aAh5{W(!LBY*r^#au0eE9zWTHhw4 delta 10283 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 tso7$%e`^T0IMf